#ifndef __UTILS_H__ #define __UTILS_H__ #include #include #include #include #include #include #include #include #include #include // To work around https://svn.boost.org/trac10/ticket/12534 #include #include #include #include //#include #include "cray_types.h" #include "exceptions.h" #include "config.h" #ifndef SINGLE_THREADED typedef std::atomic AtomicBool; //typedef bool AtomicBool; typedef std::atomic AtomicUInt64; typedef std::atomic AtomicUInt32; typedef std::atomic AtomicUInt16; typedef std::atomic AtomicInt64; typedef std::atomic AtomicInt32; typedef std::atomic AtomicInt16; static const bool MultiThreadedSupport = true; #else // SINGLE_THREADED typedef bool AtomicBool; typedef uint64_t AtomicUInt64; typedef uint32_t AtomicUInt32; typedef uint16_t AtomicUInt16; typedef int64_t AtomicInt64; typedef int32_t AtomicInt32; typedef int16_t AtomicInt16; static const bool MultiThreadedSupport = false; #endif // SINGLE_THREADED #ifndef NO_ASSERTS #define CRAY_ASSERT(aCond) do { if (!(aCond)) { std::stringstream ErrorStr; ErrorStr << "CRAY_ASSERT at " << __FILE__ << ":" << DecPrinter(__LINE__,0) << "(" << #aCond << " failed)"; std::cout << ErrorStr.str() << std::endl; throw Assert_x(ErrorStr.str()); }} while (false); #else #define CRAY_ASSERT(aCond) #endif #ifndef NO_ASSERTS #define CRAY_FIXME do { std::stringstream ErrorStr; ErrorStr << "CRAY_ASSERT at " << __FILE__ << ":" << DecPrinter(__LINE__,0) << "(" << #aCond << " failed)"; std::cout << ErrorStr.str() << std::endl; throw Assert_x(ErrorStr.str()); } while (false); #else #define CRAY_FIXME #endif #ifdef _MSC_VER #ifndef FORCEINLINE #define FORCEINLINE __forceinline #endif #define FORCEINLINEATTR #else #ifndef FORCEINLINE #define FORCEINLINE inline #endif #define FORCEINLINEATTR __attribute__((always_inline)) #endif #ifdef _MSC_VER #ifndef DEBUGBREAK #define DEBUGBREAK __debugbreak() #endif #else #ifndef DEBUGBREAK #define DEBUGBREAK #endif #endif #if 0 // Endienness swap code that doesn't use intrinsics inline uint16_t SwapBytes(uint16_t aInput) { return ((aInput & 0x00ff) << 8) | ((aInput & 0xff00) >> 8); } inline uint32_t SwapBytes(uint32_t aInput) { return ((aInput & 0x000000ff) << 24) | ((aInput & 0x0000ff00) << 8) | ((aInput & 0x00ff0000) >> 8) | ((aInput & 0xff000000) >> 24); } inline uint64_t SwapBytes(uint64_t aInput) { uint8_t *Data = (uint8_t *)&aInput; uint8_t Tmp; Tmp = Data[0]; Data[0] = Data[7]; Data[7] = Tmp; Tmp = Data[1]; Data[1] = Data[6]; Data[6] = Tmp; Tmp = Data[2]; Data[2] = Data[5]; Data[5] = Tmp; Tmp = Data[3]; Data[3] = Data[4]; Data[4] = Tmp; return aInput; } inline uint64_t SwapBytesInWords(uint64_t aInput) { uint16_t *Data = (uint16_t *)&aInput; Data[0] = SwapBytes(Data[0]); Data[1] = SwapBytes(Data[1]); Data[2] = SwapBytes(Data[2]); Data[3] = SwapBytes(Data[3]); return aInput; } #endif #ifdef _MSC_VER #include inline uint16_t SwapBytes(uint16_t aInput) { return _byteswap_ushort(aInput); } inline uint32_t SwapBytes(uint32_t aInput) { return _byteswap_ulong(aInput); } inline uint64_t SwapBytes(uint64_t aInput) { return _byteswap_uint64(aInput); } inline uint64_t SwapBytesInWords(uint64_t aInput) { uint16_t *Data = (uint16_t *)&aInput; Data[0] = SwapBytes(Data[0]); Data[1] = SwapBytes(Data[1]); Data[2] = SwapBytes(Data[2]); Data[3] = SwapBytes(Data[3]); return aInput; } #else // GCC inline uint16_t SwapBytes(uint16_t aInput) { return __builtin_bswap16(aInput); } inline uint32_t SwapBytes(uint32_t aInput) { return __builtin_bswap32(aInput); } inline uint64_t SwapBytes(uint64_t aInput) { return __builtin_bswap64(aInput); } inline uint64_t SwapBytesInWords(uint64_t aInput) { uint16_t *Data = (uint16_t *)&aInput; Data[0] = SwapBytes(Data[0]); Data[1] = SwapBytes(Data[1]); Data[2] = SwapBytes(Data[2]); Data[3] = SwapBytes(Data[3]); return aInput; } #endif template T SwapBits(T aInput) { T Output = 0; T InMask = 1; T OutMask = T(1) << (sizeof(OutMask)*8 - 1); while (OutMask != 0) { if ((aInput & InMask) != 0) Output |= OutMask; InMask <<= 1; OutMask >>= 1; } return Output; } inline uint64_t GetBits(uint64_t aData, size_t aStartIdx, size_t aEndIdx) { size_t StartIdx = std::min(aStartIdx, aEndIdx); size_t EndIdx = std::max(aStartIdx, aEndIdx); if (StartIdx == 0 && EndIdx == std::numeric_limits::digits - 1) { return aData; } return (aData >> StartIdx) & ((1ULL << (EndIdx - StartIdx + 1)) - 1); } inline uint32_t GetBits(uint32_t aData, size_t aStartIdx, size_t aEndIdx) { size_t StartIdx = std::min(aStartIdx, aEndIdx); size_t EndIdx = std::max(aStartIdx, aEndIdx); if (StartIdx == 0 && EndIdx == std::numeric_limits::digits - 1) { return aData; } return (aData >> StartIdx) & ((1UL << (EndIdx - StartIdx + 1)) - 1); } inline uint64_t GetBitsReverse(uint64_t aData, size_t aStartIdx, size_t aEndIdx) { return GetBits(aData, 63 - aStartIdx, 63 - aEndIdx); } inline uint32_t GetBitsReverse(uint32_t aData, size_t aStartIdx, size_t aEndIdx) { return GetBits(aData, 31 - aStartIdx, 31 - aEndIdx); } template T GetBit(T aData,size_t aIdx) { return GetBits(aData,aIdx,aIdx); } inline uint64_t SetBits(uint64_t aData,size_t aStartIdx,size_t aEndIdx,uint64_t aValue) { size_t StartIdx = std::min(aStartIdx,aEndIdx); size_t EndIdx = std::max(aStartIdx,aEndIdx); if (StartIdx == 0 && EndIdx == std::numeric_limits::digits - 1) { return aValue; } uint64_t Mask = ((1ULL << (EndIdx-StartIdx+1)) - 1) << StartIdx; return (aData & ~Mask) | ((aValue << StartIdx) & Mask); } inline uint64_t SetBitsReverse(uint64_t aData, size_t aStartIdx, size_t aEndIdx, uint64_t aValue) { return SetBits(aData, 63 - aStartIdx, 63 - aEndIdx, aValue); } //template inline V SetBits(V aValue, M aMask, N aNewValue) { return (aValue & ~aMask) | aNewValue; } #define SET_BITS(aValue, aMask, aNewValue) (((aValue) & ~(aMask)) | (aNewValue)) #define SideEffectIndent Indent(cSideEffectIdent) inline std::string Replace(std::string aSrc, std::string const& aTarget, std::string const& aRepl) { if (aTarget.length() == 0) { return aSrc; } if (aSrc.length() == 0) { return aSrc; // nothing to match against } size_t idx = 0; for (;;) { idx = aSrc.find(aTarget, idx); if (idx == std::string::npos) break; aSrc.replace(idx, aTarget.length(), aRepl); idx += aRepl.length(); } return aSrc; } inline char PrintableChar(char aC) { if (aC < ' ') return '.'; // if (aC > 127) return '.'; return aC; } /////// A simple NULL stream class NullStrm_c: public std::ostream { public: NullStrm_c(): std::ostream(/*mNoinit*/nullptr) { init(nullptr); }; protected: }; ///////////////////////////////////////////////////////////////////// // Type-dependent integral range functions template constexpr tType MinValue(const tType &) { return std::numeric_limits::min(); } template constexpr tType MaxValue(const tType &) { return std::numeric_limits::max(); } ///////////////////////////////////////////////////////////////////// // Formatter classes class FieldFormatter_i { public: virtual void Print(std::ostream &aStream) const = 0; virtual ~FieldFormatter_i() {} }; inline std::ostream & operator << (std::ostream &aStream, const FieldFormatter_i &aField) { if (!aStream.good()) return aStream; aField.Print(aStream); return aStream; } class DoublePrinter: public FieldFormatter_i { public: explicit DoublePrinter(double aNumber, int aSize = 16, int aPrecision = 16, bool aFixed = true): Number(aNumber), Size(aSize), Precision(aPrecision), Fixed(aFixed) {} explicit DoublePrinter(CFloat_t aNumber, int aSize = 16, int aPrecision = 16, bool aFixed = true): Number(aNumber.ToDouble()), Size(aSize), Precision(aPrecision), Fixed(aFixed) {} virtual void Print(std::ostream &aStream) const override { if (!aStream.good()) return; std::stringstream Str; if (Fixed) Str << std::fixed; //if (Size > 0) Str << setw(Size); if (Precision > 0) Str << std::setprecision(Precision); Str << Number; aStream << Str.str(); } protected: double Number; int Size; int Precision; bool Fixed; }; class HexPrinter: public FieldFormatter_i { public: template explicit HexPrinter(Type_T aNumber, int aSize = (std::numeric_limits::digits + 3) / 4) : Number(aNumber), IsSigned(std::is_signed::value), Size(aSize) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; std::stringstream Str; if (Size > 0) { if (IsSigned) { Str << "0x" << std::noshowbase << std::uppercase << std::hex << std::setw(Size) << std::setfill('0') << (int64_t)Number; } else { Str << "0x" << std::noshowbase << std::uppercase << std::hex << std::setw(Size) << std::setfill('0') << Number; } } else { if (IsSigned) { Str << "0x" << std::noshowbase << std::uppercase << std::hex << (int64_t)Number; } else { Str << "0x" << std::noshowbase << std::uppercase << std::hex << Number; } } aStream << Str.str(); } uint64_t Number; bool IsSigned; int Size; }; class BoolPrinter : public FieldFormatter_i { public: explicit BoolPrinter(bool aValue) : Value(aValue) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; aStream << (Value ? "true" : "false"); } bool Value; }; class AsciiDumpPrinter : public FieldFormatter_i { public: template explicit AsciiDumpPrinter(Type_T aNumber) : Number(aNumber), Size(sizeof(Type_T)) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; char *NumAsStr = (char*)(&Number); for (int i = 0; i < Size; ++i) { aStream << PrintableChar(NumAsStr[Size-1-i]); } } uint64_t Number; int Size; }; class OctPrinter: public FieldFormatter_i { public: template explicit OctPrinter(Type_T aNumber, int aSize = (std::numeric_limits::digits + 2) / 3) : Number(aNumber), IsSigned(std::is_signed::value), Size(aSize) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; std::stringstream Str; if (Size > 0) { if (IsSigned) { Str << "0" << std::noshowbase << std::uppercase << std::oct << std::setw(Size) << std::setfill('0') << (int64_t)Number; } else { Str << "0" << std::noshowbase << std::uppercase << std::oct << std::setw(Size) << std::setfill('0') << Number; } } else { if (IsSigned) { Str << "0" << std::noshowbase << std::uppercase << std::oct << (int64_t)Number; } else { Str << "0" << std::noshowbase << std::uppercase << std::oct << Number; } } aStream << Str.str(); } uint64_t Number; bool IsSigned; int Size; }; class DecPrinter: public FieldFormatter_i { public: template explicit DecPrinter(Type_T aNumber, int aSize = 0, char aFiller = ' ') : Number(aNumber), IsSigned(std::is_signed::value), Size(aSize), Filler(aFiller) {} explicit DecPrinter(CAddr_t aNumber, int aSize = 0, char aFiller = ' '): Number(aNumber), IsSigned(false), Size(aSize), Filler(aFiller) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; std::stringstream Str; if (Size > 0) { if (IsSigned) { Str << std::noshowbase << std::uppercase << std::dec << std::setw(Size) << std::setfill(Filler) << (int64_t)Number; } else { Str << std::noshowbase << std::uppercase << std::dec << std::setw(Size) << std::setfill(Filler) << Number; } } else { if (IsSigned) { Str << std::noshowbase << std::uppercase << std::dec << (int64_t)Number; } else { Str << std::noshowbase << std::uppercase << std::dec << Number; } } aStream << Str.str(); } char Filler; uint64_t Number; bool IsSigned; int Size; }; class InstAddr: public FieldFormatter_i { public: template explicit InstAddr(const Type_T aAddr) : mAddr(aAddr) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; aStream << HexPrinter(mAddr / 4) << ":p" << int(mAddr % 4); } CAddr_t mAddr; }; class Addr: public FieldFormatter_i { public: template explicit Addr(const Type_T aAddr) : mAddr(aAddr) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; aStream << HexPrinter(mAddr); } CAddr_t mAddr; }; class Indent: public FieldFormatter_i { public: explicit Indent(size_t aIndent): mIndent(aIndent) {} virtual void Print(std::ostream &aStream) const { if (!aStream.good()) return; for(uint32_t i=0;i= mArgc) throw NoMoreArgs_x("Too few arguments"); return mArgv[mCurArg++]; } void UnGetParam() { if (mCurArg == 1) throw NoMoreArgs_x("Can't un-get first parameter"); --mCurArg; } void Rewind() { mCurArg = 1; } bool HasMoreParams() { return mCurArg < mArgc; } const std::string GetProgramName() const { return mArgv[0]; } protected: size_t mArgc; const char **mArgv; size_t mCurArg; }; ///////////////////////////////////////////////////////////////////// // An adaptor class that can take a class and some methods on it and turn that into an STL-compatible iterator template class IteratorWrapper_t { public: explicit IteratorWrapper_t(tContainer& aParent): mParent(&aParent) {} IteratorWrapper_t(const IteratorWrapper_t&) = default; IteratorWrapper_t& operator=(const IteratorWrapper_t&) = default; using value_type = tElement&; class iterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename IteratorWrapper_t::value_type; using difference_type = ptrdiff_t; using pointer = value_type; using const_pointer = pointer; using reference = value_type; using const_reference = reference; iterator(const iterator&) = default; iterator& operator=(const iterator&) = default; iterator(IteratorWrapper_t& aParent, size_t aIdx): mIdx(aIdx), mParent(aParent) {} reference operator*() const { return (mParent.mParent->*Access)(mIdx); } pointer operator->() const { return operator*(); } iterator &operator++() { mIdx += 1; return *this; } iterator operator++(int) { iterator RetVal = *this; ++*this; return RetVal; } iterator &operator--() { mIdx -= 1; return *this; } iterator operator--(int) {iterator RetVal = *this; --*this; return RetVal; } friend bool operator==(const iterator &aA, const iterator &aB) { return &aA.mParent == &aB.mParent && aA.mIdx == aB.mIdx; } friend bool operator!=(const iterator &aA, const iterator &aB) { return !(aA == aB); } protected: size_t mIdx; IteratorWrapper_t& mParent; }; using const_iterator = const iterator; iterator begin() const { return iterator(const_cast(*this), 0); } iterator end() const { return iterator(const_cast(*this), (mParent->*Count)()); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } protected: tContainer *mParent; }; template class ConstIteratorWrapper_t { public: explicit ConstIteratorWrapper_t(const tContainer& aParent) : mParent(&aParent) {} ConstIteratorWrapper_t(const ConstIteratorWrapper_t&) = default; ConstIteratorWrapper_t& operator=(const ConstIteratorWrapper_t&) = default; // using value_type = tElement&; typedef tElement& value_type; class const_iterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename ConstIteratorWrapper_t::value_type; using difference_type = ptrdiff_t; using pointer = value_type; using const_pointer = pointer; using reference = value_type; using const_reference = reference; const_iterator(const const_iterator&) = default; const_iterator& operator=(const const_iterator&) = default; const_iterator(ConstIteratorWrapper_t& aParent, size_t aIdx) : mIdx(aIdx), mParent(aParent) {} const_reference operator*() const { return (mParent.mParent->*CAccess)(mIdx); } const_pointer operator->() const { return operator*(); } const_iterator &operator++() { mIdx += 1; return *this; } const_iterator operator++(int) { const_iterator RetVal = *this; ++*this; return RetVal; } const_iterator &operator--() { mIdx -= 1; return *this; } const_iterator operator--(int) { const_iterator RetVal = *this; --*this; return RetVal; } friend bool operator==(const const_iterator &aA, const const_iterator &aB) { return &aA.mParent == &aB.mParent && aA.mIdx == aB.mIdx; } friend bool operator!=(const const_iterator &aA, const const_iterator &aB) { return !(aA == aB); } protected: size_t mIdx; ConstIteratorWrapper_t& mParent; }; const_iterator cbegin() const { return const_iterator(const_cast(*this), 0); } const_iterator cend() const { return const_iterator(const_cast(*this), (mParent->*Count)()); } protected: const tContainer *mParent; }; enum class MachineTypes_e : int { XMP1xx, XMP2xx, XMP4xx, YMP, C90, T90, YEL, J90, SV1 }; inline bool IsXmp(MachineTypes_e aMachineType) { return (aMachineType == MachineTypes_e::XMP1xx) || (aMachineType == MachineTypes_e::XMP2xx) || (aMachineType == MachineTypes_e::XMP4xx); } enum class IopRevision_e { IOSD, IOSE }; struct BitRange_s { BitRange_s(uint8_t aStart, uint8_t aEnd) : Start(aStart), End(aEnd) {} uint8_t Start, End; }; void SetThreadAffinity(std::thread &aThread, size_t aCpuId); void SetThreadAffinity(size_t aCpuId); std::string Dump(std::vector &aVector); class Thread_c : public std::thread { public: Thread_c() : mTerminate(false), mPaused(true) {} virtual ~Thread_c() { Terminate(); if (joinable()) join(); } explicit Thread_c(bool aStart) : mTerminate(false) { if (aStart) Start(); } void Terminate() { mTerminate = true; } void Resume() { mPaused = false; } void Pause() { mPaused = true; } bool IsPaused() const { return mPaused; } void Start() { std::thread::operator=(std::thread(&Thread_c::BaseThread, this)); } protected: bool IsTerminating() { return mTerminate; } virtual void Thread() = 0; private: void BaseThread() { Thread(); } std::atomic_bool mTerminate; std::atomic_bool mPaused; }; #endif // __UTILS_H__