]> Dogcows Code - chaz/yoink/blob - src/stlplus/portability/inf.cpp
cleanup stlplus files
[chaz/yoink] / src / stlplus / portability / inf.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
7
8 // The integer is represented as a sequence of bytes. They are stored such that
9 // element 0 is the lsB, which makes sense when seen as an integer offset but
10 // is counter-intuitive when you think that a string is usually read from left
11 // to right, 0 to size-1, in which case the lsB is on the *left*.
12
13 // This solution is compatible with 32-bit and 64-bit machines with either
14 // little-endian or big-endian representations of integers.
15
16 // Problem: I'm using std::string, which is an array of char. However, char is
17 // not well-defined - it could be signed or unsigned.
18
19 // In fact, there's no requirement for a char to even be one byte - it can be
20 // any size of one byte or more. However, it's just impossible to make any
21 // progress with that naffness (thanks to the C non-standardisation committee)
22 // and the practice is that char on every platform/compiler I've ever come
23 // across is that char = byte.
24
25 // The algorithms here use unsigned char to represent bit-patterns so I have to
26 // be careful to type-cast from char to unsigned char a lot. I use a typedef to
27 // make life easier.
28
29 ////////////////////////////////////////////////////////////////////////////////
30 #include "inf.hpp"
31 #include <ctype.h>
32 ////////////////////////////////////////////////////////////////////////////////
33
34 namespace stlplus
35 {
36
37 ////////////////////////////////////////////////////////////////////////////////
38 // choose a sensible C type for a byte
39
40 typedef unsigned char byte;
41
42 ////////////////////////////////////////////////////////////////////////////////
43 // local functions
44
45 // removes leading bytes that don't contribute to the value to create the minimum string representation
46 static void reduce_string(std::string& data)
47 {
48 while(data.size() > 1 &&
49 ((byte(data[data.size()-1]) == byte(0) && byte(data[data.size()-2]) < byte(128)) ||
50 (byte(data[data.size()-1]) == byte(255) && byte(data[data.size()-2]) >= byte(128))))
51 {
52 data.erase(data.end()-1);
53 }
54 }
55
56 // generic implementations of type conversions from integer type to internal representation
57 // data: integer value for conversion
58 // result: internal representation
59
60 template <typename T>
61 static void convert_from_signed(const T& data, std::string& result)
62 {
63 result.erase();
64 bool lsb_first = little_endian();
65 byte* address = (byte*)&data;
66 for (size_t i = 0; i < sizeof(T); i++)
67 {
68 size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));
69 result.append(1,address[offset]);
70 }
71 reduce_string(result);
72 }
73
74 template <typename T>
75 static void convert_from_unsigned(const T& data, std::string& result)
76 {
77 result.erase();
78 bool lsb_first = little_endian();
79 byte* address = (byte*)&data;
80 for (size_t i = 0; i < sizeof(T); i++)
81 {
82 size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));
83 result.append(1,address[offset]);
84 }
85 // inf is signed - so there is a possible extra sign bit to add
86 result.append(1,std::string::value_type(0));
87 reduce_string(result);
88 }
89
90 // generic implementations of type conversions from internal representation to an integer type
91 // data : string representation of integer
92 // result: integer result of conversion
93 // return: flag indicating success - false = overflow
94
95 template <class T>
96 bool convert_to_signed(const std::string& data, T& result)
97 {
98 bool lsb_first = little_endian();
99 byte* address = (byte*)&result;
100 for (size_t i = 0; i < sizeof(T); i++)
101 {
102 size_t offset = lsb_first ? i : (sizeof(T) - i - 1);
103 if (i < data.size())
104 address[offset] = byte(data[i]);
105 else if (data.empty() || (byte(data[data.size()-1]) < byte(128)))
106 address[offset] = byte(0);
107 else
108 address[offset] = byte(255);
109 }
110 return data.size() <= sizeof(T);
111 }
112
113 template <class T>
114 bool convert_to_unsigned(const std::string& data, T& result)
115 {
116 bool lsb_first = little_endian();
117 byte* address = (byte*)&result;
118 for (size_t i = 0; i < sizeof(T); i++)
119 {
120 size_t offset = lsb_first ? i : (sizeof(T) - i - 1);
121 if (i < data.size())
122 address[offset] = byte(data[i]);
123 else
124 address[offset] = byte(0);
125 }
126 return data.size() <= sizeof(T);
127 }
128
129 ////////////////////////////////////////////////////////////////////////////////
130 // Conversions to string
131
132 static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";
133 static int from_char [] =
134 {
135 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
136 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
137 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
138 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
139 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
140 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
141 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
142 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
143 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
144 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
145 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
146 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
147 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
148 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
149 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
151 };
152
153 static void convert_to_string(const stlplus::inf& data, std::string& result, unsigned radix = 10)
154 throw(std::invalid_argument)
155 {
156 // only support the C-style radixes plus 0b for binary
157 if (radix != 2 && radix != 8 && radix != 10 && radix != 16)
158 throw std::invalid_argument("invalid radix value");
159 inf local_i = data;
160 // untangle all the options
161 bool binary = radix == 2;
162 bool octal = radix == 8;
163 bool hex = radix == 16;
164 // the C representations for binary, octal and hex use 2's-complement representation
165 // all other represenations use sign-magnitude
166 if (hex || octal || binary)
167 {
168 // bit-pattern representation
169 // this is the binary representation optionally shown in octal or hex
170 // first generate the binary by masking the bits
171 for (unsigned j = local_i.bits(); j--; )
172 result += (local_i.bit(j) ? '1' : '0');
173 // the result is now the full width of the type - e.g. int will give a 32-bit result
174 // now interpret this as either binary, octal or hex and add the prefix
175 if (binary)
176 {
177 // trim down to the smallest string that preserves the value
178 while (true)
179 {
180 // do not trim to less than 1 bit (sign only)
181 if (result.size() <= 1) break;
182 // only trim if it doesn't change the sign and therefore the value
183 if (result[0] != result[1]) break;
184 result.erase(0,1);
185 }
186 // add the prefix
187 result.insert((std::string::size_type)0, "0b");
188 }
189 else if (octal)
190 {
191 // the result is currently binary
192 // trim down to the smallest string that preserves the value
193 while (true)
194 {
195 // do not trim to less than 2 bits (sign plus 1-bit magnitude)
196 if (result.size() <= 2) break;
197 // only trim if it doesn't change the sign and therefore the value
198 if (result[0] != result[1]) break;
199 result.erase(0,1);
200 }
201 // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
202 while (result.size() % 3 != 0)
203 result.insert((std::string::size_type)0, 1, result[0]);
204 // now convert to octal
205 std::string octal_result;
206 for (unsigned i = 0; i < result.size()/3; i++)
207 {
208 // yuck - ugly or what?
209 if (result[i*3] == '0')
210 {
211 if (result[i*3+1] == '0')
212 {
213 if (result[i*3+2] == '0')
214 octal_result += '0';
215 else
216 octal_result += '1';
217 }
218 else
219 {
220 if (result[i*3+2] == '0')
221 octal_result += '2';
222 else
223 octal_result += '3';
224 }
225 }
226 else
227 {
228 if (result[i*3+1] == '0')
229 {
230 if (result[i*3+2] == '0')
231 octal_result += '4';
232 else
233 octal_result += '5';
234 }
235 else
236 {
237 if (result[i*3+2] == '0')
238 octal_result += '6';
239 else
240 octal_result += '7';
241 }
242 }
243 }
244 result = octal_result;
245 // add the prefix
246 result.insert((std::string::size_type)0, "0");
247 }
248 else
249 {
250 // similar to octal
251 while (true)
252 {
253 // do not trim to less than 2 bits (sign plus 1-bit magnitude)
254 if (result.size() <= 2) break;
255 // only trim if it doesn't change the sign and therefore the value
256 if (result[0] != result[1]) break;
257 result.erase(0,1);
258 }
259 // pad to a multiple of 4 characters
260 while (result.size() % 4 != 0)
261 result.insert((std::string::size_type)0, 1, result[0]);
262 // now convert to hex
263 std::string hex_result;
264 for (unsigned i = 0; i < result.size()/4; i++)
265 {
266 // yuck - ugly or what?
267 if (result[i*4] == '0')
268 {
269 if (result[i*4+1] == '0')
270 {
271 if (result[i*4+2] == '0')
272 {
273 if (result[i*4+3] == '0')
274 hex_result += '0';
275 else
276 hex_result += '1';
277 }
278 else
279 {
280 if (result[i*4+3] == '0')
281 hex_result += '2';
282 else
283 hex_result += '3';
284 }
285 }
286 else
287 {
288 if (result[i*4+2] == '0')
289 {
290 if (result[i*4+3] == '0')
291 hex_result += '4';
292 else
293 hex_result += '5';
294 }
295 else
296 {
297 if (result[i*4+3] == '0')
298 hex_result += '6';
299 else
300 hex_result += '7';
301 }
302 }
303 }
304 else
305 {
306 if (result[i*4+1] == '0')
307 {
308 if (result[i*4+2] == '0')
309 {
310 if (result[i*4+3] == '0')
311 hex_result += '8';
312 else
313 hex_result += '9';
314 }
315 else
316 {
317 if (result[i*4+3] == '0')
318 hex_result += 'a';
319 else
320 hex_result += 'b';
321 }
322 }
323 else
324 {
325 if (result[i*4+2] == '0')
326 {
327 if (result[i*4+3] == '0')
328 hex_result += 'c';
329 else
330 hex_result += 'd';
331 }
332 else
333 {
334 if (result[i*4+3] == '0')
335 hex_result += 'e';
336 else
337 hex_result += 'f';
338 }
339 }
340 }
341 }
342 result = hex_result;
343 // add the prefix
344 result.insert((std::string::size_type)0, "0x");
345 }
346 }
347 else
348 {
349 // convert to sign-magnitude
350 // the representation is:
351 // [sign]magnitude
352 bool negative = local_i.negative();
353 local_i.abs();
354 // create a representation of the magnitude by successive division
355 inf inf_radix(radix);
356 do
357 {
358 std::pair<inf,inf> divided = local_i.divide(inf_radix);
359 unsigned remainder = divided.second.to_unsigned();
360 char digit = to_char[remainder];
361 result.insert((std::string::size_type)0, 1, digit);
362 local_i = divided.first;
363 }
364 while(!local_i.zero());
365 // add the prefixes
366 // add a sign only for negative values
367 if (negative)
368 result.insert((std::string::size_type)0, 1, '-');
369 }
370 }
371
372 ////////////////////////////////////////////////////////////////////////////////
373 // Conversions FROM string
374
375 void convert_from_string(const std::string& str, inf& result, unsigned radix = 10) throw(std::invalid_argument)
376 {
377 result = 0;
378 // only support the C-style radixes plus 0b for binary
379 // a radix of 0 means deduce the radix from the input - assume 10
380 if (radix != 0 && radix != 2 && radix != 8 && radix != 10 && radix != 16)
381 throw std::invalid_argument("invalid radix value");
382 unsigned i = 0;
383 // the radix passed as a parameter is just the default - it can be
384 // overridden by the C prefix
385 // Note: a leading zero is the C-style prefix for octal - I only make this
386 // override the default when the default radix is not specified
387 // first check for a C-style prefix
388 bool c_style = false;
389 if (i < str.size() && str[i] == '0')
390 {
391 // binary or hex
392 if (i+1 < str.size() && tolower(str[i+1]) == 'x')
393 {
394 c_style = true;
395 radix = 16;
396 i += 2;
397 }
398 else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
399 {
400 c_style = true;
401 radix = 2;
402 i += 2;
403 }
404 else if (radix == 0)
405 {
406 c_style = true;
407 radix = 8;
408 i += 1;
409 }
410 }
411 if (radix == 0)
412 radix = 10;
413 if (c_style)
414 {
415 // the C style formats are bit patterns not integer values - these need
416 // to be sign-extended to get the right value
417 std::string binary;
418 if (radix == 2)
419 {
420 for (unsigned j = i; j < str.size(); j++)
421 {
422 switch(str[j])
423 {
424 case '0':
425 binary += '0';
426 break;
427 case '1':
428 binary += '1';
429 break;
430 default:
431 throw std::invalid_argument("invalid binary character in string " + str);
432 }
433 }
434 }
435 else if (radix == 8)
436 {
437 for (unsigned j = i; j < str.size(); j++)
438 {
439 switch(str[j])
440 {
441 case '0':
442 binary += "000";
443 break;
444 case '1':
445 binary += "001";
446 break;
447 case '2':
448 binary += "010";
449 break;
450 case '3':
451 binary += "011";
452 break;
453 case '4':
454 binary += "100";
455 break;
456 case '5':
457 binary += "101";
458 break;
459 case '6':
460 binary += "110";
461 break;
462 case '7':
463 binary += "111";
464 break;
465 default:
466 throw std::invalid_argument("invalid octal character in string " + str);
467 }
468 }
469 }
470 else
471 {
472 for (unsigned j = i; j < str.size(); j++)
473 {
474 switch(tolower(str[j]))
475 {
476 case '0':
477 binary += "0000";
478 break;
479 case '1':
480 binary += "0001";
481 break;
482 case '2':
483 binary += "0010";
484 break;
485 case '3':
486 binary += "0011";
487 break;
488 case '4':
489 binary += "0100";
490 break;
491 case '5':
492 binary += "0101";
493 break;
494 case '6':
495 binary += "0110";
496 break;
497 case '7':
498 binary += "0111";
499 break;
500 case '8':
501 binary += "1000";
502 break;
503 case '9':
504 binary += "1001";
505 break;
506 case 'a':
507 binary += "1010";
508 break;
509 case 'b':
510 binary += "1011";
511 break;
512 case 'c':
513 binary += "1100";
514 break;
515 case 'd':
516 binary += "1101";
517 break;
518 case 'e':
519 binary += "1110";
520 break;
521 case 'f':
522 binary += "1111";
523 break;
524 default:
525 throw std::invalid_argument("invalid hex character in string " + str);
526 }
527 }
528 }
529 // now convert the value
530 result.resize(binary.size());
531 for (unsigned j = 0; j < binary.size(); j++)
532 result.preset(binary.size() - j - 1, binary[j] == '1');
533 }
534 else
535 {
536 // sign-magnitude representation
537 // now scan for a sign and find whether this is a negative number
538 bool negative = false;
539 if (i < str.size())
540 {
541 switch (str[i])
542 {
543 case '-':
544 negative = true;
545 i++;
546 break;
547 case '+':
548 i++;
549 break;
550 }
551 }
552 for (; i < str.size(); i++)
553 {
554 result *= inf(radix);
555 unsigned char ascii = (unsigned char)str[i];
556 int ch = from_char[ascii] ;
557 if (ch == -1)
558 throw std::invalid_argument("invalid decimal character in string " + str);
559 result += inf(ch);
560 }
561 if (negative)
562 result.negate();
563 }
564 }
565
566 ////////////////////////////////////////////////////////////////////////////////
567 // constructors - mostly implemented in terms of the assignment operators
568
569 inf::inf(void)
570 {
571 // void constructor initialises to zero - represented as a single-byte value containing zero
572 m_data.append(1,std::string::value_type(0));
573 }
574
575 inf::inf(short r)
576 {
577 operator=(r);
578 }
579
580 inf::inf(unsigned short r)
581 {
582 operator=(r);
583 }
584
585 inf::inf(int r)
586 {
587 operator=(r);
588 }
589
590 inf::inf(unsigned r)
591 {
592 operator=(r);
593 }
594
595 inf::inf(long r)
596 {
597 operator=(r);
598 }
599
600 inf::inf(unsigned long r)
601 {
602 operator=(r);
603 }
604
605 inf::inf (const std::string& r) throw(std::invalid_argument)
606 {
607 operator=(r);
608 }
609
610 inf::inf(const inf& r)
611 {
612 #ifdef __BORLANDC__
613 // work round bug in Borland compiler - copy constructor fails if string
614 // contains null characters, so do my own copy
615 for (unsigned i = 0; i < r.m_data.size(); i++)
616 m_data += r.m_data[i];
617 #else
618 m_data = r.m_data;
619 #endif
620 }
621
622 ////////////////////////////////////////////////////////////////////////////////
623
624 inf::~inf(void)
625 {
626 }
627
628 ////////////////////////////////////////////////////////////////////////////////
629 // assignments convert from iteger types to internal representation
630
631 inf& inf::operator = (short r)
632 {
633 convert_from_signed(r, m_data);
634 return *this;
635 }
636
637 inf& inf::operator = (unsigned short r)
638 {
639 convert_from_unsigned(r, m_data);
640 return *this;
641 }
642
643 inf& inf::operator = (int r)
644 {
645 convert_from_signed(r, m_data);
646 return *this;
647 }
648
649 inf& inf::operator = (unsigned r)
650 {
651 convert_from_unsigned(r, m_data);
652 return *this;
653 }
654
655 inf& inf::operator = (long r)
656 {
657 convert_from_signed(r, m_data);
658 return *this;
659 }
660
661 inf& inf::operator = (unsigned long r)
662 {
663 convert_from_unsigned(r, m_data);
664 return *this;
665 }
666
667 inf& inf::operator = (const std::string& r) throw(std::invalid_argument)
668 {
669 convert_from_string(r, *this);
670 return *this;
671 }
672
673 inf& inf::operator = (const inf& r)
674 {
675 m_data = r.m_data;
676 return *this;
677 }
678
679 ////////////////////////////////////////////////////////////////////////////////
680
681 short inf::to_short(bool truncate) const throw(std::overflow_error)
682 {
683 short result = 0;
684 if (!convert_to_signed(m_data, result))
685 if (!truncate)
686 throw std::overflow_error("stlplus::inf::to_short");
687 return result;
688 }
689
690 unsigned short inf::to_unsigned_short(bool truncate) const throw(std::overflow_error)
691 {
692 unsigned short result = 0;
693 if (!convert_to_unsigned(m_data, result))
694 if (!truncate)
695 throw std::overflow_error("stlplus::inf::to_unsigned_short");
696 return result;
697 }
698
699 int inf::to_int(bool truncate) const throw(std::overflow_error)
700 {
701 int result = 0;
702 if (!convert_to_signed(m_data, result))
703 if (!truncate)
704 throw std::overflow_error("stlplus::inf::to_int");
705 return result;
706 }
707
708 unsigned inf::to_unsigned(bool truncate) const throw(std::overflow_error)
709 {
710 unsigned result = 0;
711 if (!convert_to_unsigned(m_data, result))
712 if (!truncate)
713 throw std::overflow_error("stlplus::inf::to_unsigned");
714 return result;
715 }
716
717 long inf::to_long(bool truncate) const throw(std::overflow_error)
718 {
719 long result = 0;
720 if (!convert_to_signed(m_data, result))
721 if (!truncate)
722 throw std::overflow_error("stlplus::inf::to_long");
723 return result;
724 }
725
726 unsigned long inf::to_unsigned_long(bool truncate) const throw(std::overflow_error)
727 {
728 unsigned long result = 0;
729 if (!convert_to_unsigned(m_data, result))
730 if (!truncate)
731 throw std::overflow_error("stlplus::inf::to_unsigned_long");
732 return result;
733 }
734
735 ////////////////////////////////////////////////////////////////////////////////
736 // resize the inf regardless of the data
737
738 void inf::resize(unsigned bits)
739 {
740 if (bits == 0) bits = 1;
741 unsigned bytes = (bits+7)/8;
742 byte extend = negative() ? byte(255) : byte (0);
743 while(bytes > m_data.size())
744 m_data.append(1,extend);
745 }
746
747 // reduce the bit count to the minimum needed to preserve the value
748
749 void inf::reduce(void)
750 {
751 reduce_string(m_data);
752 }
753
754 ////////////////////////////////////////////////////////////////////////////////
755 // the number of significant bits in the number
756
757 unsigned inf::bits (void) const
758 {
759 // The number of significant bits in the integer value - this is the number
760 // of indexable bits less any redundant sign bits at the msb
761 // This does not assume that the inf has been reduced to its minimum form
762 unsigned result = indexable_bits();
763 bool sign = bit(result-1);
764 while (result > 1 && (sign == bit(result-2)))
765 result--;
766 return result;
767 }
768
769 unsigned inf::size(void) const
770 {
771 return bits();
772 }
773
774 unsigned inf::indexable_bits (void) const
775 {
776 return 8 * unsigned(m_data.size());
777 }
778
779 ////////////////////////////////////////////////////////////////////////////////
780 // bitwise operations
781
782 bool inf::bit (unsigned index) const throw(std::out_of_range)
783 {
784 if (index >= indexable_bits())
785 throw std::out_of_range(std::string("stlplus::inf::bit"));
786 // first split the offset into byte offset and bit offset
787 unsigned byte_offset = index/8;
788 unsigned bit_offset = index%8;
789 return (byte(m_data[byte_offset]) & (byte(1) << bit_offset)) != 0;
790 }
791
792 bool inf::operator [] (unsigned index) const throw(std::out_of_range)
793 {
794 return bit(index);
795 }
796
797 void inf::set (unsigned index) throw(std::out_of_range)
798 {
799 if (index >= indexable_bits())
800 throw std::out_of_range(std::string("stlplus::inf::set"));
801 // first split the offset into byte offset and bit offset
802 unsigned byte_offset = index/8;
803 unsigned bit_offset = index%8;
804 m_data[byte_offset] |= (byte(1) << bit_offset);
805 }
806
807 void inf::clear (unsigned index) throw(std::out_of_range)
808 {
809 if (index >= indexable_bits())
810 throw std::out_of_range(std::string("stlplus::inf::clear"));
811 // first split the offset into byte offset and bit offset
812 unsigned byte_offset = index/8;
813 unsigned bit_offset = index%8;
814 m_data[byte_offset] &= (~(byte(1) << bit_offset));
815 }
816
817 void inf::preset (unsigned index, bool value) throw(std::out_of_range)
818 {
819 if (value)
820 set(index);
821 else
822 clear(index);
823 }
824
825 inf inf::slice(unsigned low, unsigned high) const throw(std::out_of_range)
826 {
827 if (low >= indexable_bits())
828 throw std::out_of_range(std::string("stlplus::inf::slice: low index"));
829 if (high >= indexable_bits())
830 throw std::out_of_range(std::string("stlplus::inf::slice: high index"));
831 inf result;
832 if (high >= low)
833 {
834 // create a result the right size and filled with sign bits
835 std::string::size_type result_size = (high-low+1+7)/8;
836 result.m_data.erase();
837 byte extend = bit(high) ? byte(255) : byte (0);
838 while (result.m_data.size() < result_size)
839 result.m_data.append(1,extend);
840 // now set the relevant bits
841 for (unsigned i = low; i <= high; i++)
842 result.preset(i-low, bit(i));
843 }
844 return result;
845 }
846
847 ////////////////////////////////////////////////////////////////////////////////
848 // testing operations
849
850 bool inf::negative (void) const
851 {
852 return bit(indexable_bits()-1);
853 }
854
855 bool inf::natural (void) const
856 {
857 return !negative();
858 }
859
860 bool inf::positive (void) const
861 {
862 return natural() && !zero();
863 }
864
865 bool inf::zero (void) const
866 {
867 for (std::string::size_type i = 0; i < m_data.size(); i++)
868 if (m_data[i] != 0)
869 return false;
870 return true;
871 }
872
873 bool inf::non_zero (void) const
874 {
875 return !zero();
876 }
877
878 bool inf::operator ! (void) const
879 {
880 return zero();
881 }
882
883 ////////////////////////////////////////////////////////////////////////////////
884 // comparison operators
885
886 bool inf::operator == (const inf& r) const
887 {
888 // Two infs are equal if they are numerically equal, even if they are
889 // different sizes (i.e. they could be non-reduced values).
890 // This makes life a little more complicated than if I could assume that values were reduced.
891 byte l_extend = negative() ? byte(255) : byte (0);
892 byte r_extend = r.negative() ? byte(255) : byte (0);
893 std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
894 for (std::string::size_type i = bytes; i--; )
895 {
896 byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
897 byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
898 if (l_byte != r_byte)
899 return false;
900 }
901 return true;
902 }
903
904 bool inf::operator != (const inf& r) const
905 {
906 return !operator==(r);
907 }
908
909 bool inf::operator < (const inf& r) const
910 {
911 // This could be implemented in terms of subtraction. However, it can be
912 // simplified since there is no need to calculate the accurate difference,
913 // just the direction of the difference. I compare from msB down and as
914 // soon as a byte difference is found, that defines the ordering. The
915 // problem is that in 2's-complement, all negative values are greater than
916 // all natural values if you just do a straight unsigned comparison. I
917 // handle this by doing a preliminary test for different signs.
918
919 // For example, a 3-bit signed type has the coding:
920 // 000 = 0
921 // ...
922 // 011 = 3
923 // 100 = -4
924 // ...
925 // 111 = -1
926
927 // So, for natural values, the ordering of the integer values is the
928 // ordering of the bit patterns. Similarly, for negative values, the
929 // ordering of the integer values is the ordering of the bit patterns
930 // However, the bit patterns for the negative values are *greater than*
931 // the natural values. This is a side-effect of the naffness of
932 // 2's-complement representation
933
934 // first handle the case of comparing two values with different signs
935 bool l_sign = negative();
936 bool r_sign = r.negative();
937 if (l_sign != r_sign)
938 {
939 // one argument must be negative and the other natural
940 // the left is less if it is the negative one
941 return l_sign;
942 }
943 // the arguments are the same sign
944 // so the ordering is a simple unsigned byte-by-byte comparison
945 // However, this is complicated by the possibility that the values could be different lengths
946 byte l_extend = l_sign ? byte(255) : byte (0);
947 byte r_extend = r_sign ? byte(255) : byte (0);
948 std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
949 for (std::string::size_type i = bytes; i--; )
950 {
951 byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
952 byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
953 if (l_byte != r_byte)
954 return l_byte < r_byte;
955 }
956 // if I get here, the two are equal, so that is not less-than
957 return false;
958 }
959
960 bool inf::operator <= (const inf& r) const
961 {
962 return !(r < *this);
963 }
964
965 bool inf::operator > (const inf& r) const
966 {
967 return r < *this;
968 }
969
970 bool inf::operator >= (const inf& r) const
971 {
972 return !(*this < r);
973 }
974
975 ////////////////////////////////////////////////////////////////////////////////
976 // logical operators
977
978 inf& inf::invert (void)
979 {
980 for (std::string::size_type i = 0; i < m_data.size(); i++)
981 m_data[i] = ~m_data[i];
982 return *this;
983 }
984
985 inf inf::operator ~ (void) const
986 {
987 inf result(*this);
988 result.invert();
989 return result;
990 }
991
992 inf& inf::operator &= (const inf& r)
993 {
994 // bitwise AND is extended to the length of the largest argument
995 byte l_extend = negative() ? byte(255) : byte (0);
996 byte r_extend = r.negative() ? byte(255) : byte (0);
997 std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
998 for (std::string::size_type i = 0; i < bytes; i++)
999 {
1000 byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
1001 byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
1002 byte result = l_byte & r_byte;
1003 if (i < m_data.size())
1004 m_data[i] = result;
1005 else
1006 m_data.append(1,result);
1007 }
1008 // now reduce the result
1009 reduce();
1010 return *this;
1011 }
1012
1013 inf inf::operator & (const inf& r) const
1014 {
1015 inf result(*this);
1016 result &= r;
1017 return result;
1018 }
1019
1020 inf& inf::operator |= (const inf& r)
1021 {
1022 // bitwise OR is extended to the length of the largest argument
1023 byte l_extend = negative() ? byte(255) : byte (0);
1024 byte r_extend = r.negative() ? byte(255) : byte (0);
1025 std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
1026 for (std::string::size_type i = 0; i < bytes; i++)
1027 {
1028 byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
1029 byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
1030 byte result = l_byte | r_byte;
1031 if (i < m_data.size())
1032 m_data[i] = result;
1033 else
1034 m_data.append(1,result);
1035 }
1036 // now reduce the result
1037 reduce();
1038 return *this;
1039 }
1040
1041 inf inf::operator | (const inf& r) const
1042 {
1043 inf result(*this);
1044 result |= r;
1045 return result;
1046 }
1047
1048 inf& inf::operator ^= (const inf& r)
1049 {
1050 // bitwise XOR is extended to the length of the largest argument
1051 byte l_extend = negative() ? byte(255) : byte (0);
1052 byte r_extend = r.negative() ? byte(255) : byte (0);
1053 std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
1054 for (std::string::size_type i = 0; i < bytes; i++)
1055 {
1056 byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
1057 byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
1058 byte result = l_byte ^ r_byte;
1059 if (i < m_data.size())
1060 m_data[i] = result;
1061 else
1062 m_data.append(1,result);
1063 }
1064 // now reduce the result
1065 reduce();
1066 return *this;
1067 }
1068
1069 inf inf::operator ^ (const inf& r) const
1070 {
1071 inf result(*this);
1072 result ^= r;
1073 return result;
1074 }
1075
1076 ////////////////////////////////////////////////////////////////////////////////
1077 // shift operators all preserve the value by increasing the word size
1078
1079 inf& inf::operator <<= (unsigned shift)
1080 {
1081 // left shift is a shift towards the msb, with 0s being shifted in at the lsb
1082 // split this into a byte shift followed by a bit shift
1083
1084 // first expand the value to be big enough for the result
1085 std::string::size_type new_size = (indexable_bits() + shift + 7) / 8;
1086 byte extend = negative() ? byte(255) : byte (0);
1087 while (m_data.size() < new_size)
1088 m_data.append(1,extend);
1089 // now do the byte shift
1090 unsigned byte_shift = shift/8;
1091 if (byte_shift > 0)
1092 {
1093 for (std::string::size_type b = new_size; b--; )
1094 m_data[b] = (b >= byte_shift) ? m_data[b-byte_shift] : byte(0);
1095 }
1096 // and finally the bit shift
1097 unsigned bit_shift = shift%8;
1098 if (bit_shift > 0)
1099 {
1100 for (std::string::size_type b = new_size; b--; )
1101 {
1102 byte current = byte(m_data[b]);
1103 byte previous = b > 0 ? m_data[b-1] : byte(0);
1104 m_data[b] = (current << bit_shift) | (previous >> (8 - bit_shift));
1105 }
1106 }
1107 // now reduce the result
1108 reduce();
1109 return *this;
1110 }
1111
1112 inf inf::operator << (unsigned shift) const
1113 {
1114 inf result(*this);
1115 result <<= shift;
1116 return result;
1117 }
1118
1119 inf& inf::operator >>= (unsigned shift)
1120 {
1121 // right shift is a shift towards the lsb, with sign bits being shifted in at the msb
1122 // split this into a byte shift followed by a bit shift
1123
1124 // a byte of sign bits
1125 byte extend = negative() ? byte(255) : byte (0);
1126 // do the byte shift
1127 unsigned byte_shift = shift/8;
1128 if (byte_shift > 0)
1129 {
1130 for (std::string::size_type b = 0; b < m_data.size(); b++)
1131 m_data[b] = (b + byte_shift < m_data.size()) ? m_data[b+byte_shift] : extend;
1132 }
1133 // and finally the bit shift
1134 unsigned bit_shift = shift%8;
1135 if (bit_shift > 0)
1136 {
1137 for (std::string::size_type b = 0; b < m_data.size(); b++)
1138 {
1139 byte current = byte(m_data[b]);
1140 byte next = ((b+1) < m_data.size()) ? m_data[b+1] : extend;
1141 byte shifted = (current >> bit_shift) | (next << (8 - bit_shift));
1142 m_data[b] = shifted;
1143 }
1144 }
1145 // now reduce the result
1146 reduce();
1147 return *this;
1148 }
1149
1150 inf inf::operator >> (unsigned shift) const
1151 {
1152 inf result(*this);
1153 result >>= shift;
1154 return result;
1155 }
1156
1157 ////////////////////////////////////////////////////////////////////////////////
1158 // negation operators
1159
1160 inf& inf::negate (void)
1161 {
1162 // do 2's-complement negation
1163 // equivalent to inversion plus one
1164 invert();
1165 operator += (inf(1));
1166 return *this;
1167 }
1168
1169 inf inf::operator - (void) const
1170 {
1171 inf result(*this);
1172 result.negate();
1173 return result;
1174 }
1175
1176 inf& inf::abs(void)
1177 {
1178 if (negative()) negate();
1179 return *this;
1180 }
1181
1182 inf abs(const inf& i)
1183 {
1184 inf result = i;
1185 result.abs();
1186 return result;
1187 }
1188
1189 ////////////////////////////////////////////////////////////////////////////////
1190 // addition operators
1191
1192 inf& inf::operator += (const inf& r)
1193 {
1194 // do 2's-complement addition
1195 // Note that the addition can give a result that is larger than either argument
1196 byte carry = 0;
1197 std::string::size_type max_size = maximum(m_data.size(),r.m_data.size());
1198 byte l_extend = negative() ? byte(255) : byte (0);
1199 byte r_extend = r.negative() ? byte(255) : byte (0);
1200 for (std::string::size_type i = 0; i < max_size; i++)
1201 {
1202 byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
1203 byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
1204 // calculate the addition in a type that is bigger than a byte in order to catch the carry-out
1205 unsigned short result = ((unsigned short)(l_byte)) + ((unsigned short)(r_byte)) + carry;
1206 // now truncate the result to get the lsB
1207 if (i < m_data.size())
1208 m_data[i] = byte(result);
1209 else
1210 m_data.append(1,byte(result));
1211 // and capture the carry out by grabbing the second byte of the result
1212 carry = byte(result >> 8);
1213 }
1214 // if the result overflowed or underflowed, add an extra byte to catch it
1215 unsigned short result = ((unsigned short)(l_extend)) + ((unsigned short)(r_extend)) + carry;
1216 if (byte(result) != (negative() ? byte(255) : byte(0)))
1217 m_data.append(1,byte(result));
1218 // now reduce the result
1219 reduce();
1220 return *this;
1221 }
1222
1223 inf inf::operator + (const inf& r) const
1224 {
1225 inf result(*this);
1226 result += r;
1227 return result;
1228 }
1229
1230 ////////////////////////////////////////////////////////////////////////////////
1231 // subtraction operators
1232
1233 inf& inf::operator -= (const inf& r)
1234 {
1235 // subtraction is defined in terms of negation and addition
1236 inf negated = -r;
1237 operator += (negated);
1238 return *this;
1239 }
1240
1241 inf inf::operator - (const inf& r) const
1242 {
1243 inf result(*this);
1244 result -= r;
1245 return result;
1246 }
1247
1248 ////////////////////////////////////////////////////////////////////////////////
1249 // multiplication operators
1250
1251 inf& inf::operator *= (const inf& r)
1252 {
1253 // 2's complement multiplication
1254 // one day I'll do a more efficient version than this based on the underlying representation
1255 inf left(*this);
1256 inf right = r;
1257 // make the right value natural but preserve its sign for later
1258 bool right_negative = right.negative();
1259 right.abs();
1260 // implemented as a series of conditional additions
1261 operator = (0);
1262 // left.resize(right.bits() + left.bits() - 1);
1263 left <<= right.bits()-1;
1264 for (unsigned i = right.bits(); i--; )
1265 {
1266 if (right[i])
1267 operator += (left);
1268 left >>= 1;
1269 }
1270 if (right_negative)
1271 negate();
1272 // now reduce the result
1273 reduce();
1274 return *this;
1275 }
1276
1277 inf inf::operator * (const inf& r) const
1278 {
1279 inf result(*this);
1280 result *= r;
1281 return result;
1282 }
1283
1284 ////////////////////////////////////////////////////////////////////////////////
1285 // division and remainder operators
1286
1287 std::pair<inf,inf> inf::divide(const inf& right) const throw(divide_by_zero)
1288 {
1289 if (right.zero())
1290 throw divide_by_zero("stlplus::inf::divide");
1291 inf numerator(*this);
1292 inf denominator = right;
1293 // make the numerator natural but preserve the sign for later
1294 bool numerator_negative = numerator.negative();
1295 numerator.abs();
1296 // same with the denominator
1297 bool denominator_negative = denominator.negative();
1298 denominator.abs();
1299 // the quotient and remainder will form the result
1300 // start with the quotiont zero and the remainder equal to the whole of the
1301 // numerator, then do trial subtraction from this
1302 inf quotient;
1303 inf remainder = numerator;
1304 // there's nothing more to do if the numerator is smaller than the denominator
1305 // but otherwise do the division
1306 if (numerator.bits() >= denominator.bits())
1307 {
1308 // make the quotient big enough to take the result
1309 quotient.resize(numerator.bits());
1310 // start with the numerator shifted to the far left
1311 unsigned shift = numerator.bits() - denominator.bits();
1312 denominator <<= shift;
1313 // do the division by repeated subtraction,
1314 for (unsigned i = shift+1; i--; )
1315 {
1316 if (remainder >= denominator)
1317 {
1318 remainder -= denominator;
1319 quotient.set(i);
1320 }
1321 denominator >>= 1;
1322 }
1323 }
1324 // now adjust the signs
1325 // x/(-y) == (-x)/y == -(x/y)
1326 if (numerator_negative != denominator_negative)
1327 quotient.negate();
1328 quotient.reduce();
1329 // x%(-y) == x%y and (-x)%y == -(x%y)
1330 if (numerator_negative)
1331 remainder.negate();
1332 remainder.reduce();
1333 return std::pair<inf,inf>(quotient,remainder);
1334 }
1335
1336 inf& inf::operator /= (const inf& r) throw(divide_by_zero)
1337 {
1338 std::pair<inf,inf> result = divide(r);
1339 operator=(result.first);
1340 return *this;
1341 }
1342
1343 inf inf::operator / (const inf& r) const throw(divide_by_zero)
1344 {
1345 std::pair<inf,inf> result = divide(r);
1346 return result.first;
1347 }
1348
1349 inf& inf::operator %= (const inf& r) throw(divide_by_zero)
1350 {
1351 std::pair<inf,inf> result = divide(r);
1352 operator=(result.second);
1353 return *this;
1354 }
1355
1356 inf inf::operator % (const inf& r) const throw(divide_by_zero)
1357 {
1358 std::pair<inf,inf> result = divide(r);
1359 return result.second;
1360 }
1361
1362 ////////////////////////////////////////////////////////////////////////////////
1363 // prefix (void) and postfix (int) operators
1364
1365 inf& inf::operator ++ (void)
1366 {
1367 operator += (inf(1));
1368 return *this;
1369 }
1370
1371 inf inf::operator ++ (int)
1372 {
1373 inf old(*this);
1374 operator += (inf(1));
1375 return old;
1376 }
1377
1378 inf& inf::operator -- (void)
1379 {
1380 operator -= (inf(1));
1381 return *this;
1382 }
1383
1384 inf inf::operator -- (int)
1385 {
1386 inf old(*this);
1387 operator -= (inf(1));
1388 return old;
1389 }
1390
1391 ////////////////////////////////////////////////////////////////////////////////
1392 // string representation and I/O routines
1393
1394 std::string inf::to_string(unsigned radix) const
1395 throw(std::invalid_argument)
1396 {
1397 std::string result;
1398 convert_to_string(*this, result, radix);
1399 return result;
1400 }
1401
1402 inf& inf::from_string(const std::string& value, unsigned radix)
1403 throw(std::invalid_argument)
1404 {
1405 convert_from_string(value, *this, radix);
1406 return *this;
1407 }
1408
1409 std::ostream& operator << (std::ostream& str, const inf& i)
1410 {
1411 try
1412 {
1413 // get radix
1414 unsigned radix = 10;
1415 if (str.flags() & std::ios_base::oct)
1416 radix = 8;
1417 if (str.flags() & std::ios_base::hex)
1418 radix = 16;
1419 // the field width is handled by iostream, so I don't need to handle it as well
1420 // generate the string representation then print it
1421 str << i.to_string(radix);
1422 }
1423 catch(const std::invalid_argument)
1424 {
1425 str.setstate(std::ios_base::badbit);
1426 }
1427 return str;
1428 }
1429
1430 std::istream& operator >> (std::istream& str, inf& i)
1431 {
1432 try
1433 {
1434 // get radix
1435 unsigned radix = 10;
1436 if (str.flags() & std::ios_base::oct)
1437 radix = 8;
1438 if (str.flags() & std::ios_base::hex)
1439 radix = 16;
1440 // now get the string image of the value
1441 std::string image;
1442 str >> image;
1443 // and convert to inf
1444 i.from_string(image, radix);
1445 }
1446 catch(const std::invalid_argument)
1447 {
1448 str.setstate(std::ios_base::badbit);
1449 }
1450 return str;
1451 }
1452
1453 ////////////////////////////////////////////////////////////////////////////////
1454 // diagnostic dump
1455 // just convert to hex
1456
1457 std::string inf::image_debug(void) const
1458 {
1459 // create this dump in the human-readable form, i.e. msB to the left
1460 std::string result = "0x";
1461 for (std::string::size_type i = m_data.size(); i--; )
1462 {
1463 byte current = m_data[i];
1464 byte msB = (current & byte(0xf0)) >> 4;
1465 result += to_char[msB];
1466 byte lsB = (current & byte(0x0f));
1467 result += to_char[lsB];
1468 }
1469 return result;
1470 }
1471
1472 const std::string& inf::get_bytes(void) const
1473 {
1474 return m_data;
1475 }
1476
1477 void inf::set_bytes(const std::string& data)
1478 {
1479 m_data = data;
1480 }
1481
1482 } // end namespace stlplus
This page took 0.098587 seconds and 4 git commands to generate.