X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fstlplus%2Fportability%2Finf.cpp;h=d70ab76453f40454f25043c39540ec2b6b3f15c6;hp=80b047556783330867ef7dd05c514d7986ef1943;hb=5846afb00833cc72fe72422ca896d2387c712cb4;hpb=a97500609dc3c1b11f9786d32bc458eb00de4c36 diff --git a/src/stlplus/portability/inf.cpp b/src/stlplus/portability/inf.cpp index 80b0475..d70ab76 100644 --- a/src/stlplus/portability/inf.cpp +++ b/src/stlplus/portability/inf.cpp @@ -1,1482 +1,1482 @@ -//////////////////////////////////////////////////////////////////////////////// - -// Author: Andy Rushton -// Copyright: (c) Southampton University 1999-2004 -// (c) Andy Rushton 2004-2009 -// License: BSD License, see ../docs/license.html - -// The integer is represented as a sequence of bytes. They are stored such that -// element 0 is the lsB, which makes sense when seen as an integer offset but -// is counter-intuitive when you think that a string is usually read from left -// to right, 0 to size-1, in which case the lsB is on the *left*. - -// This solution is compatible with 32-bit and 64-bit machines with either -// little-endian or big-endian representations of integers. - -// Problem: I'm using std::string, which is an array of char. However, char is -// not well-defined - it could be signed or unsigned. - -// In fact, there's no requirement for a char to even be one byte - it can be -// any size of one byte or more. However, it's just impossible to make any -// progress with that naffness (thanks to the C non-standardisation committee) -// and the practice is that char on every platform/compiler I've ever come -// across is that char = byte. - -// The algorithms here use unsigned char to represent bit-patterns so I have to -// be careful to type-cast from char to unsigned char a lot. I use a typedef to -// make life easier. - -//////////////////////////////////////////////////////////////////////////////// -#include "inf.hpp" -#include -//////////////////////////////////////////////////////////////////////////////// - -namespace stlplus -{ - - //////////////////////////////////////////////////////////////////////////////// - // choose a sensible C type for a byte - - typedef unsigned char byte; - - //////////////////////////////////////////////////////////////////////////////// - // local functions - - // removes leading bytes that don't contribute to the value to create the minimum string representation - static void reduce_string(std::string& data) - { - while(data.size() > 1 && - ((byte(data[data.size()-1]) == byte(0) && byte(data[data.size()-2]) < byte(128)) || - (byte(data[data.size()-1]) == byte(255) && byte(data[data.size()-2]) >= byte(128)))) - { - data.erase(data.end()-1); - } - } - - // generic implementations of type conversions from integer type to internal representation - // data: integer value for conversion - // result: internal representation - - template - static void convert_from_signed(const T& data, std::string& result) - { - result.erase(); - bool lsb_first = little_endian(); - byte* address = (byte*)&data; - for (size_t i = 0; i < sizeof(T); i++) - { - size_t offset = (lsb_first ? i : (sizeof(T) - i - 1)); - result.append(1,address[offset]); - } - reduce_string(result); - } - - template - static void convert_from_unsigned(const T& data, std::string& result) - { - result.erase(); - bool lsb_first = little_endian(); - byte* address = (byte*)&data; - for (size_t i = 0; i < sizeof(T); i++) - { - size_t offset = (lsb_first ? i : (sizeof(T) - i - 1)); - result.append(1,address[offset]); - } - // inf is signed - so there is a possible extra sign bit to add - result.append(1,std::string::value_type(0)); - reduce_string(result); - } - - // generic implementations of type conversions from internal representation to an integer type - // data : string representation of integer - // result: integer result of conversion - // return: flag indicating success - false = overflow - - template - bool convert_to_signed(const std::string& data, T& result) - { - bool lsb_first = little_endian(); - byte* address = (byte*)&result; - for (size_t i = 0; i < sizeof(T); i++) - { - size_t offset = lsb_first ? i : (sizeof(T) - i - 1); - if (i < data.size()) - address[offset] = byte(data[i]); - else if (data.empty() || (byte(data[data.size()-1]) < byte(128))) - address[offset] = byte(0); - else - address[offset] = byte(255); - } - return data.size() <= sizeof(T); - } - - template - bool convert_to_unsigned(const std::string& data, T& result) - { - bool lsb_first = little_endian(); - byte* address = (byte*)&result; - for (size_t i = 0; i < sizeof(T); i++) - { - size_t offset = lsb_first ? i : (sizeof(T) - i - 1); - if (i < data.size()) - address[offset] = byte(data[i]); - else - address[offset] = byte(0); - } - return data.size() <= sizeof(T); - } - - //////////////////////////////////////////////////////////////////////////////// - // Conversions to string - - static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz"; - static int from_char [] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - static void convert_to_string(const stlplus::inf& data, std::string& result, unsigned radix = 10) - throw(std::invalid_argument) - { - // only support the C-style radixes plus 0b for binary - if (radix != 2 && radix != 8 && radix != 10 && radix != 16) - throw std::invalid_argument("invalid radix value"); - inf local_i = data; - // untangle all the options - bool binary = radix == 2; - bool octal = radix == 8; - bool hex = radix == 16; - // the C representations for binary, octal and hex use 2's-complement representation - // all other represenations use sign-magnitude - if (hex || octal || binary) - { - // bit-pattern representation - // this is the binary representation optionally shown in octal or hex - // first generate the binary by masking the bits - for (unsigned j = local_i.bits(); j--; ) - result += (local_i.bit(j) ? '1' : '0'); - // the result is now the full width of the type - e.g. int will give a 32-bit result - // now interpret this as either binary, octal or hex and add the prefix - if (binary) - { - // trim down to the smallest string that preserves the value - while (true) - { - // do not trim to less than 1 bit (sign only) - if (result.size() <= 1) break; - // only trim if it doesn't change the sign and therefore the value - if (result[0] != result[1]) break; - result.erase(0,1); - } - // add the prefix - result.insert((std::string::size_type)0, "0b"); - } - else if (octal) - { - // the result is currently binary - // trim down to the smallest string that preserves the value - while (true) - { - // do not trim to less than 2 bits (sign plus 1-bit magnitude) - if (result.size() <= 2) break; - // only trim if it doesn't change the sign and therefore the value - if (result[0] != result[1]) break; - result.erase(0,1); - } - // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier - while (result.size() % 3 != 0) - result.insert((std::string::size_type)0, 1, result[0]); - // now convert to octal - std::string octal_result; - for (unsigned i = 0; i < result.size()/3; i++) - { - // yuck - ugly or what? - if (result[i*3] == '0') - { - if (result[i*3+1] == '0') - { - if (result[i*3+2] == '0') - octal_result += '0'; - else - octal_result += '1'; - } - else - { - if (result[i*3+2] == '0') - octal_result += '2'; - else - octal_result += '3'; - } - } - else - { - if (result[i*3+1] == '0') - { - if (result[i*3+2] == '0') - octal_result += '4'; - else - octal_result += '5'; - } - else - { - if (result[i*3+2] == '0') - octal_result += '6'; - else - octal_result += '7'; - } - } - } - result = octal_result; - // add the prefix - result.insert((std::string::size_type)0, "0"); - } - else - { - // similar to octal - while (true) - { - // do not trim to less than 2 bits (sign plus 1-bit magnitude) - if (result.size() <= 2) break; - // only trim if it doesn't change the sign and therefore the value - if (result[0] != result[1]) break; - result.erase(0,1); - } - // pad to a multiple of 4 characters - while (result.size() % 4 != 0) - result.insert((std::string::size_type)0, 1, result[0]); - // now convert to hex - std::string hex_result; - for (unsigned i = 0; i < result.size()/4; i++) - { - // yuck - ugly or what? - if (result[i*4] == '0') - { - if (result[i*4+1] == '0') - { - if (result[i*4+2] == '0') - { - if (result[i*4+3] == '0') - hex_result += '0'; - else - hex_result += '1'; - } - else - { - if (result[i*4+3] == '0') - hex_result += '2'; - else - hex_result += '3'; - } - } - else - { - if (result[i*4+2] == '0') - { - if (result[i*4+3] == '0') - hex_result += '4'; - else - hex_result += '5'; - } - else - { - if (result[i*4+3] == '0') - hex_result += '6'; - else - hex_result += '7'; - } - } - } - else - { - if (result[i*4+1] == '0') - { - if (result[i*4+2] == '0') - { - if (result[i*4+3] == '0') - hex_result += '8'; - else - hex_result += '9'; - } - else - { - if (result[i*4+3] == '0') - hex_result += 'a'; - else - hex_result += 'b'; - } - } - else - { - if (result[i*4+2] == '0') - { - if (result[i*4+3] == '0') - hex_result += 'c'; - else - hex_result += 'd'; - } - else - { - if (result[i*4+3] == '0') - hex_result += 'e'; - else - hex_result += 'f'; - } - } - } - } - result = hex_result; - // add the prefix - result.insert((std::string::size_type)0, "0x"); - } - } - else - { - // convert to sign-magnitude - // the representation is: - // [sign]magnitude - bool negative = local_i.negative(); - local_i.abs(); - // create a representation of the magnitude by successive division - inf inf_radix(radix); - do - { - std::pair divided = local_i.divide(inf_radix); - unsigned remainder = divided.second.to_unsigned(); - char digit = to_char[remainder]; - result.insert((std::string::size_type)0, 1, digit); - local_i = divided.first; - } - while(!local_i.zero()); - // add the prefixes - // add a sign only for negative values - if (negative) - result.insert((std::string::size_type)0, 1, '-'); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // Conversions FROM string - - void convert_from_string(const std::string& str, inf& result, unsigned radix = 10) throw(std::invalid_argument) - { - result = 0; - // only support the C-style radixes plus 0b for binary - // a radix of 0 means deduce the radix from the input - assume 10 - if (radix != 0 && radix != 2 && radix != 8 && radix != 10 && radix != 16) - throw std::invalid_argument("invalid radix value"); - unsigned i = 0; - // the radix passed as a parameter is just the default - it can be - // overridden by the C prefix - // Note: a leading zero is the C-style prefix for octal - I only make this - // override the default when the default radix is not specified - // first check for a C-style prefix - bool c_style = false; - if (i < str.size() && str[i] == '0') - { - // binary or hex - if (i+1 < str.size() && tolower(str[i+1]) == 'x') - { - c_style = true; - radix = 16; - i += 2; - } - else if (i+1 < str.size() && tolower(str[i+1]) == 'b') - { - c_style = true; - radix = 2; - i += 2; - } - else if (radix == 0) - { - c_style = true; - radix = 8; - i += 1; - } - } - if (radix == 0) - radix = 10; - if (c_style) - { - // the C style formats are bit patterns not integer values - these need - // to be sign-extended to get the right value - std::string binary; - if (radix == 2) - { - for (unsigned j = i; j < str.size(); j++) - { - switch(str[j]) - { - case '0': - binary += '0'; - break; - case '1': - binary += '1'; - break; - default: - throw std::invalid_argument("invalid binary character in string " + str); - } - } - } - else if (radix == 8) - { - for (unsigned j = i; j < str.size(); j++) - { - switch(str[j]) - { - case '0': - binary += "000"; - break; - case '1': - binary += "001"; - break; - case '2': - binary += "010"; - break; - case '3': - binary += "011"; - break; - case '4': - binary += "100"; - break; - case '5': - binary += "101"; - break; - case '6': - binary += "110"; - break; - case '7': - binary += "111"; - break; - default: - throw std::invalid_argument("invalid octal character in string " + str); - } - } - } - else - { - for (unsigned j = i; j < str.size(); j++) - { - switch(tolower(str[j])) - { - case '0': - binary += "0000"; - break; - case '1': - binary += "0001"; - break; - case '2': - binary += "0010"; - break; - case '3': - binary += "0011"; - break; - case '4': - binary += "0100"; - break; - case '5': - binary += "0101"; - break; - case '6': - binary += "0110"; - break; - case '7': - binary += "0111"; - break; - case '8': - binary += "1000"; - break; - case '9': - binary += "1001"; - break; - case 'a': - binary += "1010"; - break; - case 'b': - binary += "1011"; - break; - case 'c': - binary += "1100"; - break; - case 'd': - binary += "1101"; - break; - case 'e': - binary += "1110"; - break; - case 'f': - binary += "1111"; - break; - default: - throw std::invalid_argument("invalid hex character in string " + str); - } - } - } - // now convert the value - result.resize(binary.size()); - for (unsigned j = 0; j < binary.size(); j++) - result.preset(binary.size() - j - 1, binary[j] == '1'); - } - else - { - // sign-magnitude representation - // now scan for a sign and find whether this is a negative number - bool negative = false; - if (i < str.size()) - { - switch (str[i]) - { - case '-': - negative = true; - i++; - break; - case '+': - i++; - break; - } - } - for (; i < str.size(); i++) - { - result *= inf(radix); - unsigned char ascii = (unsigned char)str[i]; - int ch = from_char[ascii] ; - if (ch == -1) - throw std::invalid_argument("invalid decimal character in string " + str); - result += inf(ch); - } - if (negative) - result.negate(); - } - } - - //////////////////////////////////////////////////////////////////////////////// - // constructors - mostly implemented in terms of the assignment operators - - inf::inf(void) - { - // void constructor initialises to zero - represented as a single-byte value containing zero - m_data.append(1,std::string::value_type(0)); - } - - inf::inf(short r) - { - operator=(r); - } - - inf::inf(unsigned short r) - { - operator=(r); - } - - inf::inf(int r) - { - operator=(r); - } - - inf::inf(unsigned r) - { - operator=(r); - } - - inf::inf(long r) - { - operator=(r); - } - - inf::inf(unsigned long r) - { - operator=(r); - } - - inf::inf (const std::string& r) throw(std::invalid_argument) - { - operator=(r); - } - - inf::inf(const inf& r) - { -#ifdef __BORLANDC__ - // work round bug in Borland compiler - copy constructor fails if string - // contains null characters, so do my own copy - for (unsigned i = 0; i < r.m_data.size(); i++) - m_data += r.m_data[i]; -#else - m_data = r.m_data; -#endif - } - - //////////////////////////////////////////////////////////////////////////////// - - inf::~inf(void) - { - } - - //////////////////////////////////////////////////////////////////////////////// - // assignments convert from iteger types to internal representation - - inf& inf::operator = (short r) - { - convert_from_signed(r, m_data); - return *this; - } - - inf& inf::operator = (unsigned short r) - { - convert_from_unsigned(r, m_data); - return *this; - } - - inf& inf::operator = (int r) - { - convert_from_signed(r, m_data); - return *this; - } - - inf& inf::operator = (unsigned r) - { - convert_from_unsigned(r, m_data); - return *this; - } - - inf& inf::operator = (long r) - { - convert_from_signed(r, m_data); - return *this; - } - - inf& inf::operator = (unsigned long r) - { - convert_from_unsigned(r, m_data); - return *this; - } - - inf& inf::operator = (const std::string& r) throw(std::invalid_argument) - { - convert_from_string(r, *this); - return *this; - } - - inf& inf::operator = (const inf& r) - { - m_data = r.m_data; - return *this; - } - - //////////////////////////////////////////////////////////////////////////////// - - short inf::to_short(bool truncate) const throw(std::overflow_error) - { - short result = 0; - if (!convert_to_signed(m_data, result)) - if (!truncate) - throw std::overflow_error("stlplus::inf::to_short"); - return result; - } - - unsigned short inf::to_unsigned_short(bool truncate) const throw(std::overflow_error) - { - unsigned short result = 0; - if (!convert_to_unsigned(m_data, result)) - if (!truncate) - throw std::overflow_error("stlplus::inf::to_unsigned_short"); - return result; - } - - int inf::to_int(bool truncate) const throw(std::overflow_error) - { - int result = 0; - if (!convert_to_signed(m_data, result)) - if (!truncate) - throw std::overflow_error("stlplus::inf::to_int"); - return result; - } - - unsigned inf::to_unsigned(bool truncate) const throw(std::overflow_error) - { - unsigned result = 0; - if (!convert_to_unsigned(m_data, result)) - if (!truncate) - throw std::overflow_error("stlplus::inf::to_unsigned"); - return result; - } - - long inf::to_long(bool truncate) const throw(std::overflow_error) - { - long result = 0; - if (!convert_to_signed(m_data, result)) - if (!truncate) - throw std::overflow_error("stlplus::inf::to_long"); - return result; - } - - unsigned long inf::to_unsigned_long(bool truncate) const throw(std::overflow_error) - { - unsigned long result = 0; - if (!convert_to_unsigned(m_data, result)) - if (!truncate) - throw std::overflow_error("stlplus::inf::to_unsigned_long"); - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // resize the inf regardless of the data - - void inf::resize(unsigned bits) - { - if (bits == 0) bits = 1; - unsigned bytes = (bits+7)/8; - byte extend = negative() ? byte(255) : byte (0); - while(bytes > m_data.size()) - m_data.append(1,extend); - } - - // reduce the bit count to the minimum needed to preserve the value - - void inf::reduce(void) - { - reduce_string(m_data); - } - - //////////////////////////////////////////////////////////////////////////////// - // the number of significant bits in the number - - unsigned inf::bits (void) const - { - // The number of significant bits in the integer value - this is the number - // of indexable bits less any redundant sign bits at the msb - // This does not assume that the inf has been reduced to its minimum form - unsigned result = indexable_bits(); - bool sign = bit(result-1); - while (result > 1 && (sign == bit(result-2))) - result--; - return result; - } - - unsigned inf::size(void) const - { - return bits(); - } - - unsigned inf::indexable_bits (void) const - { - return 8 * unsigned(m_data.size()); - } - - //////////////////////////////////////////////////////////////////////////////// - // bitwise operations - - bool inf::bit (unsigned index) const throw(std::out_of_range) - { - if (index >= indexable_bits()) - throw std::out_of_range(std::string("stlplus::inf::bit")); - // first split the offset into byte offset and bit offset - unsigned byte_offset = index/8; - unsigned bit_offset = index%8; - return (byte(m_data[byte_offset]) & (byte(1) << bit_offset)) != 0; - } - - bool inf::operator [] (unsigned index) const throw(std::out_of_range) - { - return bit(index); - } - - void inf::set (unsigned index) throw(std::out_of_range) - { - if (index >= indexable_bits()) - throw std::out_of_range(std::string("stlplus::inf::set")); - // first split the offset into byte offset and bit offset - unsigned byte_offset = index/8; - unsigned bit_offset = index%8; - m_data[byte_offset] |= (byte(1) << bit_offset); - } - - void inf::clear (unsigned index) throw(std::out_of_range) - { - if (index >= indexable_bits()) - throw std::out_of_range(std::string("stlplus::inf::clear")); - // first split the offset into byte offset and bit offset - unsigned byte_offset = index/8; - unsigned bit_offset = index%8; - m_data[byte_offset] &= (~(byte(1) << bit_offset)); - } - - void inf::preset (unsigned index, bool value) throw(std::out_of_range) - { - if (value) - set(index); - else - clear(index); - } - - inf inf::slice(unsigned low, unsigned high) const throw(std::out_of_range) - { - if (low >= indexable_bits()) - throw std::out_of_range(std::string("stlplus::inf::slice: low index")); - if (high >= indexable_bits()) - throw std::out_of_range(std::string("stlplus::inf::slice: high index")); - inf result; - if (high >= low) - { - // create a result the right size and filled with sign bits - std::string::size_type result_size = (high-low+1+7)/8; - result.m_data.erase(); - byte extend = bit(high) ? byte(255) : byte (0); - while (result.m_data.size() < result_size) - result.m_data.append(1,extend); - // now set the relevant bits - for (unsigned i = low; i <= high; i++) - result.preset(i-low, bit(i)); - } - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // testing operations - - bool inf::negative (void) const - { - return bit(indexable_bits()-1); - } - - bool inf::natural (void) const - { - return !negative(); - } - - bool inf::positive (void) const - { - return natural() && !zero(); - } - - bool inf::zero (void) const - { - for (std::string::size_type i = 0; i < m_data.size(); i++) - if (m_data[i] != 0) - return false; - return true; - } - - bool inf::non_zero (void) const - { - return !zero(); - } - - bool inf::operator ! (void) const - { - return zero(); - } - - //////////////////////////////////////////////////////////////////////////////// - // comparison operators - - bool inf::operator == (const inf& r) const - { - // Two infs are equal if they are numerically equal, even if they are - // different sizes (i.e. they could be non-reduced values). - // This makes life a little more complicated than if I could assume that values were reduced. - byte l_extend = negative() ? byte(255) : byte (0); - byte r_extend = r.negative() ? byte(255) : byte (0); - std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); - for (std::string::size_type i = bytes; i--; ) - { - byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); - byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); - if (l_byte != r_byte) - return false; - } - return true; - } - - bool inf::operator != (const inf& r) const - { - return !operator==(r); - } - - bool inf::operator < (const inf& r) const - { - // This could be implemented in terms of subtraction. However, it can be - // simplified since there is no need to calculate the accurate difference, - // just the direction of the difference. I compare from msB down and as - // soon as a byte difference is found, that defines the ordering. The - // problem is that in 2's-complement, all negative values are greater than - // all natural values if you just do a straight unsigned comparison. I - // handle this by doing a preliminary test for different signs. - - // For example, a 3-bit signed type has the coding: - // 000 = 0 - // ... - // 011 = 3 - // 100 = -4 - // ... - // 111 = -1 - - // So, for natural values, the ordering of the integer values is the - // ordering of the bit patterns. Similarly, for negative values, the - // ordering of the integer values is the ordering of the bit patterns - // However, the bit patterns for the negative values are *greater than* - // the natural values. This is a side-effect of the naffness of - // 2's-complement representation - - // first handle the case of comparing two values with different signs - bool l_sign = negative(); - bool r_sign = r.negative(); - if (l_sign != r_sign) - { - // one argument must be negative and the other natural - // the left is less if it is the negative one - return l_sign; - } - // the arguments are the same sign - // so the ordering is a simple unsigned byte-by-byte comparison - // However, this is complicated by the possibility that the values could be different lengths - byte l_extend = l_sign ? byte(255) : byte (0); - byte r_extend = r_sign ? byte(255) : byte (0); - std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); - for (std::string::size_type i = bytes; i--; ) - { - byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); - byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); - if (l_byte != r_byte) - return l_byte < r_byte; - } - // if I get here, the two are equal, so that is not less-than - return false; - } - - bool inf::operator <= (const inf& r) const - { - return !(r < *this); - } - - bool inf::operator > (const inf& r) const - { - return r < *this; - } - - bool inf::operator >= (const inf& r) const - { - return !(*this < r); - } - - //////////////////////////////////////////////////////////////////////////////// - // logical operators - - inf& inf::invert (void) - { - for (std::string::size_type i = 0; i < m_data.size(); i++) - m_data[i] = ~m_data[i]; - return *this; - } - - inf inf::operator ~ (void) const - { - inf result(*this); - result.invert(); - return result; - } - - inf& inf::operator &= (const inf& r) - { - // bitwise AND is extended to the length of the largest argument - byte l_extend = negative() ? byte(255) : byte (0); - byte r_extend = r.negative() ? byte(255) : byte (0); - std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); - for (std::string::size_type i = 0; i < bytes; i++) - { - byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); - byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); - byte result = l_byte & r_byte; - if (i < m_data.size()) - m_data[i] = result; - else - m_data.append(1,result); - } - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator & (const inf& r) const - { - inf result(*this); - result &= r; - return result; - } - - inf& inf::operator |= (const inf& r) - { - // bitwise OR is extended to the length of the largest argument - byte l_extend = negative() ? byte(255) : byte (0); - byte r_extend = r.negative() ? byte(255) : byte (0); - std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); - for (std::string::size_type i = 0; i < bytes; i++) - { - byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); - byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); - byte result = l_byte | r_byte; - if (i < m_data.size()) - m_data[i] = result; - else - m_data.append(1,result); - } - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator | (const inf& r) const - { - inf result(*this); - result |= r; - return result; - } - - inf& inf::operator ^= (const inf& r) - { - // bitwise XOR is extended to the length of the largest argument - byte l_extend = negative() ? byte(255) : byte (0); - byte r_extend = r.negative() ? byte(255) : byte (0); - std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); - for (std::string::size_type i = 0; i < bytes; i++) - { - byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); - byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); - byte result = l_byte ^ r_byte; - if (i < m_data.size()) - m_data[i] = result; - else - m_data.append(1,result); - } - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator ^ (const inf& r) const - { - inf result(*this); - result ^= r; - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // shift operators all preserve the value by increasing the word size - - inf& inf::operator <<= (unsigned shift) - { - // left shift is a shift towards the msb, with 0s being shifted in at the lsb - // split this into a byte shift followed by a bit shift - - // first expand the value to be big enough for the result - std::string::size_type new_size = (indexable_bits() + shift + 7) / 8; - byte extend = negative() ? byte(255) : byte (0); - while (m_data.size() < new_size) - m_data.append(1,extend); - // now do the byte shift - unsigned byte_shift = shift/8; - if (byte_shift > 0) - { - for (std::string::size_type b = new_size; b--; ) - m_data[b] = (b >= byte_shift) ? m_data[b-byte_shift] : byte(0); - } - // and finally the bit shift - unsigned bit_shift = shift%8; - if (bit_shift > 0) - { - for (std::string::size_type b = new_size; b--; ) - { - byte current = byte(m_data[b]); - byte previous = b > 0 ? m_data[b-1] : byte(0); - m_data[b] = (current << bit_shift) | (previous >> (8 - bit_shift)); - } - } - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator << (unsigned shift) const - { - inf result(*this); - result <<= shift; - return result; - } - - inf& inf::operator >>= (unsigned shift) - { - // right shift is a shift towards the lsb, with sign bits being shifted in at the msb - // split this into a byte shift followed by a bit shift - - // a byte of sign bits - byte extend = negative() ? byte(255) : byte (0); - // do the byte shift - unsigned byte_shift = shift/8; - if (byte_shift > 0) - { - for (std::string::size_type b = 0; b < m_data.size(); b++) - m_data[b] = (b + byte_shift < m_data.size()) ? m_data[b+byte_shift] : extend; - } - // and finally the bit shift - unsigned bit_shift = shift%8; - if (bit_shift > 0) - { - for (std::string::size_type b = 0; b < m_data.size(); b++) - { - byte current = byte(m_data[b]); - byte next = ((b+1) < m_data.size()) ? m_data[b+1] : extend; - byte shifted = (current >> bit_shift) | (next << (8 - bit_shift)); - m_data[b] = shifted; - } - } - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator >> (unsigned shift) const - { - inf result(*this); - result >>= shift; - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // negation operators - - inf& inf::negate (void) - { - // do 2's-complement negation - // equivalent to inversion plus one - invert(); - operator += (inf(1)); - return *this; - } - - inf inf::operator - (void) const - { - inf result(*this); - result.negate(); - return result; - } - - inf& inf::abs(void) - { - if (negative()) negate(); - return *this; - } - - inf abs(const inf& i) - { - inf result = i; - result.abs(); - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // addition operators - - inf& inf::operator += (const inf& r) - { - // do 2's-complement addition - // Note that the addition can give a result that is larger than either argument - byte carry = 0; - std::string::size_type max_size = maximum(m_data.size(),r.m_data.size()); - byte l_extend = negative() ? byte(255) : byte (0); - byte r_extend = r.negative() ? byte(255) : byte (0); - for (std::string::size_type i = 0; i < max_size; i++) - { - byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); - byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); - // calculate the addition in a type that is bigger than a byte in order to catch the carry-out - unsigned short result = ((unsigned short)(l_byte)) + ((unsigned short)(r_byte)) + carry; - // now truncate the result to get the lsB - if (i < m_data.size()) - m_data[i] = byte(result); - else - m_data.append(1,byte(result)); - // and capture the carry out by grabbing the second byte of the result - carry = byte(result >> 8); - } - // if the result overflowed or underflowed, add an extra byte to catch it - unsigned short result = ((unsigned short)(l_extend)) + ((unsigned short)(r_extend)) + carry; - if (byte(result) != (negative() ? byte(255) : byte(0))) - m_data.append(1,byte(result)); - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator + (const inf& r) const - { - inf result(*this); - result += r; - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // subtraction operators - - inf& inf::operator -= (const inf& r) - { - // subtraction is defined in terms of negation and addition - inf negated = -r; - operator += (negated); - return *this; - } - - inf inf::operator - (const inf& r) const - { - inf result(*this); - result -= r; - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // multiplication operators - - inf& inf::operator *= (const inf& r) - { - // 2's complement multiplication - // one day I'll do a more efficient version than this based on the underlying representation - inf left(*this); - inf right = r; - // make the right value natural but preserve its sign for later - bool right_negative = right.negative(); - right.abs(); - // implemented as a series of conditional additions - operator = (0); - // left.resize(right.bits() + left.bits() - 1); - left <<= right.bits()-1; - for (unsigned i = right.bits(); i--; ) - { - if (right[i]) - operator += (left); - left >>= 1; - } - if (right_negative) - negate(); - // now reduce the result - reduce(); - return *this; - } - - inf inf::operator * (const inf& r) const - { - inf result(*this); - result *= r; - return result; - } - - //////////////////////////////////////////////////////////////////////////////// - // division and remainder operators - - std::pair inf::divide(const inf& right) const throw(divide_by_zero) - { - if (right.zero()) - throw divide_by_zero("stlplus::inf::divide"); - inf numerator(*this); - inf denominator = right; - // make the numerator natural but preserve the sign for later - bool numerator_negative = numerator.negative(); - numerator.abs(); - // same with the denominator - bool denominator_negative = denominator.negative(); - denominator.abs(); - // the quotient and remainder will form the result - // start with the quotiont zero and the remainder equal to the whole of the - // numerator, then do trial subtraction from this - inf quotient; - inf remainder = numerator; - // there's nothing more to do if the numerator is smaller than the denominator - // but otherwise do the division - if (numerator.bits() >= denominator.bits()) - { - // make the quotient big enough to take the result - quotient.resize(numerator.bits()); - // start with the numerator shifted to the far left - unsigned shift = numerator.bits() - denominator.bits(); - denominator <<= shift; - // do the division by repeated subtraction, - for (unsigned i = shift+1; i--; ) - { - if (remainder >= denominator) - { - remainder -= denominator; - quotient.set(i); - } - denominator >>= 1; - } - } - // now adjust the signs - // x/(-y) == (-x)/y == -(x/y) - if (numerator_negative != denominator_negative) - quotient.negate(); - quotient.reduce(); - // x%(-y) == x%y and (-x)%y == -(x%y) - if (numerator_negative) - remainder.negate(); - remainder.reduce(); - return std::pair(quotient,remainder); - } - - inf& inf::operator /= (const inf& r) throw(divide_by_zero) - { - std::pair result = divide(r); - operator=(result.first); - return *this; - } - - inf inf::operator / (const inf& r) const throw(divide_by_zero) - { - std::pair result = divide(r); - return result.first; - } - - inf& inf::operator %= (const inf& r) throw(divide_by_zero) - { - std::pair result = divide(r); - operator=(result.second); - return *this; - } - - inf inf::operator % (const inf& r) const throw(divide_by_zero) - { - std::pair result = divide(r); - return result.second; - } - - //////////////////////////////////////////////////////////////////////////////// - // prefix (void) and postfix (int) operators - - inf& inf::operator ++ (void) - { - operator += (inf(1)); - return *this; - } - - inf inf::operator ++ (int) - { - inf old(*this); - operator += (inf(1)); - return old; - } - - inf& inf::operator -- (void) - { - operator -= (inf(1)); - return *this; - } - - inf inf::operator -- (int) - { - inf old(*this); - operator -= (inf(1)); - return old; - } - - //////////////////////////////////////////////////////////////////////////////// - // string representation and I/O routines - - std::string inf::to_string(unsigned radix) const - throw(std::invalid_argument) - { - std::string result; - convert_to_string(*this, result, radix); - return result; - } - - inf& inf::from_string(const std::string& value, unsigned radix) - throw(std::invalid_argument) - { - convert_from_string(value, *this, radix); - return *this; - } - - std::ostream& operator << (std::ostream& str, const inf& i) - { - try - { - // get radix - unsigned radix = 10; - if (str.flags() & std::ios_base::oct) - radix = 8; - if (str.flags() & std::ios_base::hex) - radix = 16; - // the field width is handled by iostream, so I don't need to handle it as well - // generate the string representation then print it - str << i.to_string(radix); - } - catch(const std::invalid_argument) - { - str.setstate(std::ios_base::badbit); - } - return str; - } - - std::istream& operator >> (std::istream& str, inf& i) - { - try - { - // get radix - unsigned radix = 10; - if (str.flags() & std::ios_base::oct) - radix = 8; - if (str.flags() & std::ios_base::hex) - radix = 16; - // now get the string image of the value - std::string image; - str >> image; - // and convert to inf - i.from_string(image, radix); - } - catch(const std::invalid_argument) - { - str.setstate(std::ios_base::badbit); - } - return str; - } - - //////////////////////////////////////////////////////////////////////////////// - // diagnostic dump - // just convert to hex - - std::string inf::image_debug(void) const - { - // create this dump in the human-readable form, i.e. msB to the left - std::string result = "0x"; - for (std::string::size_type i = m_data.size(); i--; ) - { - byte current = m_data[i]; - byte msB = (current & byte(0xf0)) >> 4; - result += to_char[msB]; - byte lsB = (current & byte(0x0f)); - result += to_char[lsB]; - } - return result; - } - - const std::string& inf::get_bytes(void) const - { - return m_data; - } - - void inf::set_bytes(const std::string& data) - { - m_data = data; - } - -} // end namespace stlplus +//////////////////////////////////////////////////////////////////////////////// + +// Author: Andy Rushton +// Copyright: (c) Southampton University 1999-2004 +// (c) Andy Rushton 2004-2009 +// License: BSD License, see ../docs/license.html + +// The integer is represented as a sequence of bytes. They are stored such that +// element 0 is the lsB, which makes sense when seen as an integer offset but +// is counter-intuitive when you think that a string is usually read from left +// to right, 0 to size-1, in which case the lsB is on the *left*. + +// This solution is compatible with 32-bit and 64-bit machines with either +// little-endian or big-endian representations of integers. + +// Problem: I'm using std::string, which is an array of char. However, char is +// not well-defined - it could be signed or unsigned. + +// In fact, there's no requirement for a char to even be one byte - it can be +// any size of one byte or more. However, it's just impossible to make any +// progress with that naffness (thanks to the C non-standardisation committee) +// and the practice is that char on every platform/compiler I've ever come +// across is that char = byte. + +// The algorithms here use unsigned char to represent bit-patterns so I have to +// be careful to type-cast from char to unsigned char a lot. I use a typedef to +// make life easier. + +//////////////////////////////////////////////////////////////////////////////// +#include "inf.hpp" +#include +//////////////////////////////////////////////////////////////////////////////// + +namespace stlplus +{ + + //////////////////////////////////////////////////////////////////////////////// + // choose a sensible C type for a byte + + typedef unsigned char byte; + + //////////////////////////////////////////////////////////////////////////////// + // local functions + + // removes leading bytes that don't contribute to the value to create the minimum string representation + static void reduce_string(std::string& data) + { + while(data.size() > 1 && + ((byte(data[data.size()-1]) == byte(0) && byte(data[data.size()-2]) < byte(128)) || + (byte(data[data.size()-1]) == byte(255) && byte(data[data.size()-2]) >= byte(128)))) + { + data.erase(data.end()-1); + } + } + + // generic implementations of type conversions from integer type to internal representation + // data: integer value for conversion + // result: internal representation + + template + static void convert_from_signed(const T& data, std::string& result) + { + result.erase(); + bool lsb_first = little_endian(); + byte* address = (byte*)&data; + for (size_t i = 0; i < sizeof(T); i++) + { + size_t offset = (lsb_first ? i : (sizeof(T) - i - 1)); + result.append(1,address[offset]); + } + reduce_string(result); + } + + template + static void convert_from_unsigned(const T& data, std::string& result) + { + result.erase(); + bool lsb_first = little_endian(); + byte* address = (byte*)&data; + for (size_t i = 0; i < sizeof(T); i++) + { + size_t offset = (lsb_first ? i : (sizeof(T) - i - 1)); + result.append(1,address[offset]); + } + // inf is signed - so there is a possible extra sign bit to add + result.append(1,std::string::value_type(0)); + reduce_string(result); + } + + // generic implementations of type conversions from internal representation to an integer type + // data : string representation of integer + // result: integer result of conversion + // return: flag indicating success - false = overflow + + template + bool convert_to_signed(const std::string& data, T& result) + { + bool lsb_first = little_endian(); + byte* address = (byte*)&result; + for (size_t i = 0; i < sizeof(T); i++) + { + size_t offset = lsb_first ? i : (sizeof(T) - i - 1); + if (i < data.size()) + address[offset] = byte(data[i]); + else if (data.empty() || (byte(data[data.size()-1]) < byte(128))) + address[offset] = byte(0); + else + address[offset] = byte(255); + } + return data.size() <= sizeof(T); + } + + template + bool convert_to_unsigned(const std::string& data, T& result) + { + bool lsb_first = little_endian(); + byte* address = (byte*)&result; + for (size_t i = 0; i < sizeof(T); i++) + { + size_t offset = lsb_first ? i : (sizeof(T) - i - 1); + if (i < data.size()) + address[offset] = byte(data[i]); + else + address[offset] = byte(0); + } + return data.size() <= sizeof(T); + } + + //////////////////////////////////////////////////////////////////////////////// + // Conversions to string + + static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static int from_char [] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + static void convert_to_string(const stlplus::inf& data, std::string& result, unsigned radix = 10) + throw(std::invalid_argument) + { + // only support the C-style radixes plus 0b for binary + if (radix != 2 && radix != 8 && radix != 10 && radix != 16) + throw std::invalid_argument("invalid radix value"); + inf local_i = data; + // untangle all the options + bool binary = radix == 2; + bool octal = radix == 8; + bool hex = radix == 16; + // the C representations for binary, octal and hex use 2's-complement representation + // all other represenations use sign-magnitude + if (hex || octal || binary) + { + // bit-pattern representation + // this is the binary representation optionally shown in octal or hex + // first generate the binary by masking the bits + for (unsigned j = local_i.bits(); j--; ) + result += (local_i.bit(j) ? '1' : '0'); + // the result is now the full width of the type - e.g. int will give a 32-bit result + // now interpret this as either binary, octal or hex and add the prefix + if (binary) + { + // trim down to the smallest string that preserves the value + while (true) + { + // do not trim to less than 1 bit (sign only) + if (result.size() <= 1) break; + // only trim if it doesn't change the sign and therefore the value + if (result[0] != result[1]) break; + result.erase(0,1); + } + // add the prefix + result.insert((std::string::size_type)0, "0b"); + } + else if (octal) + { + // the result is currently binary + // trim down to the smallest string that preserves the value + while (true) + { + // do not trim to less than 2 bits (sign plus 1-bit magnitude) + if (result.size() <= 2) break; + // only trim if it doesn't change the sign and therefore the value + if (result[0] != result[1]) break; + result.erase(0,1); + } + // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier + while (result.size() % 3 != 0) + result.insert((std::string::size_type)0, 1, result[0]); + // now convert to octal + std::string octal_result; + for (unsigned i = 0; i < result.size()/3; i++) + { + // yuck - ugly or what? + if (result[i*3] == '0') + { + if (result[i*3+1] == '0') + { + if (result[i*3+2] == '0') + octal_result += '0'; + else + octal_result += '1'; + } + else + { + if (result[i*3+2] == '0') + octal_result += '2'; + else + octal_result += '3'; + } + } + else + { + if (result[i*3+1] == '0') + { + if (result[i*3+2] == '0') + octal_result += '4'; + else + octal_result += '5'; + } + else + { + if (result[i*3+2] == '0') + octal_result += '6'; + else + octal_result += '7'; + } + } + } + result = octal_result; + // add the prefix + result.insert((std::string::size_type)0, "0"); + } + else + { + // similar to octal + while (true) + { + // do not trim to less than 2 bits (sign plus 1-bit magnitude) + if (result.size() <= 2) break; + // only trim if it doesn't change the sign and therefore the value + if (result[0] != result[1]) break; + result.erase(0,1); + } + // pad to a multiple of 4 characters + while (result.size() % 4 != 0) + result.insert((std::string::size_type)0, 1, result[0]); + // now convert to hex + std::string hex_result; + for (unsigned i = 0; i < result.size()/4; i++) + { + // yuck - ugly or what? + if (result[i*4] == '0') + { + if (result[i*4+1] == '0') + { + if (result[i*4+2] == '0') + { + if (result[i*4+3] == '0') + hex_result += '0'; + else + hex_result += '1'; + } + else + { + if (result[i*4+3] == '0') + hex_result += '2'; + else + hex_result += '3'; + } + } + else + { + if (result[i*4+2] == '0') + { + if (result[i*4+3] == '0') + hex_result += '4'; + else + hex_result += '5'; + } + else + { + if (result[i*4+3] == '0') + hex_result += '6'; + else + hex_result += '7'; + } + } + } + else + { + if (result[i*4+1] == '0') + { + if (result[i*4+2] == '0') + { + if (result[i*4+3] == '0') + hex_result += '8'; + else + hex_result += '9'; + } + else + { + if (result[i*4+3] == '0') + hex_result += 'a'; + else + hex_result += 'b'; + } + } + else + { + if (result[i*4+2] == '0') + { + if (result[i*4+3] == '0') + hex_result += 'c'; + else + hex_result += 'd'; + } + else + { + if (result[i*4+3] == '0') + hex_result += 'e'; + else + hex_result += 'f'; + } + } + } + } + result = hex_result; + // add the prefix + result.insert((std::string::size_type)0, "0x"); + } + } + else + { + // convert to sign-magnitude + // the representation is: + // [sign]magnitude + bool negative = local_i.negative(); + local_i.abs(); + // create a representation of the magnitude by successive division + inf inf_radix(radix); + do + { + std::pair divided = local_i.divide(inf_radix); + unsigned remainder = divided.second.to_unsigned(); + char digit = to_char[remainder]; + result.insert((std::string::size_type)0, 1, digit); + local_i = divided.first; + } + while(!local_i.zero()); + // add the prefixes + // add a sign only for negative values + if (negative) + result.insert((std::string::size_type)0, 1, '-'); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Conversions FROM string + + void convert_from_string(const std::string& str, inf& result, unsigned radix = 10) throw(std::invalid_argument) + { + result = 0; + // only support the C-style radixes plus 0b for binary + // a radix of 0 means deduce the radix from the input - assume 10 + if (radix != 0 && radix != 2 && radix != 8 && radix != 10 && radix != 16) + throw std::invalid_argument("invalid radix value"); + unsigned i = 0; + // the radix passed as a parameter is just the default - it can be + // overridden by the C prefix + // Note: a leading zero is the C-style prefix for octal - I only make this + // override the default when the default radix is not specified + // first check for a C-style prefix + bool c_style = false; + if (i < str.size() && str[i] == '0') + { + // binary or hex + if (i+1 < str.size() && tolower(str[i+1]) == 'x') + { + c_style = true; + radix = 16; + i += 2; + } + else if (i+1 < str.size() && tolower(str[i+1]) == 'b') + { + c_style = true; + radix = 2; + i += 2; + } + else if (radix == 0) + { + c_style = true; + radix = 8; + i += 1; + } + } + if (radix == 0) + radix = 10; + if (c_style) + { + // the C style formats are bit patterns not integer values - these need + // to be sign-extended to get the right value + std::string binary; + if (radix == 2) + { + for (unsigned j = i; j < str.size(); j++) + { + switch(str[j]) + { + case '0': + binary += '0'; + break; + case '1': + binary += '1'; + break; + default: + throw std::invalid_argument("invalid binary character in string " + str); + } + } + } + else if (radix == 8) + { + for (unsigned j = i; j < str.size(); j++) + { + switch(str[j]) + { + case '0': + binary += "000"; + break; + case '1': + binary += "001"; + break; + case '2': + binary += "010"; + break; + case '3': + binary += "011"; + break; + case '4': + binary += "100"; + break; + case '5': + binary += "101"; + break; + case '6': + binary += "110"; + break; + case '7': + binary += "111"; + break; + default: + throw std::invalid_argument("invalid octal character in string " + str); + } + } + } + else + { + for (unsigned j = i; j < str.size(); j++) + { + switch(tolower(str[j])) + { + case '0': + binary += "0000"; + break; + case '1': + binary += "0001"; + break; + case '2': + binary += "0010"; + break; + case '3': + binary += "0011"; + break; + case '4': + binary += "0100"; + break; + case '5': + binary += "0101"; + break; + case '6': + binary += "0110"; + break; + case '7': + binary += "0111"; + break; + case '8': + binary += "1000"; + break; + case '9': + binary += "1001"; + break; + case 'a': + binary += "1010"; + break; + case 'b': + binary += "1011"; + break; + case 'c': + binary += "1100"; + break; + case 'd': + binary += "1101"; + break; + case 'e': + binary += "1110"; + break; + case 'f': + binary += "1111"; + break; + default: + throw std::invalid_argument("invalid hex character in string " + str); + } + } + } + // now convert the value + result.resize(binary.size()); + for (unsigned j = 0; j < binary.size(); j++) + result.preset(binary.size() - j - 1, binary[j] == '1'); + } + else + { + // sign-magnitude representation + // now scan for a sign and find whether this is a negative number + bool negative = false; + if (i < str.size()) + { + switch (str[i]) + { + case '-': + negative = true; + i++; + break; + case '+': + i++; + break; + } + } + for (; i < str.size(); i++) + { + result *= inf(radix); + unsigned char ascii = (unsigned char)str[i]; + int ch = from_char[ascii] ; + if (ch == -1) + throw std::invalid_argument("invalid decimal character in string " + str); + result += inf(ch); + } + if (negative) + result.negate(); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // constructors - mostly implemented in terms of the assignment operators + + inf::inf(void) + { + // void constructor initialises to zero - represented as a single-byte value containing zero + m_data.append(1,std::string::value_type(0)); + } + + inf::inf(short r) + { + operator=(r); + } + + inf::inf(unsigned short r) + { + operator=(r); + } + + inf::inf(int r) + { + operator=(r); + } + + inf::inf(unsigned r) + { + operator=(r); + } + + inf::inf(long r) + { + operator=(r); + } + + inf::inf(unsigned long r) + { + operator=(r); + } + + inf::inf (const std::string& r) throw(std::invalid_argument) + { + operator=(r); + } + + inf::inf(const inf& r) + { +#ifdef __BORLANDC__ + // work round bug in Borland compiler - copy constructor fails if string + // contains null characters, so do my own copy + for (unsigned i = 0; i < r.m_data.size(); i++) + m_data += r.m_data[i]; +#else + m_data = r.m_data; +#endif + } + + //////////////////////////////////////////////////////////////////////////////// + + inf::~inf(void) + { + } + + //////////////////////////////////////////////////////////////////////////////// + // assignments convert from iteger types to internal representation + + inf& inf::operator = (short r) + { + convert_from_signed(r, m_data); + return *this; + } + + inf& inf::operator = (unsigned short r) + { + convert_from_unsigned(r, m_data); + return *this; + } + + inf& inf::operator = (int r) + { + convert_from_signed(r, m_data); + return *this; + } + + inf& inf::operator = (unsigned r) + { + convert_from_unsigned(r, m_data); + return *this; + } + + inf& inf::operator = (long r) + { + convert_from_signed(r, m_data); + return *this; + } + + inf& inf::operator = (unsigned long r) + { + convert_from_unsigned(r, m_data); + return *this; + } + + inf& inf::operator = (const std::string& r) throw(std::invalid_argument) + { + convert_from_string(r, *this); + return *this; + } + + inf& inf::operator = (const inf& r) + { + m_data = r.m_data; + return *this; + } + + //////////////////////////////////////////////////////////////////////////////// + + short inf::to_short(bool truncate) const throw(std::overflow_error) + { + short result = 0; + if (!convert_to_signed(m_data, result)) + if (!truncate) + throw std::overflow_error("stlplus::inf::to_short"); + return result; + } + + unsigned short inf::to_unsigned_short(bool truncate) const throw(std::overflow_error) + { + unsigned short result = 0; + if (!convert_to_unsigned(m_data, result)) + if (!truncate) + throw std::overflow_error("stlplus::inf::to_unsigned_short"); + return result; + } + + int inf::to_int(bool truncate) const throw(std::overflow_error) + { + int result = 0; + if (!convert_to_signed(m_data, result)) + if (!truncate) + throw std::overflow_error("stlplus::inf::to_int"); + return result; + } + + unsigned inf::to_unsigned(bool truncate) const throw(std::overflow_error) + { + unsigned result = 0; + if (!convert_to_unsigned(m_data, result)) + if (!truncate) + throw std::overflow_error("stlplus::inf::to_unsigned"); + return result; + } + + long inf::to_long(bool truncate) const throw(std::overflow_error) + { + long result = 0; + if (!convert_to_signed(m_data, result)) + if (!truncate) + throw std::overflow_error("stlplus::inf::to_long"); + return result; + } + + unsigned long inf::to_unsigned_long(bool truncate) const throw(std::overflow_error) + { + unsigned long result = 0; + if (!convert_to_unsigned(m_data, result)) + if (!truncate) + throw std::overflow_error("stlplus::inf::to_unsigned_long"); + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // resize the inf regardless of the data + + void inf::resize(unsigned bits) + { + if (bits == 0) bits = 1; + unsigned bytes = (bits+7)/8; + byte extend = negative() ? byte(255) : byte (0); + while(bytes > m_data.size()) + m_data.append(1,extend); + } + + // reduce the bit count to the minimum needed to preserve the value + + void inf::reduce(void) + { + reduce_string(m_data); + } + + //////////////////////////////////////////////////////////////////////////////// + // the number of significant bits in the number + + unsigned inf::bits (void) const + { + // The number of significant bits in the integer value - this is the number + // of indexable bits less any redundant sign bits at the msb + // This does not assume that the inf has been reduced to its minimum form + unsigned result = indexable_bits(); + bool sign = bit(result-1); + while (result > 1 && (sign == bit(result-2))) + result--; + return result; + } + + unsigned inf::size(void) const + { + return bits(); + } + + unsigned inf::indexable_bits (void) const + { + return 8 * unsigned(m_data.size()); + } + + //////////////////////////////////////////////////////////////////////////////// + // bitwise operations + + bool inf::bit (unsigned index) const throw(std::out_of_range) + { + if (index >= indexable_bits()) + throw std::out_of_range(std::string("stlplus::inf::bit")); + // first split the offset into byte offset and bit offset + unsigned byte_offset = index/8; + unsigned bit_offset = index%8; + return (byte(m_data[byte_offset]) & (byte(1) << bit_offset)) != 0; + } + + bool inf::operator [] (unsigned index) const throw(std::out_of_range) + { + return bit(index); + } + + void inf::set (unsigned index) throw(std::out_of_range) + { + if (index >= indexable_bits()) + throw std::out_of_range(std::string("stlplus::inf::set")); + // first split the offset into byte offset and bit offset + unsigned byte_offset = index/8; + unsigned bit_offset = index%8; + m_data[byte_offset] |= (byte(1) << bit_offset); + } + + void inf::clear (unsigned index) throw(std::out_of_range) + { + if (index >= indexable_bits()) + throw std::out_of_range(std::string("stlplus::inf::clear")); + // first split the offset into byte offset and bit offset + unsigned byte_offset = index/8; + unsigned bit_offset = index%8; + m_data[byte_offset] &= (~(byte(1) << bit_offset)); + } + + void inf::preset (unsigned index, bool value) throw(std::out_of_range) + { + if (value) + set(index); + else + clear(index); + } + + inf inf::slice(unsigned low, unsigned high) const throw(std::out_of_range) + { + if (low >= indexable_bits()) + throw std::out_of_range(std::string("stlplus::inf::slice: low index")); + if (high >= indexable_bits()) + throw std::out_of_range(std::string("stlplus::inf::slice: high index")); + inf result; + if (high >= low) + { + // create a result the right size and filled with sign bits + std::string::size_type result_size = (high-low+1+7)/8; + result.m_data.erase(); + byte extend = bit(high) ? byte(255) : byte (0); + while (result.m_data.size() < result_size) + result.m_data.append(1,extend); + // now set the relevant bits + for (unsigned i = low; i <= high; i++) + result.preset(i-low, bit(i)); + } + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // testing operations + + bool inf::negative (void) const + { + return bit(indexable_bits()-1); + } + + bool inf::natural (void) const + { + return !negative(); + } + + bool inf::positive (void) const + { + return natural() && !zero(); + } + + bool inf::zero (void) const + { + for (std::string::size_type i = 0; i < m_data.size(); i++) + if (m_data[i] != 0) + return false; + return true; + } + + bool inf::non_zero (void) const + { + return !zero(); + } + + bool inf::operator ! (void) const + { + return zero(); + } + + //////////////////////////////////////////////////////////////////////////////// + // comparison operators + + bool inf::operator == (const inf& r) const + { + // Two infs are equal if they are numerically equal, even if they are + // different sizes (i.e. they could be non-reduced values). + // This makes life a little more complicated than if I could assume that values were reduced. + byte l_extend = negative() ? byte(255) : byte (0); + byte r_extend = r.negative() ? byte(255) : byte (0); + std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); + for (std::string::size_type i = bytes; i--; ) + { + byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); + byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); + if (l_byte != r_byte) + return false; + } + return true; + } + + bool inf::operator != (const inf& r) const + { + return !operator==(r); + } + + bool inf::operator < (const inf& r) const + { + // This could be implemented in terms of subtraction. However, it can be + // simplified since there is no need to calculate the accurate difference, + // just the direction of the difference. I compare from msB down and as + // soon as a byte difference is found, that defines the ordering. The + // problem is that in 2's-complement, all negative values are greater than + // all natural values if you just do a straight unsigned comparison. I + // handle this by doing a preliminary test for different signs. + + // For example, a 3-bit signed type has the coding: + // 000 = 0 + // ... + // 011 = 3 + // 100 = -4 + // ... + // 111 = -1 + + // So, for natural values, the ordering of the integer values is the + // ordering of the bit patterns. Similarly, for negative values, the + // ordering of the integer values is the ordering of the bit patterns + // However, the bit patterns for the negative values are *greater than* + // the natural values. This is a side-effect of the naffness of + // 2's-complement representation + + // first handle the case of comparing two values with different signs + bool l_sign = negative(); + bool r_sign = r.negative(); + if (l_sign != r_sign) + { + // one argument must be negative and the other natural + // the left is less if it is the negative one + return l_sign; + } + // the arguments are the same sign + // so the ordering is a simple unsigned byte-by-byte comparison + // However, this is complicated by the possibility that the values could be different lengths + byte l_extend = l_sign ? byte(255) : byte (0); + byte r_extend = r_sign ? byte(255) : byte (0); + std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); + for (std::string::size_type i = bytes; i--; ) + { + byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); + byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); + if (l_byte != r_byte) + return l_byte < r_byte; + } + // if I get here, the two are equal, so that is not less-than + return false; + } + + bool inf::operator <= (const inf& r) const + { + return !(r < *this); + } + + bool inf::operator > (const inf& r) const + { + return r < *this; + } + + bool inf::operator >= (const inf& r) const + { + return !(*this < r); + } + + //////////////////////////////////////////////////////////////////////////////// + // logical operators + + inf& inf::invert (void) + { + for (std::string::size_type i = 0; i < m_data.size(); i++) + m_data[i] = ~m_data[i]; + return *this; + } + + inf inf::operator ~ (void) const + { + inf result(*this); + result.invert(); + return result; + } + + inf& inf::operator &= (const inf& r) + { + // bitwise AND is extended to the length of the largest argument + byte l_extend = negative() ? byte(255) : byte (0); + byte r_extend = r.negative() ? byte(255) : byte (0); + std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); + for (std::string::size_type i = 0; i < bytes; i++) + { + byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); + byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); + byte result = l_byte & r_byte; + if (i < m_data.size()) + m_data[i] = result; + else + m_data.append(1,result); + } + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator & (const inf& r) const + { + inf result(*this); + result &= r; + return result; + } + + inf& inf::operator |= (const inf& r) + { + // bitwise OR is extended to the length of the largest argument + byte l_extend = negative() ? byte(255) : byte (0); + byte r_extend = r.negative() ? byte(255) : byte (0); + std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); + for (std::string::size_type i = 0; i < bytes; i++) + { + byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); + byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); + byte result = l_byte | r_byte; + if (i < m_data.size()) + m_data[i] = result; + else + m_data.append(1,result); + } + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator | (const inf& r) const + { + inf result(*this); + result |= r; + return result; + } + + inf& inf::operator ^= (const inf& r) + { + // bitwise XOR is extended to the length of the largest argument + byte l_extend = negative() ? byte(255) : byte (0); + byte r_extend = r.negative() ? byte(255) : byte (0); + std::string::size_type bytes = maximum(m_data.size(),r.m_data.size()); + for (std::string::size_type i = 0; i < bytes; i++) + { + byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); + byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); + byte result = l_byte ^ r_byte; + if (i < m_data.size()) + m_data[i] = result; + else + m_data.append(1,result); + } + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator ^ (const inf& r) const + { + inf result(*this); + result ^= r; + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // shift operators all preserve the value by increasing the word size + + inf& inf::operator <<= (unsigned shift) + { + // left shift is a shift towards the msb, with 0s being shifted in at the lsb + // split this into a byte shift followed by a bit shift + + // first expand the value to be big enough for the result + std::string::size_type new_size = (indexable_bits() + shift + 7) / 8; + byte extend = negative() ? byte(255) : byte (0); + while (m_data.size() < new_size) + m_data.append(1,extend); + // now do the byte shift + unsigned byte_shift = shift/8; + if (byte_shift > 0) + { + for (std::string::size_type b = new_size; b--; ) + m_data[b] = (b >= byte_shift) ? m_data[b-byte_shift] : byte(0); + } + // and finally the bit shift + unsigned bit_shift = shift%8; + if (bit_shift > 0) + { + for (std::string::size_type b = new_size; b--; ) + { + byte current = byte(m_data[b]); + byte previous = b > 0 ? m_data[b-1] : byte(0); + m_data[b] = (current << bit_shift) | (previous >> (8 - bit_shift)); + } + } + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator << (unsigned shift) const + { + inf result(*this); + result <<= shift; + return result; + } + + inf& inf::operator >>= (unsigned shift) + { + // right shift is a shift towards the lsb, with sign bits being shifted in at the msb + // split this into a byte shift followed by a bit shift + + // a byte of sign bits + byte extend = negative() ? byte(255) : byte (0); + // do the byte shift + unsigned byte_shift = shift/8; + if (byte_shift > 0) + { + for (std::string::size_type b = 0; b < m_data.size(); b++) + m_data[b] = (b + byte_shift < m_data.size()) ? m_data[b+byte_shift] : extend; + } + // and finally the bit shift + unsigned bit_shift = shift%8; + if (bit_shift > 0) + { + for (std::string::size_type b = 0; b < m_data.size(); b++) + { + byte current = byte(m_data[b]); + byte next = ((b+1) < m_data.size()) ? m_data[b+1] : extend; + byte shifted = (current >> bit_shift) | (next << (8 - bit_shift)); + m_data[b] = shifted; + } + } + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator >> (unsigned shift) const + { + inf result(*this); + result >>= shift; + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // negation operators + + inf& inf::negate (void) + { + // do 2's-complement negation + // equivalent to inversion plus one + invert(); + operator += (inf(1)); + return *this; + } + + inf inf::operator - (void) const + { + inf result(*this); + result.negate(); + return result; + } + + inf& inf::abs(void) + { + if (negative()) negate(); + return *this; + } + + inf abs(const inf& i) + { + inf result = i; + result.abs(); + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // addition operators + + inf& inf::operator += (const inf& r) + { + // do 2's-complement addition + // Note that the addition can give a result that is larger than either argument + byte carry = 0; + std::string::size_type max_size = maximum(m_data.size(),r.m_data.size()); + byte l_extend = negative() ? byte(255) : byte (0); + byte r_extend = r.negative() ? byte(255) : byte (0); + for (std::string::size_type i = 0; i < max_size; i++) + { + byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend); + byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend); + // calculate the addition in a type that is bigger than a byte in order to catch the carry-out + unsigned short result = ((unsigned short)(l_byte)) + ((unsigned short)(r_byte)) + carry; + // now truncate the result to get the lsB + if (i < m_data.size()) + m_data[i] = byte(result); + else + m_data.append(1,byte(result)); + // and capture the carry out by grabbing the second byte of the result + carry = byte(result >> 8); + } + // if the result overflowed or underflowed, add an extra byte to catch it + unsigned short result = ((unsigned short)(l_extend)) + ((unsigned short)(r_extend)) + carry; + if (byte(result) != (negative() ? byte(255) : byte(0))) + m_data.append(1,byte(result)); + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator + (const inf& r) const + { + inf result(*this); + result += r; + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // subtraction operators + + inf& inf::operator -= (const inf& r) + { + // subtraction is defined in terms of negation and addition + inf negated = -r; + operator += (negated); + return *this; + } + + inf inf::operator - (const inf& r) const + { + inf result(*this); + result -= r; + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // multiplication operators + + inf& inf::operator *= (const inf& r) + { + // 2's complement multiplication + // one day I'll do a more efficient version than this based on the underlying representation + inf left(*this); + inf right = r; + // make the right value natural but preserve its sign for later + bool right_negative = right.negative(); + right.abs(); + // implemented as a series of conditional additions + operator = (0); + // left.resize(right.bits() + left.bits() - 1); + left <<= right.bits()-1; + for (unsigned i = right.bits(); i--; ) + { + if (right[i]) + operator += (left); + left >>= 1; + } + if (right_negative) + negate(); + // now reduce the result + reduce(); + return *this; + } + + inf inf::operator * (const inf& r) const + { + inf result(*this); + result *= r; + return result; + } + + //////////////////////////////////////////////////////////////////////////////// + // division and remainder operators + + std::pair inf::divide(const inf& right) const throw(divide_by_zero) + { + if (right.zero()) + throw divide_by_zero("stlplus::inf::divide"); + inf numerator(*this); + inf denominator = right; + // make the numerator natural but preserve the sign for later + bool numerator_negative = numerator.negative(); + numerator.abs(); + // same with the denominator + bool denominator_negative = denominator.negative(); + denominator.abs(); + // the quotient and remainder will form the result + // start with the quotiont zero and the remainder equal to the whole of the + // numerator, then do trial subtraction from this + inf quotient; + inf remainder = numerator; + // there's nothing more to do if the numerator is smaller than the denominator + // but otherwise do the division + if (numerator.bits() >= denominator.bits()) + { + // make the quotient big enough to take the result + quotient.resize(numerator.bits()); + // start with the numerator shifted to the far left + unsigned shift = numerator.bits() - denominator.bits(); + denominator <<= shift; + // do the division by repeated subtraction, + for (unsigned i = shift+1; i--; ) + { + if (remainder >= denominator) + { + remainder -= denominator; + quotient.set(i); + } + denominator >>= 1; + } + } + // now adjust the signs + // x/(-y) == (-x)/y == -(x/y) + if (numerator_negative != denominator_negative) + quotient.negate(); + quotient.reduce(); + // x%(-y) == x%y and (-x)%y == -(x%y) + if (numerator_negative) + remainder.negate(); + remainder.reduce(); + return std::pair(quotient,remainder); + } + + inf& inf::operator /= (const inf& r) throw(divide_by_zero) + { + std::pair result = divide(r); + operator=(result.first); + return *this; + } + + inf inf::operator / (const inf& r) const throw(divide_by_zero) + { + std::pair result = divide(r); + return result.first; + } + + inf& inf::operator %= (const inf& r) throw(divide_by_zero) + { + std::pair result = divide(r); + operator=(result.second); + return *this; + } + + inf inf::operator % (const inf& r) const throw(divide_by_zero) + { + std::pair result = divide(r); + return result.second; + } + + //////////////////////////////////////////////////////////////////////////////// + // prefix (void) and postfix (int) operators + + inf& inf::operator ++ (void) + { + operator += (inf(1)); + return *this; + } + + inf inf::operator ++ (int) + { + inf old(*this); + operator += (inf(1)); + return old; + } + + inf& inf::operator -- (void) + { + operator -= (inf(1)); + return *this; + } + + inf inf::operator -- (int) + { + inf old(*this); + operator -= (inf(1)); + return old; + } + + //////////////////////////////////////////////////////////////////////////////// + // string representation and I/O routines + + std::string inf::to_string(unsigned radix) const + throw(std::invalid_argument) + { + std::string result; + convert_to_string(*this, result, radix); + return result; + } + + inf& inf::from_string(const std::string& value, unsigned radix) + throw(std::invalid_argument) + { + convert_from_string(value, *this, radix); + return *this; + } + + std::ostream& operator << (std::ostream& str, const inf& i) + { + try + { + // get radix + unsigned radix = 10; + if (str.flags() & std::ios_base::oct) + radix = 8; + if (str.flags() & std::ios_base::hex) + radix = 16; + // the field width is handled by iostream, so I don't need to handle it as well + // generate the string representation then print it + str << i.to_string(radix); + } + catch(const std::invalid_argument) + { + str.setstate(std::ios_base::badbit); + } + return str; + } + + std::istream& operator >> (std::istream& str, inf& i) + { + try + { + // get radix + unsigned radix = 10; + if (str.flags() & std::ios_base::oct) + radix = 8; + if (str.flags() & std::ios_base::hex) + radix = 16; + // now get the string image of the value + std::string image; + str >> image; + // and convert to inf + i.from_string(image, radix); + } + catch(const std::invalid_argument) + { + str.setstate(std::ios_base::badbit); + } + return str; + } + + //////////////////////////////////////////////////////////////////////////////// + // diagnostic dump + // just convert to hex + + std::string inf::image_debug(void) const + { + // create this dump in the human-readable form, i.e. msB to the left + std::string result = "0x"; + for (std::string::size_type i = m_data.size(); i--; ) + { + byte current = m_data[i]; + byte msB = (current & byte(0xf0)) >> 4; + result += to_char[msB]; + byte lsB = (current & byte(0x0f)); + result += to_char[lsB]; + } + return result; + } + + const std::string& inf::get_bytes(void) const + { + return m_data; + } + + void inf::set_bytes(const std::string& data) + { + m_data = data; + } + +} // end namespace stlplus