diff options
| author | Nicholas Estelami <NEstelami@users.noreply.github.com> | 2021-08-05 05:11:24 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-05 05:11:24 -0400 |
| commit | 82bd27604a4c8f8c1f01f9c2f54c87fab103c39f (patch) | |
| tree | 282b189bd2d6113bf134a8b34d7ddc518369f3bb /ZAPD/Utils | |
| parent | 469285b3e1f7885b42905fbfb9b4448f51ea20b3 (diff) | |
Exporter Support Added (#127)
* Initial exporter implementation
* Updated to use static library.
* minor cleanup
* Cleaned things up a bit
* Fixed merge issues
* Minor commenting
* Added Begin and End functions, and removed HL stuff (to be turned into an exporter at a later date)
* Cleaned some stuff up
* Additional cleanup
* Removed some commented out code
* Fixed compilation issues
* Cleanup
* Fixed merge issues
* Got rid of unused windows.h includes
* Cleanup
* Fixed warning
* Removed additional redundancies
* Cleanup
* Fixed merge issues
* Fixed some compiler issues, added makefile for exportertest.
* Removed redundancies and clang formatted
* Made sure exportertest compiles with C++17
* Moved certain files into new "Utils" folder.
* GetExporterMap uses a reference now
* Minor fixes and updates.
Co-authored-by: Jack Walker <7463599+Jack-Walker@users.noreply.github.com>
Diffstat (limited to 'ZAPD/Utils')
| -rw-r--r-- | ZAPD/Utils/BinaryWriter.cpp | 95 | ||||
| -rw-r--r-- | ZAPD/Utils/BinaryWriter.h | 35 | ||||
| -rw-r--r-- | ZAPD/Utils/BitConverter.h | 161 | ||||
| -rw-r--r-- | ZAPD/Utils/Directory.h | 39 | ||||
| -rw-r--r-- | ZAPD/Utils/File.h | 78 | ||||
| -rw-r--r-- | ZAPD/Utils/MemoryStream.cpp | 90 | ||||
| -rw-r--r-- | ZAPD/Utils/MemoryStream.h | 32 | ||||
| -rw-r--r-- | ZAPD/Utils/Path.h | 53 | ||||
| -rw-r--r-- | ZAPD/Utils/Stream.h | 32 | ||||
| -rw-r--r-- | ZAPD/Utils/StringHelper.h | 116 |
10 files changed, 731 insertions, 0 deletions
diff --git a/ZAPD/Utils/BinaryWriter.cpp b/ZAPD/Utils/BinaryWriter.cpp new file mode 100644 index 0000000..a48d40d --- /dev/null +++ b/ZAPD/Utils/BinaryWriter.cpp @@ -0,0 +1,95 @@ +#include "BinaryWriter.h" + +BinaryWriter::BinaryWriter(Stream* nStream) +{ + stream.reset(nStream); +} + +BinaryWriter::BinaryWriter(std::shared_ptr<Stream> nStream) +{ + stream = nStream; +} + +void BinaryWriter::Close() +{ + stream->Close(); +} + +std::shared_ptr<Stream> BinaryWriter::GetStream() +{ + return stream; +} + +uint64_t BinaryWriter::GetBaseAddress() +{ + return stream->GetBaseAddress(); +} + +uint64_t BinaryWriter::GetLength() +{ + return stream->GetLength(); +} + +void BinaryWriter::Seek(int32_t offset, SeekOffsetType seekType) +{ + stream->Seek(offset, seekType); +} + +void BinaryWriter::Write(int8_t value) +{ + stream->Write((char*)&value, sizeof(int8_t)); +} + +void BinaryWriter::Write(uint8_t value) +{ + stream->Write((char*)&value, sizeof(uint8_t)); +} + +void BinaryWriter::Write(int16_t value) +{ + stream->Write((char*)&value, sizeof(int16_t)); +} + +void BinaryWriter::Write(uint16_t value) +{ + stream->Write((char*)&value, sizeof(uint16_t)); +} + +void BinaryWriter::Write(int32_t value) +{ + stream->Write((char*)&value, sizeof(int32_t)); +} + +void BinaryWriter::Write(uint32_t value) +{ + stream->Write((char*)&value, sizeof(uint32_t)); +} + +void BinaryWriter::Write(int64_t value) +{ + stream->Write((char*)&value, sizeof(int64_t)); +} + +void BinaryWriter::Write(uint64_t value) +{ + stream->Write((char*)&value, sizeof(uint64_t)); +} + +void BinaryWriter::Write(float value) +{ + stream->Write((char*)&value, sizeof(float)); +} + +void BinaryWriter::Write(double value) +{ + stream->Write((char*)&value, sizeof(double)); +} + +void BinaryWriter::Write(std::string str) +{ + int strLen = str.size(); + stream->Write((char*)&strLen, sizeof(int)); + + for (char c : str) + stream->WriteByte(c); +} diff --git a/ZAPD/Utils/BinaryWriter.h b/ZAPD/Utils/BinaryWriter.h new file mode 100644 index 0000000..e187b8c --- /dev/null +++ b/ZAPD/Utils/BinaryWriter.h @@ -0,0 +1,35 @@ +#pragma once + +#include <array> +#include <memory> +#include <string> +#include <vector> +#include "Stream.h" + +class BinaryWriter +{ +public: + BinaryWriter(Stream* nStream); + BinaryWriter(std::shared_ptr<Stream> nStream); + + std::shared_ptr<Stream> GetStream(); + uint64_t GetBaseAddress(); + uint64_t GetLength(); + void Seek(int32_t offset, SeekOffsetType seekType); + void Close(); + + void Write(int8_t value); + void Write(uint8_t value); + void Write(int16_t value); + void Write(uint16_t value); + void Write(int32_t value); + void Write(uint32_t value); + void Write(int64_t value); + void Write(uint64_t value); + void Write(float value); + void Write(double value); + void Write(std::string str); + +protected: + std::shared_ptr<Stream> stream; +};
\ No newline at end of file diff --git a/ZAPD/Utils/BitConverter.h b/ZAPD/Utils/BitConverter.h new file mode 100644 index 0000000..5cca35b --- /dev/null +++ b/ZAPD/Utils/BitConverter.h @@ -0,0 +1,161 @@ +#pragma once + +#include <limits> +#include <stdint.h> +#include <vector> + +class BitConverter +{ +public: + static inline int8_t ToInt8BE(const uint8_t* data, int32_t offset) + { + return (uint8_t)data[offset + 0]; + } + + static inline int8_t ToInt8BE(const std::vector<uint8_t>& data, int32_t offset) + { + return (uint8_t)data[offset + 0]; + } + + static inline uint8_t ToUInt8BE(const uint8_t* data, int32_t offset) + { + return (uint8_t)data[offset + 0]; + } + + static inline uint8_t ToUInt8BE(const std::vector<uint8_t>& data, int32_t offset) + { + return (uint8_t)data[offset + 0]; + } + + static inline int16_t ToInt16BE(const uint8_t* data, int32_t offset) + { + return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1]; + } + + static inline int16_t ToInt16BE(const std::vector<uint8_t>& data, int32_t offset) + { + return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1]; + } + + static inline uint16_t ToUInt16BE(const uint8_t* data, int32_t offset) + { + return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1]; + } + + static inline uint16_t ToUInt16BE(const std::vector<uint8_t>& data, int32_t offset) + { + return ((uint16_t)data[offset + 0] << 8) + (uint16_t)data[offset + 1]; + } + + static inline int32_t ToInt32BE(const uint8_t* data, int32_t offset) + { + return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) + + ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3]; + } + + static inline int32_t ToInt32BE(const std::vector<uint8_t>& data, int32_t offset) + { + return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) + + ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3]; + } + + static inline uint32_t ToUInt32BE(const uint8_t* data, int32_t offset) + { + return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) + + ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3]; + } + + static inline uint32_t ToUInt32BE(const std::vector<uint8_t>& data, int32_t offset) + { + return ((uint32_t)data[offset + 0] << 24) + ((uint32_t)data[offset + 1] << 16) + + ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3]; + } + + static inline int64_t ToInt64BE(const uint8_t* data, int32_t offset) + { + return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) + + ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) + + ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) + + ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]); + } + + static inline int64_t ToInt64BE(const std::vector<uint8_t>& data, int32_t offset) + { + return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) + + ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) + + ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) + + ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]); + } + + static inline uint64_t ToUInt64BE(const uint8_t* data, int32_t offset) + { + return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) + + ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) + + ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) + + ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]); + } + + static inline uint64_t ToUInt64BE(const std::vector<uint8_t>& data, int32_t offset) + { + return ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) + + ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) + + ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) + + ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]); + } + + static inline float ToFloatBE(const uint8_t* data, int32_t offset) + { + float value; + uint32_t floatData = ((uint32_t)data[offset + 0] << 24) + + ((uint32_t)data[offset + 1] << 16) + + ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3]; + static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } + + static inline float ToFloatBE(const std::vector<uint8_t>& data, int32_t offset) + { + float value; + uint32_t floatData = ((uint32_t)data[offset + 0] << 24) + + ((uint32_t)data[offset + 1] << 16) + + ((uint32_t)data[offset + 2] << 8) + (uint32_t)data[offset + 3]; + static_assert(sizeof(uint32_t) == sizeof(float), "expected 32-bit float"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } + + static inline double ToDoubleBE(const uint8_t* data, int32_t offset) + { + double value; + uint64_t floatData = + ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) + + ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) + + ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) + + ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]); + static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double"); + // Checks if the float format on the platform the ZAPD binary is running on supports the + // same float format as the object file. + static_assert(std::numeric_limits<float>::is_iec559, + "expected IEC559 floats on host machine"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } + + static inline double ToDoubleBE(const std::vector<uint8_t>& data, int32_t offset) + { + double value; + uint64_t floatData = + ((uint64_t)data[offset + 0] << 56) + ((uint64_t)data[offset + 1] << 48) + + ((uint64_t)data[offset + 2] << 40) + ((uint64_t)data[offset + 3] << 32) + + ((uint64_t)data[offset + 4] << 24) + ((uint64_t)data[offset + 5] << 16) + + ((uint64_t)data[offset + 6] << 8) + ((uint64_t)data[offset + 7]); + static_assert(sizeof(uint64_t) == sizeof(double), "expected 64-bit double"); + // Checks if the float format on the platform the ZAPD binary is running on supports the + // same float format as the object file. + static_assert(std::numeric_limits<double>::is_iec559, + "expected IEC559 doubles on host machine"); + std::memcpy(&value, &floatData, sizeof(value)); + return value; + } +}; diff --git a/ZAPD/Utils/Directory.h b/ZAPD/Utils/Directory.h new file mode 100644 index 0000000..a266487 --- /dev/null +++ b/ZAPD/Utils/Directory.h @@ -0,0 +1,39 @@ +#pragma once + +#include <iostream> +#include <string> +#include <vector> + +#if __has_include(<filesystem>) +#include <filesystem> +namespace fs = std::filesystem; +#else +#include <experimental/filesystem> +namespace fs = std::experimental::filesystem; +#endif + +#include "Utils/StringHelper.h" + +class Directory +{ +public: + static std::string GetCurrentDirectory() { return fs::current_path().u8string(); } + + static bool Exists(const fs::path& path) { return fs::exists(path); } + + static void CreateDirectory(const std::string& path) + { + std::string curPath = ""; + std::vector<std::string> split = StringHelper::Split(path, "/"); + + for (std::string s : split) + { + curPath += s + "/"; + + if (!Exists(curPath)) + fs::create_directory(curPath); + } + + // fs::create_directory(path); + } +}; diff --git a/ZAPD/Utils/File.h b/ZAPD/Utils/File.h new file mode 100644 index 0000000..e3f8880 --- /dev/null +++ b/ZAPD/Utils/File.h @@ -0,0 +1,78 @@ +#pragma once + +#include <fstream> +#include <iostream> +#include <stdio.h> +#include <string> +#include <vector> +#include "Directory.h" +#include "Utils/StringHelper.h" + +class File +{ +public: + static bool Exists(const fs::path& filePath) + { + std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); + return file.good(); + } + + static std::vector<uint8_t> ReadAllBytes(const fs::path& filePath) + { + std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); + int32_t fileSize = (int32_t)file.tellg(); + file.seekg(0); + char* data = new char[fileSize]; + file.read(data, fileSize); + std::vector<uint8_t> result = std::vector<uint8_t>(data, data + fileSize); + delete[] data; + + return result; + }; + + static std::string ReadAllText(const fs::path& filePath) + { + std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); + int32_t fileSize = (int32_t)file.tellg(); + file.seekg(0); + char* data = new char[fileSize + 1]; + memset(data, 0, fileSize + 1); + file.read(data, fileSize); + std::string str = std::string((const char*)data); + delete[] data; + + return str; + }; + + static std::vector<std::string> ReadAllLines(const fs::path& filePath) + { + std::string text = ReadAllText(filePath); + std::vector<std::string> lines = StringHelper::Split(text, "\n"); + + return lines; + }; + + static void WriteAllBytes(const fs::path& filePath, const std::vector<uint8_t>& data) + { + std::ofstream file(filePath, std::ios::binary); + file.write((char*)data.data(), data.size()); + }; + + static void WriteAllBytes(const std::string& filePath, const std::vector<char>& data) + { + std::ofstream file(filePath, std::ios::binary); + file.write((char*)data.data(), data.size()); + }; + + static void WriteAllBytes(const std::string& filePath, const char* data, int dataSize) + { + std::ofstream file(filePath, std::ios::binary); + file.write((char*)data, dataSize); + }; + + static void WriteAllText(const fs::path& filePath, const std::string& text) + { + std::ofstream file(filePath, std::ios::out); + file.write(text.c_str(), text.size()); + } +}; diff --git a/ZAPD/Utils/MemoryStream.cpp b/ZAPD/Utils/MemoryStream.cpp new file mode 100644 index 0000000..6c940be --- /dev/null +++ b/ZAPD/Utils/MemoryStream.cpp @@ -0,0 +1,90 @@ +#include "MemoryStream.h" +#include <string.h> + +#ifndef _MSC_VER +#define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize) +#endif + +MemoryStream::MemoryStream() +{ + buffer = std::vector<char>(); + bufferSize = 0; + baseAddress = 0; +} + +MemoryStream::MemoryStream(char* nBuffer, size_t nBufferSize) : MemoryStream() +{ + buffer = std::vector<char>(nBuffer, nBuffer + nBufferSize); + bufferSize = nBufferSize; + baseAddress = 0; +} + +MemoryStream::~MemoryStream() +{ +} + +uint64_t MemoryStream::GetLength() +{ + return buffer.size(); +} + +void MemoryStream::Seek(int32_t offset, SeekOffsetType seekType) +{ + if (seekType == SeekOffsetType::Start) + baseAddress = offset; + else if (seekType == SeekOffsetType::Current) + baseAddress += offset; + else if (seekType == SeekOffsetType::End) + baseAddress = bufferSize - 1 - offset; +} + +std::unique_ptr<char[]> MemoryStream::Read(size_t length) +{ + std::unique_ptr<char[]> result = std::make_unique<char[]>(length); + + memcpy_s(result.get(), length, &buffer[baseAddress], length); + baseAddress += length; + + return result; +} + +int8_t MemoryStream::ReadByte() +{ + return buffer[baseAddress++]; +} + +void MemoryStream::Write(char* srcBuffer, size_t length) +{ + if (baseAddress + length >= buffer.size()) + { + buffer.resize(baseAddress + length); + bufferSize += length; + } + + memcpy_s(&buffer[baseAddress], length, srcBuffer, length); + baseAddress += length; +} + +void MemoryStream::WriteByte(int8_t value) +{ + if (baseAddress >= buffer.size()) + { + buffer.resize(baseAddress + 1); + bufferSize = baseAddress; + } + + buffer[baseAddress++] = value; +} + +std::vector<char> MemoryStream::ToVector() +{ + return buffer; +} + +void MemoryStream::Flush() +{ +} + +void MemoryStream::Close() +{ +}
\ No newline at end of file diff --git a/ZAPD/Utils/MemoryStream.h b/ZAPD/Utils/MemoryStream.h new file mode 100644 index 0000000..cc24315 --- /dev/null +++ b/ZAPD/Utils/MemoryStream.h @@ -0,0 +1,32 @@ +#pragma once + +#include <memory> +#include <vector> +#include "Stream.h" + +class MemoryStream : public Stream +{ +public: + MemoryStream(); + MemoryStream(char* nBuffer, size_t nBufferSize); + ~MemoryStream(); + + uint64_t GetLength() override; + + void Seek(int32_t offset, SeekOffsetType seekType); + + std::unique_ptr<char[]> Read(size_t length); + int8_t ReadByte(); + + void Write(char* srcBuffer, size_t length); + void WriteByte(int8_t value); + + std::vector<char> ToVector(); + + void Flush(); + void Close(); + +protected: + std::vector<char> buffer; + std::size_t bufferSize; +};
\ No newline at end of file diff --git a/ZAPD/Utils/Path.h b/ZAPD/Utils/Path.h new file mode 100644 index 0000000..fd3c658 --- /dev/null +++ b/ZAPD/Utils/Path.h @@ -0,0 +1,53 @@ +#pragma once + +#include <iostream> +#include <string> +#include "Utils/StringHelper.h" + +#if __has_include(<filesystem>) +#include <filesystem> +namespace fs = std::filesystem; +#else +#include <experimental/filesystem> +namespace fs = std::experimental::filesystem; +#endif + +class Path +{ +public: + static std::string GetFileName(const std::string& input) + { + std::vector<std::string> split = StringHelper::Split(input, "/"); + return split[split.size() - 1]; + }; + + static std::string GetFileNameWithoutExtension(const std::string& input) + { + std::vector<std::string> split = StringHelper::Split(input, "/"); + return split[split.size() - 1].substr(0, split[split.size() - 1].find_last_of(".")); + }; + + static std::string GetFileNameExtension(const std::string& input) + { + return input.substr(input.find_last_of("."), input.length()); + }; + + static std::string GetPath(const std::string& input) + { + std::vector<std::string> split = StringHelper::Split(input, "/"); + std::string output = ""; + + for (std::string str : split) + { + if (str.find_last_of(".") == std::string::npos) + output += str + "/"; + } + + return output; + }; + + static std::string GetDirectoryName(const fs::path& path) + { + return path.parent_path().u8string(); + }; +}; diff --git a/ZAPD/Utils/Stream.h b/ZAPD/Utils/Stream.h new file mode 100644 index 0000000..facb710 --- /dev/null +++ b/ZAPD/Utils/Stream.h @@ -0,0 +1,32 @@ +#pragma once + +#include <memory> +#include <stdint.h> + +enum class SeekOffsetType +{ + Start, + Current, + End +}; + +class Stream +{ +public: + virtual uint64_t GetLength() = 0; + uint64_t GetBaseAddress() { return baseAddress; } + + virtual void Seek(int32_t offset, SeekOffsetType seekType) = 0; + + virtual std::unique_ptr<char[]> Read(size_t length) = 0; + virtual int8_t ReadByte() = 0; + + virtual void Write(char* destBuffer, size_t length) = 0; + virtual void WriteByte(int8_t value) = 0; + + virtual void Flush() = 0; + virtual void Close() = 0; + +protected: + uint64_t baseAddress; +};
\ No newline at end of file diff --git a/ZAPD/Utils/StringHelper.h b/ZAPD/Utils/StringHelper.h new file mode 100644 index 0000000..26516d0 --- /dev/null +++ b/ZAPD/Utils/StringHelper.h @@ -0,0 +1,116 @@ +#pragma once + +#include <algorithm> +#include <cstring> +#include <numeric> +#include <stdarg.h> +#include <string> +#include <vector> + +#ifndef __PRETTY_FUNCTION__ +#ifdef _MSC_VER +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#else +#define __PRETTY_FUNCTION__ __func__ +#endif +#endif + +class StringHelper +{ +public: + static std::vector<std::string> Split(std::string s, const std::string& delimiter) + { + std::vector<std::string> result; + + size_t pos = 0; + std::string token; + + while ((pos = s.find(delimiter)) != std::string::npos) + { + token = s.substr(0, pos); + result.push_back(token); + s.erase(0, pos + delimiter.length()); + } + + if (s.length() != 0) + result.push_back(s); + + return result; + } + + static std::string Strip(std::string s, const std::string& delimiter) + { + size_t pos = 0; + std::string token; + + while ((pos = s.find(delimiter)) != std::string::npos) + { + token = s.substr(0, pos); + s.erase(pos, pos + delimiter.length()); + } + + return s; + } + + static std::string Replace(std::string str, const std::string& from, const std::string& to) + { + size_t start_pos = str.find(from); + + if (start_pos == std::string::npos) + return str; + + str.replace(start_pos, from.length(), to); + return str; + } + + static bool StartsWith(const std::string& s, const std::string& input) + { + return s.rfind(input, 0) == 0; + } + + static bool Contains(const std::string& s, const std::string& input) + { + return s.find(input) != std::string::npos; + } + + static bool EndsWith(const std::string& s, const std::string& input) + { + size_t inputLen = strlen(input.c_str()); + return s.rfind(input) == (s.size() - inputLen); + } + + static std::string Sprintf(const char* format, ...) + { + char buffer[32768]; + // char buffer[2048]; + std::string output = ""; + va_list va; + + va_start(va, format); + vsprintf(buffer, format, va); + va_end(va); + + output = buffer; + return output; + } + + static std::string Implode(std::vector<std::string>& elements, const char* const separator) + { + return std::accumulate(std::begin(elements), std::end(elements), std::string(), + [separator](std::string& ss, std::string& s) { + return ss.empty() ? s : ss + separator + s; + }); + } + + static int64_t StrToL(const std::string& str, int32_t base = 10) + { + return std::strtoull(str.c_str(), nullptr, base); + } + + static std::string BoolStr(bool b) { return b ? "true" : "false"; } + + static bool HasOnlyDigits(const std::string& str) + { + return std::all_of(str.begin(), str.end(), ::isdigit); + } +}; |
