// David Eberly, Geometric Tools, Redmond WA 98052 // Copyright (c) 1998-2020 // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt // Version: 4.0.2019.09.11 #pragma once #include #include #include #include #include #include // Class UIntegerAP32 is designed to support arbitrary precision arithmetic // using BSNumber and BSRational. It is not a general-purpose class for // arithmetic of unsigned integers. // Uncomment this to collect statistics on how large the UIntegerAP32 storage // becomes when using it for the UInteger of BSNumber. If you use this // feature, you must define gsUIntegerAP32MaxSize somewhere in your code. // After a sequence of BSNumber operations, look at gsUIntegerAP32MaxSize in // the debugger watch window. If the number is not too large, you might be // safe in replacing UIntegerAP32 by UIntegerFP32, where N is the value of // gsUIntegerAP32MaxSize. This leads to much faster code because you no // longer have dynamic memory allocations and deallocations that occur // regularly with std::vector during BSNumber operations. A safer // choice is to argue mathematically that the maximum size is bounded by N. // This requires an analysis of how many bits of precision you need for the // types of computation you perform. See class BSPrecision for code that // allows you to compute maximum N. // //#define GTE_COLLECT_UINTEGERAP32_STATISTICS #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS) #include namespace WwiseGTE { extern std::atomic gsUIntegerAP32MaxSize; } #endif namespace WwiseGTE { class UIntegerAP32 : public UIntegerALU32 { public: // Construction. UIntegerAP32() : mNumBits(0) { } UIntegerAP32(UIntegerAP32 const& number) { *this = number; } UIntegerAP32(uint32_t number) { if (number > 0) { int32_t first = BitHacks::GetLeadingBit(number); int32_t last = BitHacks::GetTrailingBit(number); mNumBits = first - last + 1; mBits.resize(1); mBits[0] = (number >> last); } else { mNumBits = 0; } #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS) AtomicMax(gsUIntegerAP32MaxSize, mBits.size()); #endif } UIntegerAP32(uint64_t number) { if (number > 0) { int32_t first = BitHacks::GetLeadingBit(number); int32_t last = BitHacks::GetTrailingBit(number); number >>= last; mNumBits = first - last + 1; mBits.resize(1 + (mNumBits - 1) / 32); mBits[0] = (uint32_t)(number & 0x00000000FFFFFFFFull); if (mBits.size() > 1) { mBits[1] = (uint32_t)((number >> 32) & 0x00000000FFFFFFFFull); } } else { mNumBits = 0; } #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS) AtomicMax(gsUIntegerAP32MaxSize, mBits.size()); #endif } // Assignment. UIntegerAP32& operator=(UIntegerAP32 const& number) { mNumBits = number.mNumBits; mBits = number.mBits; return *this; } // Support for std::move. UIntegerAP32(UIntegerAP32&& number) { *this = std::move(number); } UIntegerAP32& operator=(UIntegerAP32&& number) { mNumBits = number.mNumBits; mBits = std::move(number.mBits); number.mNumBits = 0; return *this; } // Member access. void SetNumBits(int32_t numBits) { if (numBits > 0) { mNumBits = numBits; mBits.resize(1 + (numBits - 1) / 32); } else if (numBits == 0) { mNumBits = 0; mBits.clear(); } else { LogError("The number of bits must be nonnegative."); } #if defined(GTE_COLLECT_UINTEGERAP32_STATISTICS) AtomicMax(gsUIntegerAP32MaxSize, mBits.size()); #endif } inline int32_t GetNumBits() const { return mNumBits; } inline std::vector const& GetBits() const { return mBits; } inline std::vector& GetBits() { return mBits; } inline void SetBack(uint32_t value) { mBits.back() = value; } inline uint32_t GetBack() const { return mBits.back(); } inline int32_t GetSize() const { return static_cast(mBits.size()); } inline static int32_t GetMaxSize() { return std::numeric_limits::max(); } inline void SetAllBitsToZero() { std::fill(mBits.begin(), mBits.end(), 0u); } // Disk input/output. The return value is 'true' iff the operation // was successful. bool Write(std::ostream& output) const { if (output.write((char const*)& mNumBits, sizeof(mNumBits)).bad()) { return false; } std::size_t size = mBits.size(); if (output.write((char const*)& size, sizeof(size)).bad()) { return false; } return output.write((char const*)& mBits[0], size * sizeof(mBits[0])).good(); } bool Read(std::istream& input) { if (input.read((char*)& mNumBits, sizeof(mNumBits)).bad()) { return false; } std::size_t size; if (input.read((char*)& size, sizeof(size)).bad()) { return false; } mBits.resize(size); return input.read((char*)& mBits[0], size * sizeof(mBits[0])).good(); } private: int32_t mNumBits; std::vector mBits; }; }