aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-09-26 08:36:55 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-09-26 11:04:09 +0200
commit927b42789bd3c3f108867bf067a89013a932cab3 (patch)
treebcd30812c3716aeb0fb91a8afe1208bd3f37dd15
parent385a45a47fdb47a890178b7b4604a37fc214a10e (diff)
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.
-rw-r--r--odb/oracle/details/number.cxx264
-rw-r--r--odb/oracle/details/number.hxx35
-rw-r--r--odb/oracle/makefile3
-rw-r--r--odb/oracle/traits.cxx135
4 files changed, 301 insertions, 136 deletions
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 <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstddef> // std::size_t
+#include <cassert>
+
+#include <odb/oracle/details/number.hxx>
+
+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<int> (v % 100));
+ sig = sig || r != 0;
+
+ if (sig)
+ *m++ = static_cast<unsigned char> (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<unsigned char> (~(n + 192));
+ }
+ else
+ {
+ while (v != 0)
+ {
+ int r (static_cast<int> (v % 100));
+ sig = sig || r != 0;
+
+ if (sig)
+ *m++ = static_cast<unsigned char> (r + 1);
+
+ v /= 100;
+ ++n;
+ }
+
+ // Exponent is one less than the number of base 100 digits.
+ //
+ b[1] = static_cast<unsigned char> (n + 192);
+ }
+
+ // Set the length.
+ //
+ b[0] = static_cast<unsigned char> (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<int> (v % 100));
+ sig = sig || r != 0;
+
+ if (sig)
+ *m++ = static_cast<unsigned char> (r + 1);
+
+ v /= 100;
+ ++n;
+ }
+
+ // Exponent is one less than the number of base 100 digits.
+ //
+ b[1] = static_cast<unsigned char> (n + 192);
+
+ // Set the length.
+ //
+ b[0] = static_cast<unsigned char> (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 <constantin@codesynthesis.com>
+// 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 <odb/pre.hxx>
+#include <odb/oracle/details/export.hxx>
+
+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 <odb/post.hxx>
+
+#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 <cstddef> // std::size_t
-#include <cmath> // pow
-#include <deque>
-
#include <odb/oracle/traits.hxx>
-
-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<unsigned char> 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<int> (n % 100));
- sig = sig ? true : v != 0;
-
- if (sig)
- s.push_front (static_cast<unsigned char> (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<unsigned char> (~(c + 192));
- }
- else
- {
- while (n != 0)
- {
- int v (static_cast<int> (n % 100));
- sig = sig ? true : v != 0;
-
- if (sig)
- s.push_front (static_cast<unsigned char> (v + 1));
-
- n /= 100;
- ++c;
- }
-
- // Exponent is one less than the number of base 100 digits.
- //
- exp = static_cast<unsigned char> (c + 192);
- }
-
- // Set the length.
- //
- b[0] = static_cast<unsigned char> (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;
- }
- }
- }
-}