Skip to content

Instantly share code, notes, and snippets.

@gatchamix
Last active August 31, 2017 21:21
Show Gist options
  • Save gatchamix/ba7831ff43cb744d7257bc90821da285 to your computer and use it in GitHub Desktop.
Save gatchamix/ba7831ff43cb744d7257bc90821da285 to your computer and use it in GitHub Desktop.
meta-programming types and algorithms using C++17/2a
#include <type_traits>
#include <utility>
#include <cstddef>
#include <string_view>
#include <iterator>
#include <limits>
#include <tuple>
//
// Declare basic_fixed_string.
template <class charT, size_t N>
class basic_fixed_string;
// Aliases fixed_string, u16fixed_string, u32fixed_string, wfixed_string.
template <size_t N>
using fixed_string = basic_fixed_string<char, N>;
template <size_t N>
using u16fixed_string = basic_fixed_string<char16_t, N>;
template <size_t N>
using u32fixed_string = basic_fixed_string<char32_t, N>;
template <size_t N>
using wfixed_string = basic_fixed_string<wchar_t, N>;
// Creates a fixed_string from a User-Defined Literal.
template <char... chars>
auto constexpr operator ""_fs()
{
return fixed_string<sizeof...(chars)>{ {chars..., '\0'} };
}
// Creates a fixed_string from a string literal.
template <class charT, size_t N>
auto constexpr make_fixed_string(charT const (&str)[N])
{
return basic_fixed_string<charT, N - 1>{ str };
}
// Concatenations between fixed_strings and string literals.
template <class charT, size_t N, size_t M>
auto constexpr operator+(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
basic_fixed_string<charT, N + M> temp;
for (size_t i = 0; i < N; ++i) temp[i] = lhs[i];
for (size_t i = 0; i < M; ++i) temp[N + i] = rhs[i];
return temp;
}
template <class charT, size_t N1, size_t M>
auto constexpr operator+(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) + rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator+(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs + make_fixed_string(rhs);
}
// Comparisons between fixed_strings and string literals.
template <class charT, size_t N, size_t M>
auto constexpr operator==(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
if (N != M) return false;
for (size_t i = 0; i < N; ++i)
if (lhs[i] != rhs[i]) return false;
return true;
}
template <class charT, size_t N1, size_t M>
auto constexpr operator==(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) == rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator==(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs == make_fixed_string(rhs);
}
template <class charT, size_t N, size_t M>
auto constexpr operator!=(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
return !(lhs == rhs);
}
template <class charT, size_t N1, size_t M>
auto constexpr operator!=(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) != rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator!=(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs + make_fixed_string(rhs);
}
template <class charT, size_t N, size_t M>
auto constexpr operator<(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
constexpr auto K = (N < M ? N : M);
for (size_t i = 0; i < K; ++i)
if (lhs[i] < rhs[i])
return true;
else if (lhs[i] > rhs[i])
return false;
if (N == M)
return false;
else if (N < M)
return true;
else /* N > M */
return false;
}
template <class charT, size_t N1, size_t M>
auto constexpr operator<(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) < rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator<(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs < make_fixed_string(rhs);
}
template <class charT, size_t N, size_t M>
auto constexpr operator>(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
return rhs < lhs;
}
template <class charT, size_t N1, size_t M>
auto constexpr operator>(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) > rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator>(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs > make_fixed_string(rhs);
}
template <class charT, size_t N, size_t M>
auto constexpr operator<=(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
return !(rhs < lhs);
}
template <class charT, size_t N1, size_t M>
auto constexpr operator<=(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) <= rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator<=(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs <= make_fixed_string(rhs);
}
template <class charT, size_t N, size_t M>
auto constexpr operator>=(
basic_fixed_string<charT, N> const &lhs,
basic_fixed_string<charT, M> const &rhs) noexcept
{
return !(lhs < rhs);
}
template <class charT, size_t N1, size_t M>
auto constexpr operator>=(
charT const (&lhs)[N1],
basic_fixed_string<charT, M> const &rhs) noexcept
{
return make_fixed_string(lhs) >= rhs;
}
template <class charT, size_t N, size_t M1>
auto constexpr operator>=(
basic_fixed_string<charT, N> const &lhs,
charT const (&rhs)[M1]) noexcept
{
return lhs >= make_fixed_string(rhs);
}
// Swap equal size fixed_strings.
template <class charT, size_t N>
auto constexpr swap(
basic_fixed_string<charT, N> &lhs,
basic_fixed_string<charT, N> &rhs) noexcept
{
for (size_t i = 0; i < N; ++i) swap(lhs[i], rhs[i]);
}
// Convert fixed_string to integeral values.
// TODO: Implement index + base parameters
template <size_t N>
auto constexpr __sto_integral_impl(fixed_string<N> const &str, size_t pos)
{
auto val = 0ull;
for (; pos < N; ++pos)
{
val *= 10;
auto const c = str[pos];
if (c < '0' || c > '9') throw std::invalid_argument("");
auto const temp = val + static_cast<unsigned>(c - '0');
if (temp < val) throw std::invalid_argument("");
val = temp;
}
return val;
}
template <class T, size_t N>
auto constexpr __sto_unsigned_impl(fixed_string<N> const &str)
{
size_t i = 0;
if (str[0] == '+') ++i;
auto const val = __sto_integral_impl(str, i);
auto constexpr max = std::numeric_limits<T>::max();
if (val > max) throw std::out_of_range("");
return static_cast<T>(val);
}
template <class T, size_t N>
auto constexpr __sto_signed_impl(fixed_string<N> const &str)
{
if (str[0] == '-')
{
auto const val = __sto_integral_impl(str, 1);
constexpr auto min = std::numeric_limits<T>::min();
constexpr auto max = 0 - static_cast<std::make_unsigned_t<T>>(min);
if (val > max) throw std::out_of_range("");
return static_cast<T>(0 - val);
}
else
return __sto_unsigned_impl<T>(str);
}
template <size_t N>
auto constexpr stoi(fixed_string<N> const &str)
{ return __sto_signed_impl<int>(str); }
template <size_t N>
auto constexpr stou(fixed_string<N> const &str)
{ return __sto_unsigned_impl<unsigned>(str); }
template <size_t N>
auto constexpr stol(fixed_string<N> const &str)
{ return __sto_signed_impl<long>(str); }
template <size_t N>
auto constexpr stoul(fixed_string<N> const &str)
{ return __sto_unsigned_impl<unsigned long>(str); }
template <size_t N>
auto constexpr stoll(fixed_string<N> const &str)
{ return __sto_signed_impl<long long>(str); }
template <size_t N>
auto constexpr stoull(fixed_string<N> const &str)
{ return __sto_unsigned_impl<unsigned long long>(str); }
// Convert integer to decimal fixed_string.
auto constexpr __count_num_digits(unsigned long long val) noexcept
{
size_t num_digits = 0;
do { ++num_digits; val /= 10; } while (val > 0);
return num_digits;
}
template <auto val>
auto constexpr to_fixed_string() noexcept
{
if constexpr (val >= 0)
{
auto constexpr N = __count_num_digits(val);
fixed_string<N> str;
str[0] = '0';
auto remaining = val;
for (size_t pos = N - 1; remaining > 0; --pos, remaining /= 10)
str[pos] = '0' + (remaining % 10);
return str;
}
else
{ return "-" + to_fixed_string<0ull - val>(); }
}
template <class charT, size_t N>
class basic_fixed_string {
public:
using view = std::basic_string_view<charT>;
static auto constexpr npos = view::npos;
// Default constructors (copy, move, copy-asign, move-assign)
basic_fixed_string(basic_fixed_string const&) noexcept = default;
basic_fixed_string(basic_fixed_string&&) noexcept = default;
basic_fixed_string& operator=(basic_fixed_string const&) noexcept = default;
basic_fixed_string& operator=(basic_fixed_string&&) noexcept = default;
// Implicit conversion to string_view
constexpr operator view() const noexcept
{ return { data_, N }; }
// Default construct to all zeros.
constexpr basic_fixed_string() noexcept
: data_{}
{}
// Converting constructor from string literal.
constexpr basic_fixed_string(charT const (&arr)[N + 1]) noexcept
: data_{}
{
for (size_t i = 0; i < N; ++i) data_[i] = arr[i];
}
// Assign from string literal.
auto constexpr operator=(const charT(&arr)[N + 1])
{
for (size_t i = 0; i < N + 1; ++i) data_[i] = arr[i];
return *this;
}
// c/r/begin, c/r/end.
auto constexpr begin() noexcept
{ return data_; }
auto constexpr begin() const noexcept
{ return data_; }
auto constexpr end() noexcept
{ return data_ + N; }
auto constexpr end() const noexcept
{ return data_ + N; }
auto constexpr rbegin() noexcept
{ return make_reverse_iterator(end()); }
auto constexpr rbegin() const noexcept
{ return make_reverse_iterator(end()); }
auto constexpr rend() noexcept
{ return make_reverse_iterator(begin()); }
auto constexpr rend() const noexcept
{ return make_reverse_iterator(begin()); }
auto constexpr cbegin() const noexcept
{ return data_; }
auto constexpr cend() const noexcept
{ return data_ + N; }
auto constexpr crbegin() const noexcept
{ return make_reverse_iterator(end()); }
auto constexpr crend() const noexcept
{ return make_reverse_iterator(begin()); }
// size, empty, length.
auto constexpr size() const noexcept
{ return N; }
auto constexpr empty() const noexcept
{ return N == 0; }
auto constexpr length() const noexcept
{ return N; }
// str[pos]
auto constexpr& operator[](size_t pos) noexcept
{ return data_[pos]; }
auto constexpr& operator[](size_t pos) const noexcept
{ return data_[pos]; }
// str.at(pos)
auto constexpr& at(size_t pos)
{
if (pos >= N) throw std::out_of_range("");
return data_[pos];
}
auto constexpr& at(size_t pos) const
{
if (pos >= N) throw std::out_of_range("");
return data_[pos];
}
// front, back.
auto constexpr& front() const noexcept
{ return data_[0]; }
auto constexpr& front() noexcept
{ return data_[0]; }
auto constexpr& back() const noexcept
{ return data_[N - 1]; }
auto constexpr& back() noexcept
{ return data_[N - 1]; }
private:
static auto constexpr __substr_length(size_t pos, size_t count)
{
if (pos >= N)
return static_cast<size_t>(0);
else if (count == npos || pos + count > N)
return N - pos;
else
return count;
}
public:
// str.substr<pos,count>()
auto constexpr substr(size_t pos = 0, size_t count = npos) const noexcept
{
basic_fixed_string result;
auto const n = __substr_length(pos, count);
for (size_t i = 0; i < n; ++i) result[i] = data_[pos + i];
return result;
}
// str.substr<pos,count>()
template <size_t pos = 0, size_t count = npos>
auto constexpr substr() const noexcept
{
auto constexpr n = __substr_length(pos, count);
basic_fixed_string<charT, n> result;
for (size_t i = 0; i < n; ++i) result[i] = data_[pos + i];
return result;
}
// str1.assign(str2). Must be equal size.
auto constexpr assign(view str)
{
if (str.size() != N) throw std::out_of_range("");
for (size_t i = 0; i < N; ++i) data_[i] = str[i];
return *this;
}
// Replace substring.
auto constexpr replace(size_t pos, view str)
{
if (pos + str.size() > N) throw std::out_of_range("");
for (size_t i = 0; i < str.size(); ++i) data_[i] = str[i];
return *this;
}
// Swap with fixed_string of equal size.
auto constexpr swap(basic_fixed_string &str)
{
for (size_t i = 0; i < N; ++i) swap(data_[i], str[i]);
}
// Null-terminated C string.
auto constexpr c_str() const noexcept
{ return data_; }
auto constexpr data() const noexcept
{ return data_; }
auto constexpr compare(view str) const noexcept
{ return view(*this).compare(str); }
auto constexpr compare(size_t pos1, size_t n1, view str) const
{ return view(*this).compare(pos1, n1, str); }
auto constexpr compare(size_t pos1, size_t n1, view str, size_t pos2, size_t n2 = npos) const
{ return view(*this).compare(pos1, n1, str, pos2, n2); }
auto constexpr compare(charT const *s) const
{ return view(*this).compare(s); }
auto constexpr compare(size_t pos1, size_t n1, charT const *s) const
{ return view(*this).compare(pos1, n1, s); }
auto constexpr compare(size_t pos1, size_t n1, charT const *s, size_t n2) const
{ return view(*this).compare(pos1, n1, s, n2); }
auto constexpr find(view str, size_t pos = 0) const noexcept
{ return view(*this).find(str, pos); }
auto constexpr find(charT c, size_t pos = 0) const noexcept
{ return view(*this).find(c, pos); }
auto constexpr find(charT const *s, size_t pos, size_t count) const
{ return view(*this).find(s, pos, count); }
auto constexpr find(charT const *s, size_t pos = 0) const
{ return view(*this).find(s, pos); }
auto constexpr rfind(view str, size_t pos = npos) const noexcept
{ return view(*this).rfind(str, pos); }
auto constexpr rfind(charT c, size_t pos = npos) const noexcept
{ return view(*this).rfind(c, pos); }
auto constexpr rfind(charT const *s, size_t pos, size_t n) const
{ return view(*this).rfind(s, pos, n); }
auto constexpr rfind(charT const *s, size_t pos = npos) const
{ return view(*this).rfind(s, pos); }
auto constexpr find_first_of(view str, size_t pos = 0) const noexcept
{ return view(*this).find_first_of(str, pos); }
auto constexpr find_first_of(charT c, size_t pos = 0) const noexcept
{ return view(*this).find_first_of(c, pos); }
auto constexpr find_first_of(charT const *s, size_t pos, size_t n) const
{ return view(*this).find_first_of(s, pos, n); }
auto constexpr find_first_of(charT const *s, size_t pos = 0) const
{ return view(*this).find_first_of(s, pos); }
auto constexpr find_last_of(view str, size_t pos = npos) const noexcept
{ return view(*this).find_last_of(str, pos); }
auto constexpr find_last_of(charT c, size_t pos = npos) const noexcept
{ return view(*this).find_last_of(c, pos); }
auto constexpr find_last_of(charT const *s, size_t pos, size_t n) const
{ return view(*this).find_last_of(s, pos, n); }
auto constexpr find_last_of(charT const *s, size_t pos = npos) const
{ return view(*this).find_last_of(s, pos); }
auto constexpr find_first_not_of(view str, size_t pos = 0) const noexcept
{ return view(*this).find_first_not_of(str, pos); }
auto constexpr find_first_not_of(charT c, size_t pos = 0) const noexcept
{ return view(*this).find_first_not_of(c, pos); }
auto constexpr find_first_not_of(charT const *s, size_t pos, size_t n) const
{ return view(*this).find_first_not_of(s, pos, n); }
auto constexpr find_first_not_of(charT const *s, size_t pos = 0) const
{ return view(*this).find_first_not_of(s, pos); }
auto constexpr find_last_not_of(view str, size_t pos = npos) const noexcept
{ return view(*this).find_last_not_of(str, pos); }
auto constexpr find_last_not_of(charT c, size_t pos = npos) const noexcept
{ return view(*this).find_last_not_of(c, pos); }
auto constexpr find_last_not_of(charT const *s, size_t pos, size_t n) const
{ return view(*this).find_last_not_of(s, pos, n); }
auto constexpr find_last_not_of(charT const *s, size_t pos = npos) const
{ return view(*this).find_last_not_of(s, pos); }
private:
charT data_[N + 1]; // (+1 is for terminating null)
};
//
// type_t/_v
template <class... Ts>
struct type_t
{
static auto constexpr size = sizeof...(Ts);
template <std::size_t N>
using type = std::tuple_element_t<N, std::tuple<Ts...>>;
};
template <class... Ts>
auto constexpr type_v = type_t<Ts...>{};
template <class... L, class... R>
auto constexpr operator+(type_t<L...>, type_t<R...>)
{ return type_t<L..., R...>{}; }
template <class... L, class... R>
auto constexpr operator==(type_t<L...>, type_t<R...>)
{ return std::is_same_v<type_t<L...>, type_t<R...>>; }
// remove
template <class T, class... Ts>
auto constexpr remove(type_t<Ts...>)
{ return (std::conditional_t<std::is_same_v<T, Ts>, type_t<>, type_t<Ts>>{} + ...); }
template <class T, class... Ts>
auto constexpr remove(type_t<T> = {}, type_t<Ts...> ts = {})
{ return remove<T>(ts); }
// contains
template <class T, class... Ts>
auto constexpr contains(type_t<Ts...>)
{ return (std::is_same_v<T, Ts> || ...); }
template <class T, class... Ts>
auto constexpr contains(type_t<T> = {}, type_t<Ts...> ts = {})
{ return contains<T>(ts); }
// find
namespace detail
{
template <class T, class... Ts, auto... Is>
auto constexpr find_impl__(type_t<T>, type_t<Ts...>, std::index_sequence<Is...>)
{
auto idx = sizeof...(Ts) + 2;
((std::is_same_v<T, Ts> ? idx = Is + 1 : 0) || ...);
return idx - 1;
}
}
template <class T, class... Ts>
auto constexpr find(type_t<Ts...> ts)
{ return detail::find_impl__(type_v<T>, ts, std::make_index_sequence<ts.size>{}); }
template <class T, class... Ts>
auto constexpr find(type_t<T> = {}, type_t<Ts...> ts = {})
{ return find<T>(ts); }
// C++2a
//template <class T, class... Ts>
//auto constexpr find(type_t<T> = {}, type_t<Ts...> = {})
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// {
// auto idx = sizeof...(Ts) + 1;
// ((std::is_same_v<T, Ts> ? idx = Is : 0) || ...);
// return idx;
// }
// (std::make_index_sequence<sizeof...(Ts)>{});
//}
// unique
template <class T, class... Ts>
auto constexpr is_unique(type_t<T, Ts...> = {})
{
if constexpr (sizeof...(Ts) < 2)
{ return true; }
else
{ return ((!std::is_same_v<T, Ts>) && ...) && is_unique<Ts...>(); }
}
// remove_at
namespace detail
{
template <auto I, class... Ts, auto... Is>
auto constexpr remove_at_impl(std::index_sequence<Is...>)
{ return (std::conditional_t<I == Is, type_t<>, type_t<Ts>>{} + ...); }
}
template <std::size_t I, class... Ts>
auto constexpr remove_at(type_t<Ts...> ts = {})
{ return detail::remove_at_impl<I, Ts...>(std::make_index_sequence<ts.size>{}); }
// C++2a
//template <std::size_t I, auto... Vs>
//auto constexpr remove_at(auto_t<Vs...> vs)
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// { return (std::conditional_t<I == Is, auto_t<>, auto_t<Vs>>{} + ...); }
// (std::make_index_sequence<vs.size>{});
//}
// pop_front
namespace detail
{
template <class T, class... Ts>
auto constexpr pop_front_impl(type_t<T, Ts...>)
{ return type_v<Ts...>; }
}
template <class... Ts>
auto constexpr pop_front(type_t<Ts...> ts = {})
{ return detail::pop_front_impl(ts); }
// pop_back
template <class... Ts>
auto constexpr pop_back(type_t<Ts...> ts = {})
{ return remove_at<ts.size - 1>(ts); }
// push_front
template <class T, class... Ts>
auto constexpr push_front(type_t<Ts...>)
{ return type_v<T, Ts...>; }
template <class T, class... Ts>
auto constexpr push_front(type_t<T> = {}, type_t<Ts...> ts = {})
{ return push_front<T>(ts); }
// push_back
template <class T, class... Ts>
auto constexpr push_back(type_t<Ts...>)
{ return type_v<Ts..., T>; }
template <class T, class... Ts>
auto constexpr push_back(type_t<T> = {}, type_t<Ts...> ts = {})
{ return push_back<T>(ts); }
//
// auto_t/_v
template <auto... Vs>
struct auto_t
{
static auto constexpr size = sizeof...(Vs);
using types = type_t<decltype(Vs)...>;
};
template <auto... Vs>
auto constexpr auto_v = auto_t<Vs...>{};
template <auto... L, auto... R>
auto constexpr operator+(auto_t<L...>, auto_t<R...>)
{ return auto_t<L..., R...>{}; }
template <auto... L, auto... R>
auto constexpr operator==(auto_t<L...>, auto_t<R...>)
{ return std::is_same_v<auto_t<L...>, auto_t<R...>>; }
// min / max
template <auto... Vs>
auto constexpr min(auto_t<Vs...> = {})
{
using type = std::common_type_t<decltype(Vs)...>; // replace
auto val = std::numeric_limits<type>::max();
(((val > Vs) ? val = Vs : 0), ...);
return val;
}
template <auto... Vs>
auto constexpr max(auto_t<Vs...> = {})
{
using type = std::common_type_t<decltype(Vs)...>; // replace
auto val = std::numeric_limits<type>::min();
(((val < Vs) ? val = Vs : 0), ...);
return val;
}
// remove
template <auto V, auto... Vs>
auto constexpr remove(auto_t<Vs...>)
{ return (std::conditional_t<V == Vs, auto_t<>, auto_t<Vs>>{} + ...); }
template <auto V, auto... Vs>
auto constexpr remove(auto_t<V> = {}, auto_t<Vs...> = {})
{ return (std::conditional_t<V == Vs, auto_t<>, auto_t<Vs>>{} + ...); }
// contains
template <auto V, auto... Vs>
auto constexpr contains(auto_t<V> = {}, auto_t<Vs...> = {})
{ return ((V == Vs) || ...); }
// find
namespace detail
{
template <auto V, auto... Vs, auto... Is>
auto constexpr find_impl__(auto_t<V>, auto_t<Vs...>, std::index_sequence<Is...>)
{
auto idx = sizeof...(Vs) + 2;
((V == Vs ? idx = Is + 1 : 0) || ...);
return idx - 1;
}
}
template <auto V, auto... Vs>
auto constexpr find(auto_t<Vs...> vs)
{ return detail::find_impl__(auto_v<V>, vs, std::make_index_sequence<vs.size>{}); }
template <auto V, auto... Vs>
auto constexpr find(auto_t<V> = {}, auto_t<Vs...> vs = {})
{ return find<V>(vs); }
// C++2a
//template <auto V, auto... Vs>
//auto constexpr find(auto_t<V> = {}, auto_t<Vs...> = {})
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// {
// auto idx = sizeof...(Vs) + 1;
// ((V == Vs ? idx = Is : 0) || ...);
// return idx;
// }
// (std::make_index_sequence<sizeof...(Vs)>{});
//}
// is_unique
namespace detail
{
template <auto V, auto... Vs>
auto constexpr is_unique_impl(auto_t<V, Vs...> = {})
{
if constexpr (sizeof...(Vs) == 0)
{ return true; }
else
{ return ((V != Vs) && ...) && is_unique_impl<Vs...>(); }
}
}
template <auto... Vs>
auto constexpr is_unique(auto_t<Vs...> vs = {})
{
if constexpr (sizeof...(Vs) < 2)
{ return true; }
else
{ return detail::is_unique_impl(vs); }
}
// get
namespace detail
{
template <auto Idx, auto V, auto... Vs, auto I, auto... Is>
auto constexpr get_impl(auto_t<V, Vs...>, std::index_sequence<I, Is...>)
{
if constexpr (Idx == I)
{ return V; }
else
{ return get_impl<Idx>(auto_v<Vs...>, std::index_sequence<Is...>{}); }
}
}
template <std::size_t I, auto... Vs>
auto constexpr get(auto_t<Vs...> vs)
{ return detail::get_impl<I>(vs, std::make_index_sequence<vs.size>{}); }
template <std::size_t I, auto... Vs>
auto constexpr get(auto_t<I> = {}, auto_t<Vs...> vs = {})
{ return get<I>(vs); }
// remove_at
namespace detail
{
template <auto I, auto... Vs, auto... Is>
auto constexpr remove_at_impl(std::index_sequence<Is...>)
{ return (std::conditional_t<I == Is, auto_t<>, auto_t<Vs>>{} + ...); }
}
template <std::size_t I, auto... Vs>
auto constexpr remove_at(auto_t<Vs...> vs)
{ return detail::remove_at_impl<I, Vs...>(std::make_index_sequence<vs.size>{}); }
template <std::size_t I, auto... Vs>
auto constexpr remove_at(auto_t<I> = {}, auto_t<Vs...> vs = {})
{ return remove_at<I>(vs); }
// C++2a
//template <std::size_t I, auto... Vs>
//auto constexpr remove_at(auto_t<Vs...> vs)
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// { return (std::conditional_t<I == Is, auto_t<>, auto_t<Vs>>{} + ...); }
// (std::make_index_sequence<vs.size>{});
//}
// pop_front
namespace detail
{
template <auto V, auto... Vs>
auto constexpr pop_front_impl(auto_t<V, Vs...>)
{ return auto_v<Vs...>; }
}
template <auto... Vs>
auto constexpr pop_front(auto_t<Vs...> vs = {})
{ return detail::pop_front_impl(vs); }
// pop_back
template <auto... Vs>
auto constexpr pop_back(auto_t<Vs...> vs = {})
{ return remove_at<vs.size - 1>(vs); }
// push_front
template <auto V, auto... Vs>
auto constexpr push_front(auto_t<Vs...>)
{ return auto_v<V, Vs...>; }
template <auto V, auto... Vs>
auto constexpr push_front(auto_t<V> = {}, auto_t<Vs...> vs = {})
{ return push_front<V>(vs); }
// push_back
template <auto V, auto... Vs>
auto constexpr push_back(auto_t<Vs...>)
{ return auto_v<Vs..., V>; }
template <auto V, auto... Vs>
auto constexpr push_back(auto_t<V> = {}, auto_t<Vs...> vs = {})
{ return push_back<V>(vs); }
// find_all
namespace detail
{
template <auto V, auto... Vs, auto... Is>
auto constexpr find_all_impl(std::index_sequence<Is...>)
{ return (std::conditional_t<V == Vs, auto_t<Is>, auto_t<>>{} + ...); }
}
template <auto V, auto... Vs>
auto constexpr find_all(auto_t<Vs...> vs)
{ return detail::find_all_impl<V, Vs...>(std::make_index_sequence<vs.size>{}); }
template <auto V, auto... Vs>
auto constexpr find_all(auto_t<V> = {}, auto_t<Vs...> vs = {})
{ return find_all<V>(vs); }
// C++2a
//template <auto V, auto... Vs>
//auto constexpr find_all(auto_t<Vs...> vs)
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// { return (std::conditional_t<V == Vs, auto_t<Is>, auto_t<>>{} + ...); }
// (std::make_index_sequence<vs.size>{});
//}
//
// common type
template <class...>
struct common_type;
template <class... Ts>
struct common_type<type_t<Ts...>>
{ using type = std::common_type_t<Ts...>; };
template <auto... Vs>
struct common_type<auto_t<Vs...>>
{ using type = std::common_type_t<decltype(Vs)...>; };
// flatten
template <class T>
auto constexpr flatten(T)
{ return T{}; }
template <class... Ts>
auto constexpr flatten(type_t<Ts...> = {})
{ return auto_v<> + (flatten(Ts{}) + ...); }
// subset type_t
namespace detail
{
template <std::size_t B, std::size_t E, class... Ts, auto... Is>
auto constexpr subset_impl(std::index_sequence<Is...>)
{ return (std::conditional_t<(Is < B) || (Is > E), type_t<>, type_t<Ts>>{} + ...); }
}
template <std::size_t B, std::size_t E, class... Ts>
auto constexpr subset(type_t<Ts...> ts)
{ return detail::subset_impl<B, E, Ts...>(std::make_index_sequence<ts.size>{}); }
template <std::size_t B, std::size_t E, class... Ts>
auto constexpr subset(auto_t<B> = {}, auto_t<E> = {}, type_t<Ts...> ts = {})
{ return subset<B, E>(ts); }
// C++2a
//template <std::size_t B, std::size_t E, class... Ts>
//auto constexpr subset(type_t<Ts...> ts)
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// { return (std::conditional_t<(Is < B) || (Is > E), type_t<>, type_t<Ts>>{} + ...); }
// (std::make_index_sequence<ts.size>{});
//}
// subset auto_t
namespace detail
{
template <std::size_t B, std::size_t E, auto... Vs, auto... Is>
auto constexpr subset_impl(std::index_sequence<Is...>)
{ return (std::conditional_t<(Is < B) || (Is > E), auto_t<>, auto_t<Vs>>{} + ...); }
}
template <std::size_t B, std::size_t E, auto... Vs>
auto constexpr subset(auto_t<Vs...> vs)
{ return detail::subset_impl<B, E, Vs...>(std::make_index_sequence<vs.size>{}); }
template <std::size_t B, std::size_t E, auto... Vs>
auto constexpr subset(auto_t<B> = {}, auto_t<E> = {}, auto_t<Vs...> vs = {})
{ return subset<B, E>(vs); }
// C++2a
//template <std::size_t B, std::size_t E, auto... Vs>
//auto constexpr subset(auto_t<Vs...> vs)
//{
// return []<auto... Is>
// (std::index_sequence<Is...>)
// { return (std::conditional_t<(Is < B) || (Is > E), auto_t<>, auto_t<Vs>>{} + ...); }
// (std::make_index_sequence<vs.size>{});
//}
//
// raise
template <class Seq>
auto constexpr raise(Seq)
{ return type_v<Seq>; }
// find_all type_t
namespace detail
{
template <class T, class... Ts, auto... Is>
auto constexpr find_all_impl(std::index_sequence<Is...>)
{ return (std::conditional_t<std::is_same_v<T, Ts>, auto_t<Is>, auto_t<>>{} + ...); }
}
template <class T, class... Ts>
auto constexpr find_all(type_t<Ts...> ts)
{ return detail::find_all_impl<T, Ts...>(std::make_index_sequence<ts.size>{}); }
template <class T, class... Ts>
auto constexpr find_all(type_t<T> = {}, type_t<Ts...> ts = {})
{ return find_all<T>(ts); }
// tokenise shared
namespace detail
{
template <class Seq, auto B, auto E, auto... Tail>
auto constexpr tokenise_impl(Seq seq, auto_t<B, E, Tail...>)
{
auto constexpr first = raise(subset<B, E - 1>(seq));
if constexpr (sizeof...(Tail) == 0)
{ return first + raise(subset<E + 1, seq.size - 1>(seq)); }
else
{ return first + tokenise_impl(seq, auto_v<E + 1, Tail...>); }
}
}
// tokenise type_t
template <class T, class... Ts>
auto constexpr tokenise(type_t<Ts...> ts)
{
auto constexpr offs = auto_v<0> + find_all<T>(ts);
if constexpr (offs.size < 2)
{ return raise(ts); }
else
{ return detail::tokenise_impl(ts, offs); }
}
template <class T, class... Ts>
auto constexpr tokenise(type_t<T> = {}, type_t<Ts...> ts = {})
{ return tokenise<T>(ts); }
// tokenise auto_t
template <auto V, auto... Vs>
auto constexpr tokenise(auto_t<Vs...> vs)
{
auto constexpr offs = auto_v<0> + find_all<V>(vs);
if constexpr (offs.size < 2)
{ return raise(vs); }
else
{ return detail::tokenise_impl(vs, offs); }
}
template <auto V, auto... Vs>
auto constexpr tokenise(auto_t<V> = {}, auto_t<Vs...> vs = {})
{ return tokenise<V>(vs); }
//
// UDLs (signed)
template <char... Cs>
char constexpr to_c_str[] = { Cs..., '\0' };
template <char... Vs>
auto constexpr to_fixed_string(auto_t<Vs...> vs)
{ return make_fixed_string(to_c_str<Vs...>); }
namespace detail
{
template <class... Ts>
auto constexpr udl_i_impl(type_t<Ts...>)
{ return (auto_v<stoi(to_fixed_string(Ts{}))> + ...); }
template <class... Ts>
auto constexpr udl_l_impl(type_t<Ts...>)
{ return (auto_v<stol(to_fixed_string(Ts{}))> + ...); }
template <class... Ts>
auto constexpr udl_ll_impl(type_t<Ts...>)
{ return (auto_v<stoll(to_fixed_string(Ts{}))> + ...); }
}
template <char... Vs>
auto constexpr operator ""_i()
{ return detail::udl_i_impl(tokenise<'\'', Vs...>()); }
template <char... Vs>
auto constexpr operator ""_l()
{ return detail::udl_l_impl(tokenise<'\'', Vs...>()); }
template <char... Vs>
auto constexpr operator ""_ll()
{ return detail::udl_ll_impl(tokenise<'\'', Vs...>()); }
// C++2a
//template <char... Vs>
//auto constexpr operator ""_i()
//{
// return []<class... Ts>
// (type_t<Ts...>)
// { return (auto_v<stoi(to_fixed_string(Ts{}))> + ...); }
// (tokenise<'\'', Vs...>());
//}
//template <char... Vs>
//auto constexpr operator ""_l()
//{
// return []<class... Ts>
// (type_t<Ts...>)
// { return (auto_v<stol(to_fixed_string(Ts{}))> + ...); }
// (tokenise<'\'', Vs...>());
//}
//template <char... Vs>
//auto constexpr operator ""_ll()
//{
// return []<class... Ts>
// (type_t<Ts...>)
// { return (auto_v<stoll(to_fixed_string(Ts{}))> + ...); }
// (tokenise<'\'', Vs...>());
//}
// UDLs (unsigned)
namespace detail
{
template <class... Ts>
auto constexpr udl_u_impl(type_t<Ts...>)
{ return (auto_v<stou(to_fixed_string(Ts{}))> + ...); }
template <class... Ts>
auto constexpr udl_ul_impl(type_t<Ts...>)
{ return (auto_v<stol(to_fixed_string(Ts{}))> + ...); }
template <class... Ts>
auto constexpr udl_ull_impl(type_t<Ts...>)
{ return (auto_v<stoll(to_fixed_string(Ts{}))> + ...); }
}
template <char... Vs>
auto constexpr operator ""_u()
{ return detail::udl_u_impl(tokenise<'\'', Vs...>()); }
template <char... Vs>
auto constexpr operator ""_ul()
{ return detail::udl_ul_impl(tokenise<'\'', Vs...>()); }
template <char... Vs>
auto constexpr operator ""_ull()
{ return detail::udl_ull_impl(tokenise<'\'', Vs...>()); }
// C++2a
//template <char... Vs>
//auto constexpr operator ""_u()
//{
// return []<class... Ts>
// (type_t<Ts...>)
// { return (auto_v<stou(to_fixed_string(Ts{}))> + ...); }
// (tokenise<'\'', Vs...>());
//}
//template <char... Vs>
//auto constexpr operator ""_ul()
//{
// return []<class... Ts>
// (type_t<Ts...>)
// { return (auto_v<stoul(to_fixed_string(Ts{}))> + ...); }
// (tokenise<'\'', Vs...>());
//}
//template <char... Vs>
//auto constexpr operator ""_ull()
//{
// return []<class... Ts>
// (type_t<Ts...>)
// { return (auto_v<stoull(to_fixed_string(Ts{}))> + ...); }
// (tokenise<'\'', Vs...>());
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment