From 62e234c114d2b6ead93a1d39593c66b648c3d0a6 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 1 Feb 2024 15:47:37 +0300 Subject: Turn libodb-oracle repository into package for muti-package repository --- libodb-oracle/odb/oracle/details/number.cxx | 269 ++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 libodb-oracle/odb/oracle/details/number.cxx (limited to 'libodb-oracle/odb/oracle/details/number.cxx') diff --git a/libodb-oracle/odb/oracle/details/number.cxx b/libodb-oracle/odb/oracle/details/number.cxx new file mode 100644 index 0000000..aeb2b96 --- /dev/null +++ b/libodb-oracle/odb/oracle/details/number.cxx @@ -0,0 +1,269 @@ +// file : odb/oracle/details/number.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::size_t +#include + +#include + +using namespace std; + +namespace odb +{ + namespace oracle + { + namespace details + { + // The NUMBER type's binary representation is made up of the following + // bit fields, ordered in increasing memory address. + // + // 000 to 007: 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. + // + // 008 to 167: The mantissa bits. Each byte of this field represents a + // single base-100 value. + // + // + + long long + number_to_int64 (const char* b, size_t n) + { + // All bytes in the buffer are interpreted as unsigned. + // + const unsigned char* ub (reinterpret_cast (b)); + + // Zero is represented by zero significant bits and an exponent + // set to 128. + // + if (n == 1) + { + assert (ub[0] == 128); + return 0; + } + + long long v (0); + + // Test the sign bit of the exponent. + // + if ((ub[0] & 0x80) != 0) + { + // The unbiased exponent of a positive number may be calculated as + // ub[0 - 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 (ub[0] - 193); i < o; ++i) + w *= 100; + + // Accumlate the sum of the significant base-100 terms. + // + for (const unsigned char* m (ub + 1), *e (ub + n); m < e; ++m) + { + v += (*m - 1) * w; + w /= 100; + } + } + else + { + // The unbiased exponent of a negative number is calculated as + // (~ub[0] & 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 ((~ub[0] & 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 (ub + 1), *e (ub + n - 1); m < e; ++m) + { + v -= (101 - *m) * w; + w /= 100; + } + } + + return v; + } + + void + int64_to_number (char* b, size_t& n, long long v) + { + // We assume that b is long enough to contain a long long NUMBER + // representation, that being 12 bytes. + // + + // All bytes in the buffer are interpreted as unsigned. + // + unsigned char* ub (reinterpret_cast (b)); + + if (v == 0) + { + ub[0] = 128; + n = 1; + + return; + } + + bool sig (false); + unsigned char t[11], *m (t); + n = 0; + + 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. + // + ub[0] = 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. + // + ub[0] = static_cast (n + 192); + } + + // Set the length. + // + n = static_cast (m - t + 1); + + // Set the significant digits in big-endian byte order and the + // terminator, if any. + // + for (size_t i (1); m > t; ++i) + ub[i] = *--m; + } + + unsigned long long + number_to_uint64 (const char* b, size_t n) + { + // All bytes in the buffer are interpreted as unsigned. + // + const unsigned char* ub (reinterpret_cast (b)); + + // Zero is represented by zero significant bits and an exponent + // set to 128. + // + if (n == 1) + { + assert (ub[0] == 128); + return 0; + } + + unsigned long long v (0); + + // Test the sign bit of the exponent. + // + if ((ub[0] & 0x80) == 0) + { + assert (false); + return 0; + } + + // The unbiased exponent of a positive number may be calculated as + // ub[0] - 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 (ub[0] - 193); i < o; ++i) + w *= 100; + + // Accumlate the sum of the significant base-100 terms. + // + for (const unsigned char* m (ub + 1), *e (ub + n); m < e; ++m) + { + v += (*m - 1) * w; + w /= 100; + } + + return v; + } + + void + uint64_to_number (char* b, size_t& n, unsigned long long v) + { + // We assume that b is long enough to contain an unsigned long long + // NUMBER representation, that being 12 bytes. + // + + // All bytes in the buffer are interpreted as unsigned. + // + unsigned char* ub (reinterpret_cast (b)); + + if (v == 0) + { + ub[0] = 128; + n = 1; + + return; + } + + bool sig (false); + unsigned char t[11], *m (t); + n = 0; + + 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. + // + ub[0] = static_cast (n + 192); + + // Set the length. + // + n = static_cast (m - t + 1); + + // Set the significant digits in big-endian byte order. + // + for (size_t i (1); m > t; ++i) + ub[i] = *--m; + } + } + } +} -- cgit v1.1