UIntegerAP32.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 <limits>
  11. #include <istream>
  12. #include <ostream>
  13. #include <vector>
  14. // Class UIntegerAP32 is designed to support arbitrary precision arithmetic
  15. // using BSNumber and BSRational. It is not a general-purpose class for
  16. // arithmetic of unsigned integers.
  17. // Uncomment this to collect statistics on how large the UIntegerAP32 storage
  18. // becomes when using it for the UInteger of BSNumber. If you use this
  19. // feature, you must define gsUIntegerAP32MaxSize somewhere in your code.
  20. // After a sequence of BSNumber operations, look at gsUIntegerAP32MaxSize in
  21. // the debugger watch window. If the number is not too large, you might be
  22. // safe in replacing UIntegerAP32 by UIntegerFP32<N>, where N is the value of
  23. // gsUIntegerAP32MaxSize. This leads to much faster code because you no
  24. // longer have dynamic memory allocations and deallocations that occur
  25. // regularly with std::vector<uint32_t> during BSNumber operations. A safer
  26. // choice is to argue mathematically that the maximum size is bounded by N.
  27. // This requires an analysis of how many bits of precision you need for the
  28. // types of computation you perform. See class BSPrecision for code that
  29. // allows you to compute maximum N.
  30. //
  31. //#define GTE_COLLECT_UINTEGERAP32_STATISTICS
  32. #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS)
  33. #include <Mathematics/AtomicMinMax.h>
  34. namespace WwiseGTE
  35. {
  36. extern std::atomic<size_t> gsUIntegerAP32MaxSize;
  37. }
  38. #endif
  39. namespace WwiseGTE
  40. {
  41. class UIntegerAP32 : public UIntegerALU32<UIntegerAP32>
  42. {
  43. public:
  44. // Construction.
  45. UIntegerAP32()
  46. :
  47. mNumBits(0)
  48. {
  49. }
  50. UIntegerAP32(UIntegerAP32 const& number)
  51. {
  52. *this = number;
  53. }
  54. UIntegerAP32(uint32_t number)
  55. {
  56. if (number > 0)
  57. {
  58. int32_t first = BitHacks::GetLeadingBit(number);
  59. int32_t last = BitHacks::GetTrailingBit(number);
  60. mNumBits = first - last + 1;
  61. mBits.resize(1);
  62. mBits[0] = (number >> last);
  63. }
  64. else
  65. {
  66. mNumBits = 0;
  67. }
  68. #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS)
  69. AtomicMax(gsUIntegerAP32MaxSize, mBits.size());
  70. #endif
  71. }
  72. UIntegerAP32(uint64_t number)
  73. {
  74. if (number > 0)
  75. {
  76. int32_t first = BitHacks::GetLeadingBit(number);
  77. int32_t last = BitHacks::GetTrailingBit(number);
  78. number >>= last;
  79. mNumBits = first - last + 1;
  80. mBits.resize(1 + (mNumBits - 1) / 32);
  81. mBits[0] = (uint32_t)(number & 0x00000000FFFFFFFFull);
  82. if (mBits.size() > 1)
  83. {
  84. mBits[1] = (uint32_t)((number >> 32) & 0x00000000FFFFFFFFull);
  85. }
  86. }
  87. else
  88. {
  89. mNumBits = 0;
  90. }
  91. #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS)
  92. AtomicMax(gsUIntegerAP32MaxSize, mBits.size());
  93. #endif
  94. }
  95. // Assignment.
  96. UIntegerAP32& operator=(UIntegerAP32 const& number)
  97. {
  98. mNumBits = number.mNumBits;
  99. mBits = number.mBits;
  100. return *this;
  101. }
  102. // Support for std::move.
  103. UIntegerAP32(UIntegerAP32&& number)
  104. {
  105. *this = std::move(number);
  106. }
  107. UIntegerAP32& operator=(UIntegerAP32&& number)
  108. {
  109. mNumBits = number.mNumBits;
  110. mBits = std::move(number.mBits);
  111. number.mNumBits = 0;
  112. return *this;
  113. }
  114. // Member access.
  115. void SetNumBits(int32_t numBits)
  116. {
  117. if (numBits > 0)
  118. {
  119. mNumBits = numBits;
  120. mBits.resize(1 + (numBits - 1) / 32);
  121. }
  122. else if (numBits == 0)
  123. {
  124. mNumBits = 0;
  125. mBits.clear();
  126. }
  127. else
  128. {
  129. LogError("The number of bits must be nonnegative.");
  130. }
  131. #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS)
  132. AtomicMax(gsUIntegerAP32MaxSize, mBits.size());
  133. #endif
  134. }
  135. inline int32_t GetNumBits() const
  136. {
  137. return mNumBits;
  138. }
  139. inline std::vector<uint32_t> const& GetBits() const
  140. {
  141. return mBits;
  142. }
  143. inline std::vector<uint32_t>& GetBits()
  144. {
  145. return mBits;
  146. }
  147. inline void SetBack(uint32_t value)
  148. {
  149. mBits.back() = value;
  150. }
  151. inline uint32_t GetBack() const
  152. {
  153. return mBits.back();
  154. }
  155. inline int32_t GetSize() const
  156. {
  157. return static_cast<int32_t>(mBits.size());
  158. }
  159. inline static int32_t GetMaxSize()
  160. {
  161. return std::numeric_limits<int32_t>::max();
  162. }
  163. inline void SetAllBitsToZero()
  164. {
  165. std::fill(mBits.begin(), mBits.end(), 0u);
  166. }
  167. // Disk input/output. The return value is 'true' iff the operation
  168. // was successful.
  169. bool Write(std::ostream& output) const
  170. {
  171. if (output.write((char const*)& mNumBits, sizeof(mNumBits)).bad())
  172. {
  173. return false;
  174. }
  175. std::size_t size = mBits.size();
  176. if (output.write((char const*)& size, sizeof(size)).bad())
  177. {
  178. return false;
  179. }
  180. return output.write((char const*)& mBits[0], size * sizeof(mBits[0])).good();
  181. }
  182. bool Read(std::istream& input)
  183. {
  184. if (input.read((char*)& mNumBits, sizeof(mNumBits)).bad())
  185. {
  186. return false;
  187. }
  188. std::size_t size;
  189. if (input.read((char*)& size, sizeof(size)).bad())
  190. {
  191. return false;
  192. }
  193. mBits.resize(size);
  194. return input.read((char*)& mBits[0], size * sizeof(mBits[0])).good();
  195. }
  196. private:
  197. int32_t mNumBits;
  198. std::vector<uint32_t> mBits;
  199. };
  200. }