#pragma once
/*
GameEngine and Editor
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Utilities
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iostream>
#include <fstream>
#include <algorithm>
namespace Utilities {
struct SizedArray
{
const uint8_t* data;
size_t size;
};
template <size_t N>
SizedArray make_sized_array(const uint8_t (&array)[N])
{
return SizedArray{array, N};
}
template <typename ...T>
void fail(const char* fmt, T... args)
{
printf(fmt, args...);
exit(-1);
}
template <typename T>
T clamp(T val, T min, T max)
{
return std::min(std::max(val, min), max);
}
// https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path
template<class T>
T base_name(T const & path, T const & delims = "/\\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T file_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(p) : T();
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
template<class T>
uint32_t to_uint32(T const & str)
{
return std::stoul(str, nullptr, 0);
}
template<class T>
int32_t to_int32(T const & str)
{
return std::stol(str, nullptr, 0);
}
template<class T>
uint64_t to_uint64(T const & str)
{
return std::stoull(str, nullptr, 0);
}
template<class T>
int64_t to_int64(T const & str)
{
return std::stoll(str, nullptr, 0);
}
template<class T>
float to_float(T const & str)
{
return std::stof(str, nullptr);
}
template<class T>
double to_double(T const & str)
{
return std::stod(str, nullptr);
}
// N is size without the NUL terminator
template <size_t N>
class FixedString
{
public:
FixedString()
: m_len(0)
{
}
FixedString(const char (&array)[N+1])
: m_len(N)
{
::memcpy(m_array, array, N);
m_array[N] = 0;
}
size_t size()
{
assert(m_len <= N);
return m_len; // return the size of the string without NUL terminator
}
const char* c_str()
{
return m_array;
}
template <size_t M>
FixedString<N+M-1> operator+(const char (&array)[M])
{
FixedString<N+M-1> ret;
::memcpy(ret.m_array, m_array, m_len);
::memcpy(ret.m_array + m_len, array, M-1);
ret.m_len = m_len + M - 1;
ret.m_array[ret.m_len] = 0;
return ret;
}
template <size_t M>
FixedString<N+M> operator+(FixedString<M> str)
{
FixedString<N+M> ret;
::memcpy(ret.m_array, m_array, m_len);
::memcpy(ret.m_array + m_len, str.m_array, M);
ret.m_len = m_len + M;
ret.m_array[N+M] = 0;
return ret;
}
private:
template <size_t M>
friend class FixedString;
size_t m_len;
char m_array[N+1]; // +1 for space to add a NUL terminator
};
template <size_t N>
FixedString<N-1> make_fixed_string(const char (&array)[N])
{
return FixedString<N-1>(array);
}
template <typename K, typename T>
void GetKeys(std::unordered_set<K>& outSet, const std::unordered_map<K,T>& inMap)
{
outSet.clear();
for (const auto& pair : inMap)
outSet.insert(pair.first);
}
template <typename T>
void Union(std::unordered_set<T> &outSet,
const std::unordered_set<T> &inSet1,
const std::unordered_set<T> &inSet2)
{
outSet.clear();
outSet.insert(inSet1.begin(), inSet1.end());
outSet.insert(inSet2.begin(), inSet2.end());
}
template <typename T>
void Intersection(std::unordered_set<T>& outSet, const std::unordered_set<T> &inSet1, const std::unordered_set<T> &inSet2)
{
if (inSet2.size() < inSet1.size())
return Intersection(outSet, inSet2, inSet1);
outSet.clear();
for (auto& item : inSet1)
if (inSet2.find(item) != inSet2.end())
outSet.insert(item);
}
template <typename T>
void Difference(std::unordered_set<T>& outSet, const std::unordered_set<T> &inSet1, const std::unordered_set<T> &inSet2)
{
outSet.clear();
for (auto& item : inSet1)
if (inSet2.find(item) == inSet2.end())
outSet.insert(item);
}
static inline
std::vector<uint8_t> ReadFile(const std::string& filename)
{
std::vector<uint8_t> buffer;
std::ifstream file(filename, std::ios::ate | std::ios::binary);
if (file.is_open())
{
buffer.resize((size_t)file.tellg());
file.seekg(0);
file.read((char*)buffer.data(), buffer.size());
file.close();
}
else
{
fprintf(stderr, "failed to open file!");
}
return buffer;
}
} // namespace Utilities