Cpp utilities.
Last active
May 15, 2024 01:46
-
-
Save RadAd/7a94f570d7ea1df07f0eff4cb6d46841 to your computer and use it in GitHub Desktop.
CppExtras
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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()); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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) }); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } }); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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() }; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 }; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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)); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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