Skip to content

Instantly share code, notes, and snippets.

@RadAd
Last active May 15, 2024 01:46
Show Gist options
  • Save RadAd/7a94f570d7ea1df07f0eff4cb6d46841 to your computer and use it in GitHub Desktop.
Save RadAd/7a94f570d7ea1df07f0eff4cb6d46841 to your computer and use it in GitHub Desktop.
CppExtras

Cpp utilities.

#pragma once
#include <string_view>
#include <algorithm>
#include <cctype>
#include <cwctype>
inline int CompareNoCase(std::string_view a, std::string_view b)
{
auto r = std::mismatch(a.begin(), a.end(), b.begin(), b.end(), [](auto ca, auto cb) { return std::tolower(ca) == std::tolower(cb); });
if (r.first == a.end() && r.second == b.end())
return 0;
else if (r.first == a.end())
return -1;
else if (r.second == b.end())
return 1;
else
return [](auto a, auto b) { return (a > b) - (a < b); } (std::tolower(*r.first), std::tolower(*r.second));
}
inline int CompareNoCase(std::wstring_view a, std::wstring_view b)
{
auto r = std::mismatch(a.begin(), a.end(), b.begin(), b.end(), [](auto ca, auto cb) { return std::towlower(ca) == std::towlower(cb); });
if (r.first == a.end() && r.second == b.end())
return 0;
else if (r.first == a.end())
return -1;
else if (r.second == b.end())
return 1;
else
return [](auto a, auto b) { return (a > b) - (a < b); } (std::towlower(*r.first), std::towlower(*r.second));
}
inline bool EqualNoCase(std::string_view a, std::string_view b)
{
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](auto ca, auto cb){ return std::tolower(ca) == std::tolower(cb); });
}
inline bool EqualNoCase(std::wstring_view a, std::wstring_view b)
{
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](auto ca, auto cb) { return std::towlower(ca) == std::towlower(cb); });
}
inline size_t FindNoCase(std::string_view haystack, std::string_view needle)
{
auto it = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](char ch1, char ch2) { return std::tolower(ch1) == std::tolower(ch2); });
return (it == haystack.end()) ? std::wstring_view::npos : (it - haystack.begin());
}
inline size_t FindNoCase(std::wstring_view haystack, std::wstring_view needle)
{
auto it = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](wchar_t ch1, wchar_t ch2) { return std::towlower(ch1) == std::towlower(ch2); });
return (it == haystack.end()) ? std::wstring_view::npos : (it - haystack.begin());
}
#include <cstdio>
#include <memory>
struct FileDeleter
{
void operator()(FILE* f) const noexcept { std::fclose(f); }
};
typedef std::unique_ptr<FILE, FileDeleter> FilePtr;
template <class T, class U>
class unique_ptr_ptr
{
public:
typedef std::unique_ptr<T, U> unique_ptr;
unique_ptr_ptr(unique_ptr& up)
: up(up), p(nullptr)
{
}
~unique_ptr_ptr()
{
up.reset(p);
}
operator typename unique_ptr::pointer*()
{
return &p;
}
private:
unique_ptr& up;
typename unique_ptr::pointer p;
};
template <class T, class U>
unique_ptr_ptr<T, U> p(std::unique_ptr<T, U>& up)
{
return unique_ptr_ptr<T, U>(up);
}
template<class T, class U>
typename unique_ptr_ptr<T, U> operator&(std::unique_ptr<T, U>& up)
{
return unique_ptr_ptr<T, U>(up);
}
#ifdef TEST
int main()
{
FilePtr fp;
fopen_s(p(fp), "test.txt", "r");
printf("Hello World");
}
#endif
#pragma once
#include "Window.h"
#include <memory>
// Auto convert to underlying pointer
template<class d>
struct unique_ptr : public std::unique_ptr<typename d::pointer, d>
{
using std::unique_ptr<typename d::pointer, d>::unique_ptr;
using std::unique_ptr<typename d::pointer, d>::get;
operator typename d::pointer() const { return get(); }
};
#if 0 // Cant use a function as a template parameter
template <class T, void(F*)(T*)>
struct deleter_function
{
void operator()(T* t) { F(t); }
};
#endif
#define DefineDeleter(t, f) \
struct t##Deleter \
{ \
typedef t pointer; \
void operator()(t h) { f(h); } \
}; \
typedef unique_ptr<t##Deleter> t##Ptr
DefineDeleter(HDC, DeleteDC);
DefineDeleter(HMENU, DestroyMenu);
DefineDeleter(HBITMAP, DeleteObject);
DefineDeleter(HPEN, DeleteObject);
DefineDeleter(HBRUSH, DeleteObject);
struct DCReleaser
{
struct Data
{
HWND hWnd;
HDC hDC;
operator bool() const
{
return hDC != NULL;
}
Data& operator=(HDC h)
{
hDC = h;
return *this;
}
operator HDC() const
{
return hDC;
}
};
typedef Data pointer;
void operator()(Data h)
{
ReleaseDC(h.hWnd, h.hDC);
}
};
inline unique_ptr<DCReleaser> MakeGetDC(HWND hWnd)
{
return unique_ptr<DCReleaser>({ hWnd, GetDC(hWnd) });
}
// TODO This should go in a devcontext header
struct ObjectSelecter
{
struct Data
{
HDC hDC;
HGDIOBJ hObj;
operator bool() const
{
return hObj != NULL;
}
Data& operator=(HGDIOBJ h)
{
hObj = h;
return *this;
}
operator HGDIOBJ() const
{
return hObj;
}
};
typedef Data pointer;
void operator()(Data h)
{
SelectObject(h.hDC, h.hObj);
}
};
inline unique_ptr<ObjectSelecter> SelectTempObject(HDC hDC, HGDIOBJ hObj)
{
return unique_ptr<ObjectSelecter>({ hDC, SelectObject(hDC, hObj) });
}
#include <string>
#include <cassert>
#include <cstdarg>
void Format(std::string& buffer, _In_z_ _Printf_format_string_ char const* format, va_list args)
{
int const _Result1 = _vscprintf_l(format, NULL, args);
//if (buffer.size() < _Result1 + 1)
buffer.resize(_Result1);
int const _Result2 = _vsprintf_s_l(const_cast<char*>(buffer.data()), static_cast<size_t>(_Result1) + 1, format, NULL, args);
assert(-1 != _Result2);
assert(_Result1 == _Result2);
}
void Format(std::wstring& buffer, _In_z_ _Printf_format_string_ wchar_t const* format, va_list args)
{
int const _Result1 = _vscwprintf_l(format, NULL, args);
//if (buffer.size() < _Result1 + 1)
buffer.resize(_Result1);
int const _Result2 = _vswprintf_s_l(const_cast<wchar_t*>(buffer.data()), static_cast<size_t>(_Result1) + 1, format, NULL, args);
assert(-1 != _Result2);
assert(_Result1 == _Result2);
}
void Format(std::string& buffer, _In_z_ _Printf_format_string_ char const* format, ...)
{
va_list args;
va_start(args, format);
Format(buffer, format, args);
va_end(args);
}
void Format(std::wstring& buffer, _In_z_ _Printf_format_string_ wchar_t const* format, ...)
{
va_list args;
va_start(args, format);
Format(buffer, format, args);
va_end(args);
}
std::string Format(_In_z_ _Printf_format_string_ char const* format, ...)
{
std::string buffer;
va_list args;
va_start(args, format);
Format(buffer, format, args);
va_end(args);
return buffer;
}
std::wstring Format(_In_z_ _Printf_format_string_ wchar_t const* format, ...)
{
std::wstring buffer;
va_list args;
va_start(args, format);
Format(buffer, format, args);
va_end(args);
return buffer;
}
std::string Format(_In_z_ _Printf_format_string_ const char* fmt, const tm& tm)
{
std::string str(100, '_');
std::size_t size;
while ((size = std::strftime(const_cast<char*>(str.data()), str.length() + 1, fmt, &tm)) == 0) // C++17 data returns non-const
str.resize(str.length() * 2, '_');
str.resize(size);
return str;
}
std::wstring Format(_In_z_ _Printf_format_string_ const wchar_t* fmt, const tm& tm)
{
std::wstring str(100, L'_');
std::size_t size;
while ((size = std::wcsftime(const_cast<wchar_t*>(str.data()), str.length() + 1, fmt, &tm)) == 0) // C++17 data returns non-const
str.resize(str.length() * 2, L'_');
str.resize(size);
return str;
}
struct program
{
z_string_view<char> name;
const range<z_string_view<char>*> args;
};
int start(program p);
inline int start(int argc, const char* argv[])
{
z_string_view<char>* const args = reinterpret_cast<z_string_view<char>*>(argv);
return start({ args[0], { args + 1, args + argc } });
}
#include <utility>
template <class A, class B = A>
class range : public std::pair<A, B>
{
public:
using std::pair<A, B>::pair;
auto& begin() { return this->first; }
auto& end() { return this->second; }
auto& begin() const { return this->first; }
auto& end() const { return this->second; }
bool empty() const { return begin() == end(); }
size_t size() const { return std::distance(begin(), end()); }
range take(size_t count) const
{
if (size() > count)
return range(begin(), std::next(begin(), count));
else
return *this;
}
range drop(size_t count) const
{
if (size() > count)
return { std::next(begin(), count), end() };
else
return { end(), end() };
}
};
template <class A, class B>
auto make_range(const A& a, const B& b)
{
return range<A, B>(a, b);
}
template <class T>
auto make_range(const T& t)
{
return make_range(std::begin(t), std::end(t));
}
// index range
class index_iterator
{
public:
index_iterator(size_t i)
: i(i)
{
}
size_t index() const { return i; }
index_iterator& operator++()
{
++i;
return *this;
}
index_iterator operator++(int)
{
size_t r = i++;
return index_iterator(r);
}
size_t operator*() const
{
return i;
}
private:
size_t i;
};
bool operator!=(index_iterator it1, index_iterator it2)
{
return it1.index() != it2.index();
}
template <class T>
range<index_iterator, index_iterator> index(const T& t)
{
return { 0, t.size() };
}
#include <type_traits>
template <class T>
class creverse
{
public:
creverse(T& t)
: m_t(t)
{ }
using iterator = std::conditional_t<std::is_const_v<T>, typename T::const_reverse_iterator, typename T::reverse_iterator>;
using const_iterator = typename T::const_reverse_iterator;
iterator begin() { return m_t.rbegin(); }
iterator end() { return m_t.rend(); }
const_iterator cbegin() const { return m_t.crbegin(); }
const_iterator cend() const { return m_t.crend(); }
const_iterator begin() const { return m_t.rbegin(); }
const_iterator end() const { return m_t.rend(); }
private:
T& m_t;
};
template <class T>
inline creverse<T> reverse(T& t)
{
return { t };
}
template <class T>
class crngiota
{
public:
crngiota(const T& begin, const T& end)
: m_begin(begin), m_end(end)
{
}
class iterator
{
public:
iterator(const T& i)
: m_i(i)
{
}
iterator operator++()
{
++m_i;
return *this;
}
bool operator!=(const iterator& other) const
{
return m_i != other.m_i;
}
const T& operator*() const
{
return m_i;
}
private:
T m_i;
};
iterator begin() { return m_begin; }
iterator end() { return m_end; }
private:
const T& m_begin;
const T& m_end;
};
template <class T>
crngiota<T> rngiota(const T& begin, const T& end)
{
return { begin, end };
}
#include <utility>
#include <functional>
#include <cassert>
template <class T, class U>
struct rngpairit : public std::pair<T, U>
{
rngpairit(T t, U u)
: std::pair<T, U>(t, u)
{
}
rngpairit& operator++()
{
// TODO Should only increment if not equal to end
++this->first;
++this->second;
return *this;
}
const auto operator *()
{
return std::make_pair(std::ref(*this->first), std::ref(*this->second));
}
};
template <class T, class U>
bool operator !=(const rngpairit<T, U>& i1, const rngpairit<T, U>& i2)
{
return i1.first != i2.first || i1.second != i2.second;
}
template <class T, class U>
rngpairit<T, U> make_rngpairit(T t, U u)
{
return { t, u };
}
template <class T, class U>
struct rngpair : public std::pair<T&, U&>
{
rngpair(T& t, U& u)
: std::pair<T&, U&>(t, u)
{
assert(this->first.size() == this->second.size());
}
auto begin()
{
return make_rngpairit(this->first.begin(), this->second.begin());
}
auto end()
{
return make_rngpairit(this->first.end(), this->second.end());
}
};
template <class T, class U>
rngpair<T, U> make_rngpair(T& t, U& u)
{
return { t, u };
}
#define TEST
#ifdef TEST
#include <vector>
#include <cstdio>
void test()
{
std::vector<int> a = { 1, 6, 8 };
std::vector<float> b = { 3.6f, 6.3f, 7.3f };
printf("Start\n");
for (auto& item : make_rngpair(a, b))
{
printf("%d\t%f\n", item.first, item.second);
}
}
int main()
{
test();
return 0;
}
#endif
#include <string>
#include <vector>
#include <sstream>
inline bool 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 false;
str.replace(start_pos, from.length(), to);
return true;
}
inline void replaceAll(std::string& str, const std::string& from, const std::string& to)
{
size_t start_pos = str.find(from);
while (start_pos != std::string::npos)
{
str.replace(start_pos, from.length(), to);
start_pos = str.find(from, start_pos + to.length());
}
}
inline std::vector<std::tstring> split(const std::tstring& str, TCHAR delim)
{
std::vector<std::tstring> split;
std::tstringstream ss(str);
std::tstring sstr;
while (std::getline(ss, sstr, delim))
//if (!sstr.empty())
split.push_back(sstr);
return split;
}
inline LPCTSTR strBegin(LPCTSTR s) { return s; }
inline LPCTSTR strEnd(LPCTSTR s) { return s + lstrlen(s); }
inline bool StrFindI(LPCTSTR s1, LPCTSTR s2)
{
auto it = std::search(
strBegin(s1), strEnd(s1),
strBegin(s2), strEnd(s2),
[](TCHAR ch1, TCHAR ch2) { return std::toupper(ch1) == std::toupper(ch2); }
);
return (it != strEnd(s1));
}
#include <cstdint>
template <unsigned int N, bool S> struct n_int;
template<>
struct n_int<1, true> { typedef int8_t t; };
template<>
struct n_int<2, true> { typedef int16_t t; };
template<>
struct n_int<4, true> { typedef int32_t t; };
template<>
struct n_int<8, true> { typedef int64_t t; };
template<>
struct n_int<1, false> { typedef uint8_t t; };
template<>
struct n_int<2, false> { typedef uint16_t t; };
template<>
struct n_int<4, false> { typedef uint32_t t; };
template<>
struct n_int<8, false> { typedef uint64_t t; };
template <unsigned int N, bool S>
using t_int = typename n_int<N, S>::t;
void test1()
{
t_int<4, true> i = 5;
}
#include <iostream>
#include <cstdint>
enum class e1 : uint32_t
{
one,
two,
three,
};
template <typename E, class enable = std::enable_if_t<std::is_enum<E>::value>>
constexpr auto operator+(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
enum class EnumFlags : uint32_t
{
};
template <typename E, class Enable = void>
class key;
class foo
{
};
template <typename E>
//class key<E, typename std::enable_if<std::is_enum<E>::value>::type> { };
class key<E, std::enable_if_t<std::is_enum<E>::value>>
{
};
int main()
{
std::cout << "Hello,World!\n";
std::cout << +e1::one << "\n";
foo f;
//+f;
return 0;
}
#include <utility>
template <class T>
decltype(auto) as_nonconst(T& v)
{
return const_cast<std::remove_const_t<T>&>(v);
}
template <class T>
decltype(auto) as_nonconst(T* v)
{
return const_cast<std::remove_const_t<T>*>(v);
}
#define TEST
#ifdef TEST
#include <cstdio>
int main()
{
volatile const int a = 5;
// a = 9;
decltype(auto) b = as_nonconst(a);
b = 7;
const int* x = new int(6);
//*x = 9;
decltype(auto) y = as_nonconst(x);
*y = 8;
printf("%d: %d %d\n", __LINE__, a, b);
printf("%d: %d %d\n", __LINE__, *x, *y);
return 0;
}
#endif
#include <windows.h>
#include <tchar.h>
#include <cstdio>
// Recommended to add this to compiler options:
// /d1trimfile:"$(SolutionDir)\":
struct SourceLocation
{
SourceLocation(int line, const TCHAR* file, const TCHAR* function, const TCHAR* funcsig)
: line(line)
, file(file)
, function(function)
, funcsig(funcsig)
{
}
int line;
const TCHAR* file;
const TCHAR* function;
const TCHAR* funcsig;
};
#define SRC_LOC SourceLocation(__LINE__, _T(__FILE__), _T(__FUNCTION__), _T(__FUNCSIG__))
inline bool Validate(HRESULT hr, const LPCTSTR test, const LPCTSTR msg, const SourceLocation& src_loc)
{
if (FAILED(hr))
{
TCHAR wszMsgBuff[512];
DWORD dwChars = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hr,
0,
wszMsgBuff,
ARRAYSIZE(wszMsgBuff),
NULL);
while (wszMsgBuff[dwChars - 1] == TEXT('\n') || wszMsgBuff[dwChars - 1] == TEXT('\r'))
--dwChars;
wszMsgBuff[dwChars] = TEXT('\0');
_ftprintf(stderr, TEXT("FAILED {%s}\n [%s(%d)]\n (%#10.8x: %s)\n %s\n"), test, src_loc.file, src_loc.line, hr, wszMsgBuff, msg);
return false;
}
else
return true;
}
inline bool ValidateIgnore(HRESULT hr, HRESULT ignore, const LPCTSTR test, const LPCTSTR msg, const SourceLocation& src_loc)
{
return hr == ignore ? true : Validate(hr, test, msg, src_loc);
}
#define CHECK_FAILED(x, m, r) if (!Validate(x, #x, m, SRC_LOC)) return r;
#define CHECK_FAILED_IGNORE(x, i, m, r) if (!ValidateIgnore(x, #x, i, m, SRC_LOC)) return r;
#define VALIDATE_TEST
#ifdef VALIDATE_TEST
HRESULT Fake()
{
return E_ACCESSDENIED;
}
int main()
{
CHECK_FAILED(Fake(), TEXT("Foo msg"), EXIT_FAILURE);
return EXIT_SUCCESS;
}
#endif
#include <cstring>
#include <cwchar>
#include <stdexcept>
struct zstring_sentinel
{
};
template <class T>
class basic_z_string_view
{
public:
using pointer_t = const T*;
using size_t = std::size_t;
using iterator = pointer_t;
basic_z_string_view(pointer_t p)
: p(p)
{
}
pointer_t c_str() const
{
return p;
}
size_t length() const;
int compare(basic_z_string_view q) const;
int ncompare(pointer_t q, size_t count) const;
int collate(pointer_t q) const;
pointer_t find(T c) const;
pointer_t rfind(T c) const;
size_t span(pointer_t q) const;
size_t cspan(pointer_t q) const;
pointer_t pbreak(pointer_t breakset) const;
pointer_t find(pointer_t q) const;
iterator begin() const { return p; }
//iterator end() const { return p + length(); }
zstring_sentinel end() const { return {}; }
const T& at(size_t i) const { if (i >= length()) throw std::out_of_range(); return p[i]; }
const T& operator[](size_t i) const { return p[i]; }
private:
pointer_t p;
};
#if 0
template <class T>
int operator<=>(basic_z_string_view<T> a, basic_z_string_view<T> b)
{
return a.compare(b);
}
#else
template <class T>
bool operator==(basic_z_string_view<T> a, basic_z_string_view<T> b)
{
return a.compare(b) == 0;
}
template <class T>
bool operator<(basic_z_string_view<T> a, basic_z_string_view<T> b)
{
return a.compare(b) < 0;
}
template <class T>
bool operator<=(basic_z_string_view<T> a, basic_z_string_view<T> b)
{
return a.compare(b) <= 0;
}
template <class T>
bool operator>(basic_z_string_view<T> a, basic_z_string_view<T> b)
{
return a.compare(b) > 0;
}
template <class T>
bool operator>=(basic_z_string_view<T> a, basic_z_string_view<T> b)
{
return a.compare(b) >= 0;
}
#endif
// ----- char
template <>
size_t basic_z_string_view<char>::length() const
{
return std::strlen(p);
}
template <>
int basic_z_string_view<char>::compare(basic_z_string_view q) const
{
return std::strcmp(p, q.p);
}
typedef basic_z_string_view<char> z_string_view;
z_string_view make_z_string_view(z_string_view::pointer_t s)
{
return s;
}
bool operator!=(z_string_view::iterator it, zstring_sentinel)
{
return *it != '\0';
}
// ----- wchar_t
template <>
size_t basic_z_string_view<wchar_t>::length() const
{
return std::wcslen(p);
}
template <>
int basic_z_string_view<wchar_t>::compare(basic_z_string_view q) const
{
return std::wcscmp(p, q.p);
}
typedef basic_z_string_view<wchar_t> z_wstring_view;
z_wstring_view make_z_string_view(z_wstring_view::pointer_t s)
{
return s;
}
bool operator!=(z_wstring_view::iterator it, zstring_sentinel)
{
return *it != L'\0';
}
#ifdef Z_STRING_TEST
int main()
{
for (auto c : z_string_view("Hello"))
printf("--- %c\n", c);
return 0;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment