| // |
| // Copyright (c) 2017-2021 Advanced Micro Devices, Inc. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| // |
| |
| #pragma once |
| |
| #include "VmaUsage.h" |
| |
| #include <iostream> |
| #include <fstream> |
| #include <vector> |
| #include <memory> |
| #include <algorithm> |
| #include <numeric> |
| #include <array> |
| #include <type_traits> |
| #include <utility> |
| #include <chrono> |
| #include <string> |
| #include <limits> |
| |
| #include <cassert> |
| #include <cstdlib> |
| #include <cstdio> |
| #include <cstdarg> |
| |
| typedef std::chrono::high_resolution_clock::time_point time_point; |
| typedef std::chrono::high_resolution_clock::duration duration; |
| |
| inline float ToFloatSeconds(duration d) |
| { |
| return std::chrono::duration_cast<std::chrono::duration<float>>(d).count(); |
| } |
| |
| void SecondsToFriendlyStr(float seconds, std::string& out); |
| |
| template <typename T> |
| T ceil_div(T x, T y) |
| { |
| return (x+y-1) / y; |
| } |
| template <typename T> |
| inline T round_div(T x, T y) |
| { |
| return (x+y/(T)2) / y; |
| } |
| |
| template <typename T> |
| inline T align_up(T val, T align) |
| { |
| return (val + align - 1) / align * align; |
| } |
| |
| struct StrRange |
| { |
| const char* beg; |
| const char* end; |
| |
| StrRange() { } |
| StrRange(const char* beg, const char* end) : beg(beg), end(end) { } |
| explicit StrRange(const char* sz) : beg(sz), end(sz + strlen(sz)) { } |
| explicit StrRange(const std::string& s) : beg(s.data()), end(s.data() + s.length()) { } |
| |
| size_t length() const { return end - beg; } |
| void to_str(std::string& out) const { out.assign(beg, end); } |
| }; |
| |
| inline bool StrRangeEq(const StrRange& lhs, const char* rhsSz) |
| { |
| const size_t rhsLen = strlen(rhsSz); |
| return rhsLen == lhs.length() && |
| memcmp(lhs.beg, rhsSz, rhsLen) == 0; |
| } |
| |
| inline bool StrRangeToUint(const StrRange& s, uint32_t& out) |
| { |
| char* end = (char*)s.end; |
| out = (uint32_t)strtoul(s.beg, &end, 10); |
| return end == s.end; |
| } |
| inline bool StrRangeToUint(const StrRange& s, uint64_t& out) |
| { |
| char* end = (char*)s.end; |
| out = (uint64_t)strtoull(s.beg, &end, 10); |
| return end == s.end; |
| } |
| inline bool StrRangeToPtr(const StrRange& s, uint64_t& out) |
| { |
| char* end = (char*)s.end; |
| out = (uint64_t)strtoull(s.beg, &end, 16); |
| return end == s.end; |
| } |
| inline bool StrRangeToFloat(const StrRange& s, float& out) |
| { |
| char* end = (char*)s.end; |
| out = strtof(s.beg, &end); |
| return end == s.end; |
| } |
| inline bool StrRangeToBool(const StrRange& s, bool& out) |
| { |
| if(s.end - s.beg == 1) |
| { |
| if(*s.beg == '1') |
| { |
| out = true; |
| } |
| else if(*s.beg == '0') |
| { |
| out = false; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| else |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| bool StrRangeToPtrList(const StrRange& s, std::vector<uint64_t>& out); |
| |
| class LineSplit |
| { |
| public: |
| LineSplit(const char* data, size_t numBytes) : |
| m_Data(data), |
| m_NumBytes(numBytes), |
| m_NextLineBeg(0), |
| m_NextLineIndex(0) |
| { |
| } |
| |
| bool GetNextLine(StrRange& out); |
| size_t GetNextLineIndex() const { return m_NextLineIndex; } |
| |
| private: |
| const char* const m_Data; |
| const size_t m_NumBytes; |
| size_t m_NextLineBeg; |
| size_t m_NextLineIndex; |
| }; |
| |
| class CsvSplit |
| { |
| public: |
| static const size_t RANGE_COUNT_MAX = 32; |
| |
| void Set(const StrRange& line, size_t maxCount = RANGE_COUNT_MAX); |
| |
| const StrRange& GetLine() const { return m_Line; } |
| |
| size_t GetCount() const { return m_Count; } |
| StrRange GetRange(size_t index) const |
| { |
| if(index < m_Count) |
| { |
| return StrRange { |
| m_Line.beg + m_Ranges[index * 2], |
| m_Line.beg + m_Ranges[index * 2 + 1] }; |
| } |
| else |
| { |
| return StrRange{0, 0}; |
| } |
| } |
| |
| private: |
| StrRange m_Line = { nullptr, nullptr }; |
| size_t m_Count = 0; |
| size_t m_Ranges[RANGE_COUNT_MAX * 2]; // Pairs of begin-end. |
| }; |
| |
| class CmdLineParser |
| { |
| public: |
| enum RESULT |
| { |
| RESULT_OPT, |
| RESULT_PARAMETER, |
| RESULT_END, |
| RESULT_ERROR, |
| }; |
| |
| CmdLineParser(int argc, char **argv); |
| CmdLineParser(const char *CmdLine); |
| |
| void RegisterOpt(uint32_t Id, char Opt, bool Parameter); |
| void RegisterOpt(uint32_t Id, const std::string &Opt, bool Parameter); |
| |
| RESULT ReadNext(); |
| uint32_t GetOptId(); |
| const std::string & GetParameter(); |
| |
| private: |
| struct SHORT_OPT |
| { |
| uint32_t Id; |
| char Opt; |
| bool Parameter; |
| |
| SHORT_OPT(uint32_t Id, char Opt, bool Parameter) : Id(Id), Opt(Opt), Parameter(Parameter) { } |
| }; |
| |
| struct LONG_OPT |
| { |
| uint32_t Id; |
| std::string Opt; |
| bool Parameter; |
| |
| LONG_OPT(uint32_t Id, std::string Opt, bool Parameter) : Id(Id), Opt(Opt), Parameter(Parameter) { } |
| }; |
| |
| char **m_argv; |
| const char *m_CmdLine; |
| int m_argc; |
| size_t m_CmdLineLength; |
| size_t m_ArgIndex; |
| |
| bool ReadNextArg(std::string *OutArg); |
| |
| std::vector<SHORT_OPT> m_ShortOpts; |
| std::vector<LONG_OPT> m_LongOpts; |
| |
| SHORT_OPT * FindShortOpt(char Opt); |
| LONG_OPT * FindLongOpt(const std::string &Opt); |
| |
| bool m_InsideMultioption; |
| std::string m_LastArg; |
| size_t m_LastArgIndex; |
| uint32_t m_LastOptId; |
| std::string m_LastParameter; |
| }; |
| |
| /* |
| Parses and stores a sequence of ranges. |
| |
| Upper range is inclusive. |
| |
| Examples: |
| |
| "1" -> [ {1, 1} ] |
| "1,10" -> [ {1, 1}, {10, 10} ] |
| "2-6" -> [ {2, 6} ] |
| "-8" -> [ {MIN, 8} ] |
| "12-" -> [ {12, MAX} ] |
| "1-10,12,15-" -> [ {1, 10}, {12, 12}, {15, MAX} ] |
| |
| TODO: Optimize it: Do sorting and merging while parsing. Do binary search while |
| reading. |
| */ |
| template<typename T> |
| class RangeSequence |
| { |
| public: |
| typedef std::pair<T, T> RangeType; |
| |
| void Clear() { m_Ranges.clear(); } |
| bool Parse(const StrRange& str); |
| |
| bool IsEmpty() const { return m_Ranges.empty(); } |
| size_t GetCount() const { return m_Ranges.size(); } |
| const RangeType* GetRanges() const { return m_Ranges.data(); } |
| |
| bool Includes(T number) const; |
| |
| private: |
| std::vector<RangeType> m_Ranges; |
| }; |
| |
| template<typename T> |
| bool RangeSequence<T>::Parse(const StrRange& str) |
| { |
| m_Ranges.clear(); |
| |
| StrRange currRange = { str.beg, str.beg }; |
| while(currRange.beg < str.end) |
| { |
| currRange.end = currRange.beg + 1; |
| // Find next ',' or the end. |
| while(currRange.end < str.end && *currRange.end != ',') |
| { |
| ++currRange.end; |
| } |
| |
| // Find '-' within this range. |
| const char* hyphenPos = currRange.beg; |
| while(hyphenPos < currRange.end && *hyphenPos != '-') |
| { |
| ++hyphenPos; |
| } |
| |
| // No hyphen - single number like '10'. |
| if(hyphenPos == currRange.end) |
| { |
| RangeType range; |
| if(!StrRangeToUint(currRange, range.first)) |
| { |
| return false; |
| } |
| range.second = range.first; |
| m_Ranges.push_back(range); |
| } |
| // Hyphen at the end, like '10-'. |
| else if(hyphenPos + 1 == currRange.end) |
| { |
| const StrRange numberRange = { currRange.beg, hyphenPos }; |
| RangeType range; |
| if(!StrRangeToUint(numberRange, range.first)) |
| { |
| return false; |
| } |
| range.second = std::numeric_limits<T>::max(); |
| m_Ranges.push_back(range); |
| } |
| // Hyphen at the beginning, like "-10". |
| else if(hyphenPos == currRange.beg) |
| { |
| const StrRange numberRange = { currRange.beg + 1, currRange.end }; |
| RangeType range; |
| range.first = std::numeric_limits<T>::min(); |
| if(!StrRangeToUint(numberRange, range.second)) |
| { |
| return false; |
| } |
| m_Ranges.push_back(range); |
| } |
| // Hyphen in the middle, like "1-10". |
| else |
| { |
| const StrRange numberRange1 = { currRange.beg, hyphenPos }; |
| const StrRange numberRange2 = { hyphenPos + 1, currRange.end }; |
| RangeType range; |
| if(!StrRangeToUint(numberRange1, range.first) || |
| !StrRangeToUint(numberRange2, range.second) || |
| range.second < range.first) |
| { |
| return false; |
| } |
| m_Ranges.push_back(range); |
| } |
| |
| // Skip ',' |
| currRange.beg = currRange.end + 1; |
| } |
| |
| return true; |
| } |
| |
| template<typename T> |
| bool RangeSequence<T>::Includes(T number) const |
| { |
| for(const auto& it : m_Ranges) |
| { |
| if(number >= it.first && number <= it.second) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* |
| class RandomNumberGenerator |
| { |
| public: |
| RandomNumberGenerator() : m_Value{GetTickCount()} {} |
| RandomNumberGenerator(uint32_t seed) : m_Value{seed} { } |
| void Seed(uint32_t seed) { m_Value = seed; } |
| uint32_t Generate() { return GenerateFast() ^ (GenerateFast() >> 7); } |
| |
| private: |
| uint32_t m_Value; |
| uint32_t GenerateFast() { return m_Value = (m_Value * 196314165 + 907633515); } |
| }; |
| |
| enum class CONSOLE_COLOR |
| { |
| INFO, |
| NORMAL, |
| WARNING, |
| ERROR_, |
| COUNT |
| }; |
| |
| void SetConsoleColor(CONSOLE_COLOR color); |
| |
| void PrintMessage(CONSOLE_COLOR color, const char* msg); |
| void PrintMessage(CONSOLE_COLOR color, const wchar_t* msg); |
| |
| inline void Print(const char* msg) { PrintMessage(CONSOLE_COLOR::NORMAL, msg); } |
| inline void Print(const wchar_t* msg) { PrintMessage(CONSOLE_COLOR::NORMAL, msg); } |
| inline void PrintWarning(const char* msg) { PrintMessage(CONSOLE_COLOR::WARNING, msg); } |
| inline void PrintWarning(const wchar_t* msg) { PrintMessage(CONSOLE_COLOR::WARNING, msg); } |
| inline void PrintError(const char* msg) { PrintMessage(CONSOLE_COLOR::ERROR_, msg); } |
| inline void PrintError(const wchar_t* msg) { PrintMessage(CONSOLE_COLOR::ERROR_, msg); } |
| |
| void PrintMessageV(CONSOLE_COLOR color, const char* format, va_list argList); |
| void PrintMessageV(CONSOLE_COLOR color, const wchar_t* format, va_list argList); |
| void PrintMessageF(CONSOLE_COLOR color, const char* format, ...); |
| void PrintMessageF(CONSOLE_COLOR color, const wchar_t* format, ...); |
| void PrintWarningF(const char* format, ...); |
| void PrintWarningF(const wchar_t* format, ...); |
| void PrintErrorF(const char* format, ...); |
| void PrintErrorF(const wchar_t* format, ...); |
| */ |