From 927b42789bd3c3f108867bf067a89013a932cab3 Mon Sep 17 00:00:00 2001 From: Constantin Michael Date: Mon, 26 Sep 2011 08:36:55 +0200 Subject: Reimplement Oracle NUMBER to/from C++ integer type conversions The implementation has been moved to the details namespace. Signed and unsigned 32 bit versions, as well as an unsigned 64 bit version have also been added. --- odb/oracle/details/number.cxx | 264 ++++++++++++++++++++++++++++++++++++++++++ odb/oracle/details/number.hxx | 35 ++++++ odb/oracle/makefile | 3 +- odb/oracle/traits.cxx | 135 --------------------- 4 files changed, 301 insertions(+), 136 deletions(-) create mode 100644 odb/oracle/details/number.cxx create mode 100644 odb/oracle/details/number.hxx diff --git a/odb/oracle/details/number.cxx b/odb/oracle/details/number.cxx new file mode 100644 index 0000000..bf7902a --- /dev/null +++ b/odb/oracle/details/number.cxx @@ -0,0 +1,264 @@ +// file : odb/oracle/details/number.cxx +// author : Constantin Michael +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::size_t +#include + +#include + +using namespace std; + +namespace odb +{ + namespace oracle + { + namespace details + { + // The VARNUM type's binary representation is made up of the following + // bit fields, ordered in increasing memory address. + // + // 000 to 007: The size of the binary representation, including the + // exponent bits and the mantissa bits, but excluding these + // length bits. + // + // 008 to 015: The base-100 exponent bits. The most significant bit is + // the sign bit of the number, which is set for positive + // numbers and cleared for negative numbers. For positive + // numbers, the exponent has a bias of 65 added to it. + // + // 016 to 175: The mantissa bits. Each byte of this field represents a + // single base-100 value. + // + // + + long long + number_to_int64 (const unsigned char* b) + { + int n (b[0]); + + // Zero is represented by zero significant bits and an exponent + // set to 128. + // + if (n == 1) + { + assert (b[1] == 128); + return 0; + } + + long long v (0); + + // Test the sign bit of the exponent. + // + if (b[1] & 0x80) + { + + // The unbiased exponent of a positive number may be calculated as + // b[1] - 128 - 65. For an integer, this is the order of magnitude + // of the number. Calculate the maximum weight, 100 ^ o, where o is + // the order of magnitude of the number. + // + long long w (1); + + for (size_t i (0), o (b[1] - 193); i < o; ++i) + w *= 100; + + // Accumlate the sum of the significant base-100 terms. + // + for (const unsigned char* m (b + 2), *e (b + 1 + n); m < e; ++m) + { + v += (*m - 1) * w; + w /= 100; + } + } + else + { + // The unbiased exponent of a negative number is calculated as + // (~b[1] & 0x7F) - 193. For an integer, this is the order of + // magnitude of the number. Calculate the maximum weight, 100 ^ o, + // where o is the order of magnitude of the number. + // + long long w (1); + + for (size_t i (0), o ((~b[1] & 0x7F) - 65); i < o; ++i) + w *= 100; + + // Accumulate the sum of the significant base-100 terms. Note that + // negative values will have a terminator byte which is included + // in the length. This is ignored. + // + for (const unsigned char* m (b + 2), *e (b + n); m < e; ++m) + { + v -= (101 - *m) * w; + w /= 100; + } + } + + return v; + } + + void + int64_to_number (unsigned char* b, long long v) + { + // We assume that b is long enough to contain a long long VARNUM + // representation, that being 12 bytes. + // + + if (v == 0) + { + b[0] = 1; + b[1] = 128; + + return; + } + + bool sig (false); + size_t n (0); + unsigned char t[11], *m (t); + + if (v < 0) + { + // Termination marker for negative numbers. + // + *m++ = 102; + + while (v != 0) + { + int r (static_cast (v % 100)); + sig = sig || r != 0; + + if (sig) + *m++ = static_cast (101 + r); + + v /= 100; + ++n; + } + + // The exponent is one less than the number of base 100 digits. It is + // inverted for negative values. + // + b[1] = static_cast (~(n + 192)); + } + else + { + while (v != 0) + { + int r (static_cast (v % 100)); + sig = sig || r != 0; + + if (sig) + *m++ = static_cast (r + 1); + + v /= 100; + ++n; + } + + // Exponent is one less than the number of base 100 digits. + // + b[1] = static_cast (n + 192); + } + + // Set the length. + // + b[0] = static_cast (m - t + 1); + + // Set the significant digits in big-endian byte order and the + // terminator, if any. + // + for (size_t i (2); m > t; ++i) + b[i] = *--m; + } + + unsigned long long + number_to_uint64 (const unsigned char* b) + { + int n (b[0]); + + // Zero is represented by zero significant bits and an exponent + // set to 128. + // + if (n == 1) + { + assert (b[1] == 128); + return 0; + } + + unsigned long long v (0); + + // Test the sign bit of the exponent. + // + if (b[1] & 0x80) + { + assert (false); + return 0; + } + + // The unbiased exponent of a positive number may be calculated as + // b[1] - 128 - 65. For an integer, this is the order of magnitude + // of the number. Calculate the maximum weight, 100 ^ o, where o is + // the order of magnitude of the number. + // + unsigned long long w (1); + + for (size_t i (0), o (b[1] - 193); i < o; ++i) + w *= 100; + + // Accumlate the sum of the significant base-100 terms. + // + for (const unsigned char* m (b + 2), *e (b + 1 + n); m < e; ++m) + { + v += (*m - 1) * w; + w /= 100; + } + + return v; + } + + void + uint64_to_number (unsigned char* b, unsigned long long v) + { + // We assume that b is long enough to contain an unsigned long long + // VARNUM representation, that being 12 bytes. + // + + if (v == 0) + { + b[0] = 1; + b[1] = 128; + + return; + } + + bool sig (false); + size_t n (0); + unsigned char t[11], *m (t); + + while (v != 0) + { + int r (static_cast (v % 100)); + sig = sig || r != 0; + + if (sig) + *m++ = static_cast (r + 1); + + v /= 100; + ++n; + } + + // Exponent is one less than the number of base 100 digits. + // + b[1] = static_cast (n + 192); + + // Set the length. + // + b[0] = static_cast (m - t + 1); + + // Set the significant digits in big-endian byte order. + // + for (size_t i (2); m > t; ++i) + b[i] = *--m; + } + } + } +} diff --git a/odb/oracle/details/number.hxx b/odb/oracle/details/number.hxx new file mode 100644 index 0000000..4f49643 --- /dev/null +++ b/odb/oracle/details/number.hxx @@ -0,0 +1,35 @@ +// file : odb/oracle/details/number.hxx +// author : Constantin Michael +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_ORACLE_NUMBER_HXX +#define ODB_ORACLE_NUMBER_HXX + +#include +#include + +namespace odb +{ + namespace oracle + { + namespace details + { + LIBODB_ORACLE_EXPORT long long + number_to_int64 (const unsigned char* buffer); + + LIBODB_ORACLE_EXPORT void + int64_to_number (unsigned char* buffer, long long value); + + LIBODB_ORACLE_EXPORT unsigned long long + number_to_uint64 (const unsigned char* buffer); + + LIBODB_ORACLE_EXPORT void + uint64_to_number (unsigned char* buffer, unsigned long long value); + } + } +} + +#include + +#endif // ODB_ORACLE_NUMBER_HXX diff --git a/odb/oracle/makefile b/odb/oracle/makefile index cfa42ae..0725800 100644 --- a/odb/oracle/makefile +++ b/odb/oracle/makefile @@ -17,7 +17,8 @@ object-statements.cxx \ statement.cxx \ statements-base.cxx \ transaction.cxx \ -transaction-impl.cxx +transaction-impl.cxx \ +details/number.cxx cli_tun := details/options.cli cxx_tun := $(cxx) diff --git a/odb/oracle/traits.cxx b/odb/oracle/traits.cxx index 4bae42d..3e95a00 100644 --- a/odb/oracle/traits.cxx +++ b/odb/oracle/traits.cxx @@ -3,139 +3,4 @@ // copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include // std::size_t -#include // pow -#include - #include - -using namespace std; - -namespace odb -{ - namespace oracle - { - long long - out (unsigned char const* n) - { - // The first byte specifies the length of the number representation, - // including the exponent byte and significant digits but not the length - // itself. - // - int len (n[0]); - - if (len == 1) - return 0; - - long long v (0); - if (n[1] & 0x80) - { - // The exponent of a positive number is calculated as n[1] - 193. - // The base-100 exponent of the least significant digit can be - // calculated as exp - sig - 1, where sig is the number of significant - // digits. sig may be calculated as len - 2. - // - int exp (n[1] - 191 - len); - - for (unsigned char const* m (n + len), *e (n + 1); m > e; --m, ++exp) - v += (*m - 1) * pow (100, exp); - } - else - { - // The exponent of a negative number is calculated as ~n[1] - 193. - // The base-100 exponent of the least significant digit can be - // calculated as exp - sig - 1, where sig is the number of significant - // digits. sig may be calculated as len - 2. - // - int exp (~n[1] - 190 - len); - - for (unsigned char const* m (n + len - 1), *e (n + 1); m > e; - --m, ++exp) - v -= (101 - *m) * pow (100, exp); - } - - return v; - } - - void - in (unsigned char b[22], long long n) - { - if (n == 0) - { - b[0] = 1; - b[1] = 128; - - return; - } - - // @@ Is there some sort of reserve() implementation for deque? - // - deque s; - - bool sig (false); - size_t c (0); - unsigned char exp (0); - - if (n < 0) - { - // Termination marker for negative numbers. - // - s.push_front (102); - - while (n != 0) - { - int v (static_cast (n % 100)); - sig = sig ? true : v != 0; - - if (sig) - s.push_front (static_cast (101 + v)); - - n /= 100; - ++c; - } - - // The exponent is one less than the number of base 100 digits. It is - // inverted for negative values. - // - exp = static_cast (~(c + 192)); - } - else - { - while (n != 0) - { - int v (static_cast (n % 100)); - sig = sig ? true : v != 0; - - if (sig) - s.push_front (static_cast (v + 1)); - - n /= 100; - ++c; - } - - // Exponent is one less than the number of base 100 digits. - // - exp = static_cast (c + 192); - } - - // Set the length. - // - b[0] = static_cast (s.size () + 1); - - // Set the exponent. - // - b[1] = exp; - - // Set the significant digits (big-endian byte order) and the terminator, - // if any. - // - c = 2; - while (!s.empty ()) - { - b[i] = s.front (); - s.pop_front (); - ++c; - } - } - } -} -- cgit v1.1