UIntegerFP32.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.09.11
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <Mathematics/UIntegerALU32.h>
  10. #include <array>
  11. #include <istream>
  12. #include <ostream>
  13. // Class UIntegerFP32 is designed to support fixed precision arithmetic
  14. // using BSNumber and BSRational. It is not a general-purpose class for
  15. // arithmetic of unsigned integers. The template parameter N is the
  16. // number of 32-bit words required to store the precision for the desired
  17. // computations (maximum number of bits is 32*N).
  18. // Uncomment this to trap when an attempt is made to create storage with
  19. // more than N uint32_t items.
  20. //
  21. //#define GTE_THROW_ON_UINTEGERFP32_OUT_OF_RANGE
  22. namespace WwiseGTE
  23. {
  24. template <int N>
  25. class UIntegerFP32 : public UIntegerALU32<UIntegerFP32<N>>
  26. {
  27. public:
  28. // Construction.
  29. UIntegerFP32()
  30. :
  31. mNumBits(0),
  32. mSize(0)
  33. {
  34. static_assert(N >= 1, "Invalid size N.");
  35. }
  36. UIntegerFP32(UIntegerFP32 const& number)
  37. {
  38. static_assert(N >= 1, "Invalid size N.");
  39. *this = number;
  40. }
  41. UIntegerFP32(uint32_t number)
  42. {
  43. static_assert(N >= 1, "Invalid size N.");
  44. if (number > 0)
  45. {
  46. int32_t first = BitHacks::GetLeadingBit(number);
  47. int32_t last = BitHacks::GetTrailingBit(number);
  48. mNumBits = first - last + 1;
  49. mSize = 1;
  50. mBits[0] = (number >> last);
  51. }
  52. else
  53. {
  54. mNumBits = 0;
  55. mSize = 0;
  56. }
  57. }
  58. UIntegerFP32(uint64_t number)
  59. {
  60. static_assert(N >= 2, "N not large enough to store 64-bit integers.");
  61. if (number > 0)
  62. {
  63. int32_t first = BitHacks::GetLeadingBit(number);
  64. int32_t last = BitHacks::GetTrailingBit(number);
  65. number >>= last;
  66. mNumBits = first - last + 1;
  67. mSize = 1 + (mNumBits - 1) / 32;
  68. mBits[0] = (uint32_t)(number & 0x00000000FFFFFFFFull);
  69. if (mSize > 1)
  70. {
  71. mBits[1] = (uint32_t)((number >> 32) & 0x00000000FFFFFFFFull);
  72. }
  73. }
  74. else
  75. {
  76. mNumBits = 0;
  77. mSize = 0;
  78. }
  79. }
  80. // Assignment. Only mSize elements are copied.
  81. UIntegerFP32& operator=(UIntegerFP32 const& number)
  82. {
  83. static_assert(N >= 1, "Invalid size N.");
  84. mNumBits = number.mNumBits;
  85. mSize = number.mSize;
  86. std::copy(number.mBits.begin(), number.mBits.begin() + mSize, mBits.begin());
  87. return *this;
  88. }
  89. // Support for std::move. The interface is required by BSNumber, but
  90. // the std::move of std::array is a copy (no pointer stealing).
  91. // Moreover, a std::array object in this class typically uses smaller
  92. // than N elements, the actual size stored in mSize, so we do not want
  93. // to move everything. Therefore, the move operator only copies the
  94. // bits BUT 'number' is modified as if you have stolen the data
  95. // (mNumBits and mSize set to zero).
  96. UIntegerFP32(UIntegerFP32&& number)
  97. {
  98. *this = std::move(number);
  99. }
  100. UIntegerFP32& operator=(UIntegerFP32&& number)
  101. {
  102. mNumBits = number.mNumBits;
  103. mSize = number.mSize;
  104. std::copy(number.mBits.begin(), number.mBits.begin() + mSize,
  105. mBits.begin());
  106. number.mNumBits = 0;
  107. number.mSize = 0;
  108. return *this;
  109. }
  110. // Member access.
  111. void SetNumBits(int32_t numBits)
  112. {
  113. if (numBits > 0)
  114. {
  115. mNumBits = numBits;
  116. mSize = 1 + (numBits - 1) / 32;
  117. }
  118. else if (numBits == 0)
  119. {
  120. mNumBits = 0;
  121. mSize = 0;
  122. }
  123. else
  124. {
  125. LogError("The number of bits must be nonnegative.");
  126. }
  127. #if defined(GTE_THROW_ON_UINTEGERFP32_OUT_OF_RANGE)
  128. LogAssert(mSize <= N, "N not large enough to store number of bits.");
  129. #endif
  130. }
  131. inline int32_t GetNumBits() const
  132. {
  133. return mNumBits;
  134. }
  135. inline std::array<uint32_t, N> const& GetBits() const
  136. {
  137. return mBits;
  138. }
  139. inline std::array<uint32_t, N>& GetBits()
  140. {
  141. return mBits;
  142. }
  143. inline void SetBack(uint32_t value)
  144. {
  145. mBits[mSize - 1] = value;
  146. }
  147. inline uint32_t GetBack() const
  148. {
  149. return mBits[mSize - 1];
  150. }
  151. inline int32_t GetSize() const
  152. {
  153. return mSize;
  154. }
  155. inline static int32_t GetMaxSize()
  156. {
  157. return N;
  158. }
  159. inline void SetAllBitsToZero()
  160. {
  161. std::fill(mBits.begin(), mBits.end(), 0u);
  162. }
  163. // Disk input/output. The fstream objects should be created using
  164. // std::ios::binary. The return value is 'true' iff the operation
  165. // was successful.
  166. bool Write(std::ostream& output) const
  167. {
  168. if (output.write((char const*)& mNumBits, sizeof(mNumBits)).bad())
  169. {
  170. return false;
  171. }
  172. if (output.write((char const*)& mSize, sizeof(mSize)).bad())
  173. {
  174. return false;
  175. }
  176. return output.write((char const*)& mBits[0], mSize * sizeof(mBits[0])).good();
  177. }
  178. bool Read(std::istream& input)
  179. {
  180. if (input.read((char*)& mNumBits, sizeof(mNumBits)).bad())
  181. {
  182. return false;
  183. }
  184. if (input.read((char*)& mSize, sizeof(mSize)).bad())
  185. {
  186. return false;
  187. }
  188. return input.read((char*)& mBits[0], mSize * sizeof(mBits[0])).good();
  189. }
  190. private:
  191. int32_t mNumBits, mSize;
  192. std::array<uint32_t, N> mBits;
  193. };
  194. }