// | |
// Copyright (c) 2017-2020 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, ...); | |
*/ |