Skip to content

Instantly share code, notes, and snippets.

@snhobbs
Last active July 21, 2025 21:43
Show Gist options
  • Select an option

  • Save snhobbs/b1cbf0ff98e0f62eaab3f1b47fca5ca9 to your computer and use it in GitHub Desktop.

Select an option

Save snhobbs/b1cbf0ff98e0f62eaab3f1b47fca5ca9 to your computer and use it in GitHub Desktop.
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED
#define ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED
#if defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
import std;
#else
#include <type_traits>
#include <initializer_list>
#include <utility>
#endif
#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1922
#define STRONG_CONSTEXPR
#else
#define STRONG_CONSTEXPR constexpr
#endif
#if __cplusplus >= 201703L
#define STRONG_NODISCARD [[nodiscard]]
#else
#define STRONG_NODISCARD
#endif
namespace strong {
struct uninitialized_t {
};
static constexpr uninitialized_t uninitialized{};
template<typename M, typename T>
using modifier = typename M::template modifier<T>;
struct default_constructible {
template<typename T>
class modifier {
};
};
namespace impl {
template<typename T>
constexpr bool supports_default_construction(
const ::strong::default_constructible::modifier<T> *)
{
return true;
}
template<typename T, typename ... V>
using WhenConstructible = std::enable_if_t<std::is_constructible<T, V...>::value>;
}
template<typename T, typename Tag, typename ... M>
class type : public modifier<M, type<T, Tag, M...>> ... {
public:
template<typename TT = T, typename = std::enable_if_t<std::is_trivially_constructible<TT>{}>>
explicit type(uninitialized_t)
noexcept
{
}
template<typename type_ = type,
bool = impl::supports_default_construction(
static_cast<type_ *>(nullptr))>
constexpr
type()
noexcept(noexcept(T{}))
: _val{}
{
}
template<typename U,
typename = impl::WhenConstructible<T, std::initializer_list<U>>>
constexpr
explicit
type(
std::initializer_list<U> us
)
noexcept(noexcept(T{us}))
: _val{us}
{
}
template<typename ... U,
typename = std::enable_if_t<
std::is_constructible<T, U &&...>::value && (sizeof...(U) > 0)>>
constexpr
explicit
type(
U &&... u)
noexcept(std::is_nothrow_constructible<T, U...>::value)
: _val(std::forward<U>(u)...)
{}
friend STRONG_CONSTEXPR void swap(type &a, type &b) noexcept(
std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_move_assignable<T>::value
)
{
using std::swap;
swap(a._val, b._val);
}
STRONG_NODISCARD
constexpr T &value_of() & noexcept
{ return _val; }
STRONG_NODISCARD
constexpr const T &value_of() const & noexcept
{ return _val; }
STRONG_NODISCARD
constexpr T &&value_of() && noexcept
{ return std::move(_val); }
STRONG_NODISCARD
constexpr const T &&value_of() const && noexcept
{ return std::move(_val); }
STRONG_NODISCARD
friend constexpr T &value_of(type &t) noexcept
{ return t._val; }
STRONG_NODISCARD
friend constexpr const T &value_of(const type &t) noexcept
{ return t._val; }
STRONG_NODISCARD
friend constexpr T &&value_of(type &&t) noexcept
{ return std::move(t)._val; }
STRONG_NODISCARD
friend constexpr const T &&value_of(const type &&t) noexcept
{ return std::move(t)._val; }
T _val;
};
namespace impl {
template<typename T, typename Tag, typename ... Ms>
constexpr bool is_strong_type_func(const strong::type<T, Tag, Ms...> *)
{ return true; }
constexpr bool is_strong_type_func(...)
{ return false; }
template<typename T, typename Tag, typename ... Ms>
constexpr T underlying_type(strong::type<T, Tag, Ms...> *);
}
template<typename T>
struct is_strong_type : std::integral_constant<bool, impl::is_strong_type_func(
static_cast<T *>(nullptr))> {
};
template<typename T, bool = is_strong_type<T>::value>
struct underlying_type {
using type = decltype(impl::underlying_type(static_cast<T *>(nullptr)));
};
template<typename T>
struct underlying_type<T, false> {
using type = T;
};
template<typename T>
using underlying_type_t = typename underlying_type<T>::type;
namespace impl {
template<typename T>
using WhenStrongType = std::enable_if_t<is_strong_type<std::decay_t<T>>::value>;
template<typename T>
using WhenNotStrongType = std::enable_if_t<!is_strong_type<std::decay_t<T>>::value>;
template<
typename T,
typename = impl::WhenNotStrongType<T>>
constexpr
T &&
access(T &&t)
noexcept
{
return std::forward<T>(t);
}
template<
typename T,
typename = impl::WhenStrongType<T>>
STRONG_NODISCARD
constexpr
auto
access(T &&t)
noexcept
-> decltype(value_of(std::forward<T>(t)))
{
return value_of(std::forward<T>(t));
}
template <typename T>
struct require_copy_constructible
{
static constexpr bool value = std::is_copy_constructible<underlying_type_t<T>>::value;
static_assert(value, "underlying type must be copy constructible");
};
template <typename T>
struct require_move_constructible
{
static constexpr bool value = std::is_move_constructible<underlying_type_t<T>>::value;
static_assert(value, "underlying type must be move constructible");
};
template <typename T>
struct require_copy_assignable
{
static constexpr bool value = std::is_copy_assignable<underlying_type_t<T>>::value;
static_assert(value, "underlying type must be copy assignable");
};
template <typename T>
struct require_move_assignable
{
static constexpr bool value = std::is_move_assignable<underlying_type_t<T>>::value;
static_assert(value, "underlying type must be move assignable");
};
template <typename ...>
static constexpr bool always_false = false;
template <bool> struct valid_type;
template <>
struct valid_type<true> {};
template<typename ...>
using void_t = void;
template <typename Needle, typename Type, typename Modifier>
static constexpr bool modifier_is
= std::is_base_of<modifier<Needle, Type>, modifier<Modifier,Type>>::value;
template <typename Needle, typename Type, typename Haystack>
static
constexpr
bool
type_implements
= std::is_base_of<modifier<Needle, Type>, modifier<Haystack, Type>>::value;
#if __cplusplus >= 201703
template <
template <typename...> class Modifier,
typename Needle,
typename Type,
typename ... Ms
>
static
constexpr
bool
modifier_is<Needle, Type, Modifier<Ms...>>
= (std::is_base_of<modifier<Needle, Type>, modifier<Modifier<Ms>, Type>>::value || ...);
template <
template <typename ...> class Modifier,
typename ... Needles,
typename Type,
typename ... Haystack
>
static
constexpr
bool type_implements<Modifier<Needles...>, Type, Modifier<Haystack...>>
= (modifier_is<Modifier<Needles>, Type, Modifier<Haystack...>> && ...);
#else
template <typename ...>
struct conjunction;
template <typename T, typename ... Ts>
struct conjunction<T, Ts...>
: std::integral_constant<bool, T::value && conjunction<Ts...>::value>
{};
template <>
struct conjunction<> : std::true_type {};
template <typename ...>
struct disjunction;
template <typename T, typename ... Ts>
struct disjunction<T, Ts...>
: std::integral_constant<bool, T::value || disjunction<Ts...>::value>
{};
template <>
struct disjunction<> : std::false_type {};
template <
template <typename...> class Modifier,
typename Needle,
typename Type,
typename ... Ms
>
static
constexpr
bool
modifier_is<Needle, Type, Modifier<Ms...>>
= disjunction<
std::is_base_of<
modifier<Needle, Type>,
modifier<Modifier<Ms>, Type>
>...
>::value;
template <
template <typename ...> class Modifier,
typename ... Needles,
typename Type,
typename ... Haystack
>
static
constexpr
bool
type_implements<Modifier<Needles...>, Type, Modifier<Haystack...>>
= conjunction<
std::integral_constant<
bool,
modifier_is<
Modifier<Needles>,
Type,
Modifier<Haystack...>
>
>...
>::value;
#endif
template <typename T, typename M>
static constexpr bool type_is = false;
#if __cplusplus >= 201703L
template <typename T, typename Tag, typename ... Ms, typename M>
static constexpr bool type_is<strong::type<T, Tag, Ms...>, M>
= (impl::type_implements<M, strong::type<T, Tag, Ms...>, Ms> || ...);
#else
template <typename T, typename Tag, typename ... Ms, typename M>
static constexpr bool type_is<strong::type<T, Tag, Ms...>, M>
= impl::disjunction<std::integral_constant<bool, impl::type_implements<M, strong::type<T, Tag, Ms...>, Ms>>...>::value;
#endif
template <typename T, typename Tag, typename ... Ms>
type<T, Tag, Ms...> get_strong_(const type<T, Tag, Ms...>*);
template <typename T>
using get_strong = decltype(get_strong_(static_cast<T*>(nullptr)));
}
template <typename T, typename M>
static constexpr bool type_is_v = impl::type_is<impl::get_strong<T>, M>;
template <typename T, typename M>
using type_is = std::integral_constant<bool, type_is_v<T,M>>;
}
#endif //ROLLBEAR_STRONG_TYPE_TYPE_HPP_INCLUDED
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_EQUALITY_HPP
#define STRONG_TYPE_EQUALITY_HPP
namespace strong
{
struct equality
{
template <typename T, typename = void>
class modifier {
static_assert(impl::always_false<T>,
"Underlying type must be equality comparable");
};
};
template <typename T, typename Tag, typename ... M>
class equality::modifier<
::strong::type<T, Tag, M...>,
impl::void_t<decltype(std::declval<const T&>() == std::declval<const T&>())>
>
{
using type = ::strong::type<T, Tag, M...>;
public:
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator==(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const T&>() == std::declval<const T&>()))
-> decltype(std::declval<const T&>() == std::declval<const T&>())
{
return value_of(lh) == value_of(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator!=(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const T&>() != std::declval<const T&>()))
-> decltype(std::declval<const T&>() != std::declval<const T&>())
{
return value_of(lh) != value_of(rh);
}
};
}
#endif //STRONG_TYPE_EQUALITY_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_EQUALITY_WITH_HPP
#define STRONG_TYPE_EQUALITY_WITH_HPP
namespace strong
{
namespace impl
{
template <typename T, typename Other, typename = void>
class typed_equality {
static_assert(impl::always_false<T, Other>,
"Underlying type must be equality comparable with target type");
};
template <typename T, typename Other>
class typed_equality<
T,
Other,
impl::void_t<decltype(std::declval<const underlying_type_t<T>&>() == std::declval<const underlying_type_t<Other>&>())>
>
{
private:
using TT = underlying_type_t<T>;
using OT = underlying_type_t<Other>;
public:
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator==(const T& lh, const Other& rh)
noexcept(noexcept(std::declval<const TT&>() == std::declval<const OT&>()))
-> decltype(std::declval<const TT&>() == std::declval<const OT&>())
{
return value_of(lh) == impl::access(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator==(const Other& lh, const T& rh)
noexcept(noexcept(std::declval<const OT&>() == std::declval<const TT&>()))
-> decltype(std::declval<const OT&>() == std::declval<const TT&>())
{
return impl::access(lh) == value_of(rh) ;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator!=(const T& lh, const Other rh)
noexcept(noexcept(std::declval<const TT&>() != std::declval<const OT&>()))
-> decltype(std::declval<const TT&>() != std::declval<const OT&>())
{
return value_of(lh) != impl::access(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator!=(const Other& lh, const T& rh)
noexcept(noexcept(std::declval<const OT&>() != std::declval<const TT&>()))
-> decltype(std::declval<const OT&>() != std::declval<const TT&>())
{
return impl::access(lh) != value_of(rh) ;
}
};
}
template <typename ... Ts>
struct equality_with
{
template <typename T>
class modifier : public impl::typed_equality<T, Ts>...
{
};
};
}
#endif //STRONG_TYPE_EQUALITY_WITH_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_ORDERED_HPP
#define STRONG_TYPE_ORDERED_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#if __cpp_impl_three_way_comparison && __has_include(<compare>)
#include <compare>
#endif
#endif
namespace strong
{
struct ordered
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type must support ordering relations using <, <=, > and >=");
};
};
template <typename T, typename Tag, typename ... M>
class ordered::modifier<
::strong::type<T, Tag, M...>,
impl::void_t<
decltype((std::declval<T>() < std::declval<T>())),
decltype((std::declval<T>() <= std::declval<T>())),
decltype((std::declval<T>() > std::declval<T>())),
decltype((std::declval<T>() >= std::declval<T>()))>
>
{
using type = ::strong::type<T, Tag, M...>;
public:
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator<(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const T&>() < std::declval<const T&>()))
-> decltype(std::declval<const T&>() < std::declval<const T&>())
{
return value_of(lh) < value_of(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator<=(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const T&>() <= std::declval<const T&>()))
-> decltype(std::declval<const T&>() <= std::declval<const T&>())
{
return value_of(lh) <= value_of(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator>(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const T&>() > std::declval<const T&>()))
-> decltype(std::declval<const T&>() > std::declval<const T&>())
{
return value_of(lh) > value_of(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator>=(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const T&>() >= std::declval<const T&>()))
-> decltype(std::declval<const T&>() >= std::declval<const T&>())
{
return value_of(lh) >= value_of(rh);
}
};
#if __cpp_impl_three_way_comparison && __has_include(<compare>)
namespace detail
{
template<typename Ordering>
struct spaceship_ordering {
template <typename>
struct modifier;
};
template<typename Ordering>
template<typename T, typename Tag, typename ... Ms>
struct spaceship_ordering<Ordering>::modifier<::strong::type<T, Tag, Ms...>>
{
using type = ::strong::type<T, Tag, Ms...>;
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
Ordering
operator<=>(
const type &lh,
const type &rh)
noexcept(noexcept(std::declval<const T &>() <=> std::declval<const T &>()))
requires std::is_convertible_v<decltype(std::declval<const T&>() <=> std::declval<const T&>()), Ordering>
{
return value_of(lh) <=> value_of(rh);
}
};
}
using strongly_ordered = detail::spaceship_ordering<std::strong_ordering>;
using weakly_ordered = detail::spaceship_ordering<std::weak_ordering>;
using partially_ordered = detail::spaceship_ordering<std::partial_ordering>;
#endif
}
#endif //STRONG_TYPE_ORDERED_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_ORDERED_WITH_HPP
#define STRONG_TYPE_ORDERED_WITH_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#if __cpp_impl_three_way_comparison && __has_include(<compare>)
#include <compare>
#endif
#endif
namespace strong
{
namespace impl
{
template <typename T, typename Other, typename = void>
class typed_ordering
{
static_assert(impl::always_false<T, Other>,
"Underlying type must support ordering relations with target type using operators <, <=, > and >=");
};
template <typename T, typename Other>
class typed_ordering<
T,
Other,
impl::void_t<
decltype((std::declval<underlying_type_t<T>>() < std::declval<underlying_type_t<Other>>())),
decltype((std::declval<underlying_type_t<T>>() <= std::declval<underlying_type_t<Other>>())),
decltype((std::declval<underlying_type_t<T>>() > std::declval<underlying_type_t<Other>>())),
decltype((std::declval<underlying_type_t<T>>() >= std::declval<underlying_type_t<Other>>()))
>
>
{
private:
using TT = underlying_type_t<T>;
using OT = underlying_type_t<Other>;
public:
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator<(const T& lh, const Other& rh)
noexcept(noexcept(std::declval<const TT&>() < std::declval<const OT&>()))
-> decltype(std::declval<const TT&>() < std::declval<const OT&>())
{
return value_of(lh) < impl::access(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator<(const Other& lh, const T& rh)
noexcept(noexcept(std::declval<const OT&>() < std::declval<const TT&>()))
-> decltype(std::declval<const OT&>() < std::declval<const TT&>())
{
return impl::access(lh) < value_of(rh) ;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator<=(const T& lh, const Other& rh)
noexcept(noexcept(std::declval<const TT&>() <= std::declval<const OT&>()))
-> decltype(std::declval<const TT&>() <= std::declval<const OT&>())
{
return value_of(lh) <= impl::access(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator<=(const Other& lh, const T& rh)
noexcept(noexcept(std::declval<const OT&>() <= std::declval<const TT&>()))
-> decltype(std::declval<const OT&>() <= std::declval<const TT&>())
{
return impl::access(lh) <= value_of(rh) ;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator>(const T& lh, const Other& rh)
noexcept(noexcept(std::declval<const TT&>() > std::declval<const OT&>()))
-> decltype(std::declval<const TT&>() > std::declval<const OT&>())
{
return value_of(lh) > impl::access(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator>(const Other& lh, const T& rh)
noexcept(noexcept(std::declval<const OT&>() > std::declval<const TT&>()))
-> decltype(std::declval<const OT&>() > std::declval<const TT&>())
{
return impl::access(lh) > value_of(rh) ;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator>=(const T& lh, const Other& rh)
noexcept(noexcept(std::declval<const TT&>() >= std::declval<const OT&>()))
-> decltype(std::declval<const TT&>() >= std::declval<const OT&>())
{
return value_of(lh) >= impl::access(rh);
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator>=(const Other& lh, const T& rh)
noexcept(noexcept(std::declval<const OT&>() >= std::declval<const TT&>()))
-> decltype(std::declval<const OT&>() >= std::declval<const TT&>())
{
return impl::access(lh) >= value_of(rh) ;
}
};
}
template <typename ... Ts>
struct ordered_with
{
template <typename T>
class modifier : public impl::typed_ordering<T, Ts>...
{
};
};
#if __cpp_impl_three_way_comparison && __has_include(<compare>)
namespace detail
{
template <typename Ordering, typename T, typename Other>
struct typed_spaceship_ordering_with
{
private:
using TT = underlying_type_t<T>;
using OT = underlying_type_t<Other>;
public:
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
Ordering
operator<=>(
const T& lh,
const Other& rh)
noexcept(noexcept(std::declval<const TT&>() <=> std::declval<const OT&>()))
requires std::is_convertible_v<decltype(std::declval<const TT&>() <=> std::declval<const OT&>()), Ordering>
{
return value_of(lh) <=> impl::access(rh);
}
};
template <typename Ordering, typename ... Ts>
struct spaceship_ordering_with
{
template <typename T>
struct modifier : public typed_spaceship_ordering_with<Ordering, T, Ts>...
{
};
};
}
template <typename ... Ts>
using strongly_ordered_with = detail::spaceship_ordering_with<std::strong_ordering, Ts...>;
template <typename ... Ts>
using weakly_ordered_with = detail::spaceship_ordering_with<std::weak_ordering, Ts...>;
template <typename ... Ts>
using partially_ordered_with = detail::spaceship_ordering_with<std::partial_ordering, Ts...>;
#endif
}
#endif //STRONG_TYPE_ORDERED_WITH_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_SEMIREGULAR_HPP
#define STRONG_TYPE_SEMIREGULAR_HPP
namespace strong
{
namespace impl
{
template <typename T>
struct require_semiregular
: valid_type<require_copy_constructible<T>::value &&
require_move_constructible<T>::value &&
require_copy_assignable<T>::value &&
require_move_assignable<T>::value>
{
};
}
struct semiregular
{
template <typename>
class modifier;
};
template <typename T, typename Tag, typename ... M>
class semiregular::modifier<::strong::type<T, Tag, M...>>
: public default_constructible::modifier<T>
, private impl::require_semiregular<T>
{
};
}
#endif //STRONG_TYPE_SEMIREGULAR_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_REGULAR_HPP
#define STRONG_TYPE_REGULAR_HPP
namespace strong
{
struct regular
{
template <typename T>
class modifier
: public semiregular::modifier<T>
, public equality::modifier<T>
{
};
};
}
#endif //STRONG_TYPE_REGULAR_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_UNIQUE_HPP
#define STRONG_TYPE_UNIQUE_HPP
namespace strong {
struct unique {
template<typename T>
class modifier
: private impl::valid_type<
impl::require_move_constructible<T>::value &&
impl::require_move_assignable<T>::value
> {
public:
constexpr modifier() = default;
modifier(const modifier &) = delete;
constexpr modifier(modifier &&) noexcept = default;
modifier &operator=(const modifier &) = delete;
constexpr modifier &operator=(modifier &&) noexcept = default;
};
};
}
#endif //STRONG_TYPE_UNIQUE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_INVOCABLE_HPP
#define STRONG_TYPE_INVOCABLE_HPP
namespace strong
{
struct invocable
{
template <typename>
class modifier;
};
template <typename T, typename Tag, typename ... Ms>
class invocable::modifier<type<T, Tag, Ms...>>
{
using type = strong::type<T, Tag, Ms...>;
public:
template <typename ... Args, typename R = decltype(std::declval<T&>()(std::declval<Args>()...))>
STRONG_CONSTEXPR
R operator()(Args&& ... args) &
noexcept (noexcept(std::declval<T&>()(std::declval<Args>()...)))
{
return call(static_cast<type&>(*this), std::forward<Args>(args)...);
}
template <typename ... Args, typename R = decltype(std::declval<T&&>()(std::declval<Args>()...))>
STRONG_CONSTEXPR
R operator()(Args&& ... args) &&
noexcept (noexcept(std::declval<T&&>()(std::declval<Args>()...)))
{
return call(static_cast<type&&>(std::move(*this)), std::forward<Args>(args)...);
}
template <typename ... Args, typename R = decltype(std::declval<const T&>()(std::declval<Args>()...))>
STRONG_CONSTEXPR
R operator()(Args&& ... args) const &
noexcept (noexcept(std::declval<const T&>()(std::declval<Args>()...)))
{
return call(static_cast<const type&>(*this), std::forward<Args>(args)...);
}
template <typename ... Args, typename R = decltype(std::declval<const T&&>()(std::declval<Args>()...))>
STRONG_CONSTEXPR
R operator()(Args&& ... args) const &&
noexcept (noexcept(std::declval<const T&&>()(std::declval<Args>()...)))
{
return call(static_cast<const type&&>(std::move(*this)), std::forward<Args>(args)...);
}
private:
template <typename Self, typename ... Ts>
static STRONG_CONSTEXPR decltype(auto) call(Self&& self, Ts&& ... ts)
{
return value_of(std::forward<Self>(self))(std::forward<Ts>(ts)...);
}
};
}
#endif //STRONG_TYPE_INVOCABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_ISTREAMABLE_HPP
#define STRONG_TYPE_ISTREAMABLE_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#include <istream>
#endif
namespace strong
{
struct istreamable
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type must support stream input via operator>>");
};
template <typename T>
class modifier<T, impl::void_t<decltype(std::declval<std::istream&>() >> std::declval<underlying_type_t<T>&>())>>
{
public:
friend
std::istream&
operator>>(
std::istream &is,
T &t)
{
return is >> value_of(t);
}
};
};
}
#endif //STRONG_TYPE_ISTREAMABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_OSTREAMABLE_HPP
#define STRONG_TYPE_OSTREAMABLE_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#include <ostream>
#endif
namespace strong
{
struct ostreamable
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type support stream output via operator<<");
};
template <typename T>
class modifier<T, impl::void_t<decltype(std::declval<std::ostream&>() << std::declval<const underlying_type_t<T>&>())>>
{
public:
friend
std::ostream&
operator<<(
std::ostream &os,
const T &t)
{
return os << value_of(t);
}
};
};
template<typename T>
using is_ostreamable = std::is_base_of<ostreamable::modifier<T>, T>;
}
#endif //STRONG_TYPE_OSTREAMABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_IOSTREAMABLE_HPP
#define STRONG_TYPE_IOSTREAMABLE_HPP
namespace strong
{
struct iostreamable
{
template <typename T>
class modifier
: public ostreamable::modifier<T>
, public istreamable::modifier<T>
{
};
};
}
#endif //STRONG_TYPE_IOSTREAMABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_INCREMENTABLE_HPP
#define STRONG_TYPE_INCREMENTABLE_HPP
namespace strong {
struct incrementable
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type must be incrementable");
};
template <typename T>
class modifier<T, impl::void_t<decltype(++std::declval<underlying_type_t<T>&>())>>
{
public:
friend
STRONG_CONSTEXPR
T&
operator++(T& t)
noexcept(noexcept(++std::declval<T&>().value_of()))
{
++value_of(t);
return t;
}
friend
STRONG_CONSTEXPR
T
operator++(T& t, int)
{
auto copy = t;
++t;
return copy;
}
};
};
}
#endif //STRONG_TYPE_INCREMENTABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_DECREMENTABLE_HPP
#define STRONG_TYPE_DECREMENTABLE_HPP
namespace strong
{
struct decrementable
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"underlying type must be decrementable");
};
template <typename T>
class modifier<T, impl::void_t<decltype(--std::declval<underlying_type_t<T>&>())>>
{
public:
friend
STRONG_CONSTEXPR
T&
operator--(T& t)
noexcept(noexcept(--std::declval<T&>().value_of()))
{
--value_of(t);
return t;
}
friend
STRONG_CONSTEXPR
T
operator--(T& t, int)
{
auto copy = t;
--t;
return copy;
}
};
};
}
#endif //STRONG_TYPE_DECREMENTABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_BICREMENTABLE_HPP
#define STRONG_TYPE_BICREMENTABLE_HPP
namespace strong
{
struct bicrementable
{
template <typename T>
class modifier
: public incrementable::modifier<T>
, public decrementable::modifier<T>
{
};
};
}
#endif //STRONG_TYPE_BICREMENTABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_BOOLEAN_HPP
#define STRONG_TYPE_BOOLEAN_HPP
namespace strong
{
struct boolean
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type must be convertible to bool");
};
template <typename T>
class modifier<T, impl::void_t<decltype(static_cast<bool>(std::declval<const underlying_type_t<T>>()))>>
{
public:
STRONG_NODISCARD
explicit
STRONG_CONSTEXPR
operator bool()
const
noexcept(noexcept(static_cast<bool>(value_of(std::declval<const T&>()))))
{
const auto& self = static_cast<const T&>(*this);
return static_cast<bool>(value_of(self));
}
};
};
}
#endif //STRONG_TYPE_BOOLEAN_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_POINTER_HPP
#define STRONG_TYPE_POINTER_HPP
namespace strong
{
struct pointer
{
template <typename T, typename = void>
class modifier;
};
template <typename T>
class pointer::modifier<T, void>
{
static_assert(impl::always_false<T>, "Underlying type must support dereferencing with operator*");
};
template <typename T, typename Tag, typename ... M>
class pointer::modifier<::strong::type<T, Tag, M...>, impl::void_t<decltype(*std::declval<T>())>>
{
using type = strong::type<T, Tag, M...>;
public:
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator==(
const type& t,
std::nullptr_t)
noexcept(noexcept(std::declval<const TT&>() == nullptr))
-> decltype(std::declval<const TT&>() == nullptr)
{
return value_of(t) == nullptr;
}
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator==(
std::nullptr_t,
const type& t)
noexcept(noexcept(nullptr == std::declval<const TT&>()))
-> decltype(nullptr == std::declval<const TT&>())
{
return value_of(t) == nullptr;
}
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator!=(
const type& t,
std::nullptr_t)
noexcept(noexcept(std::declval<const TT&>() != nullptr))
-> decltype(std::declval<const TT&>() != nullptr)
{
return value_of(t) != nullptr;
}
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator!=(
std::nullptr_t,
const type& t)
noexcept(noexcept(nullptr != std::declval<const TT&>()))
-> decltype(nullptr != std::declval<const TT&>())
{
return value_of(t) != nullptr;
}
STRONG_NODISCARD
STRONG_CONSTEXPR
decltype(*std::declval<const T&>())
operator*()
const
{
auto& self = static_cast<const type&>(*this);
return *value_of(self);
}
STRONG_NODISCARD
STRONG_CONSTEXPR
decltype(&(*std::declval<const T&>())) operator->() const { return &operator*();}
};
}
#endif //STRONG_TYPE_POINTER_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_HASHABLE_HPP
#define STRONG_TYPE_HASHABLE_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#include <functional>
#endif
namespace strong
{
struct hashable
{
template <typename T>
class modifier{};
};
}
namespace std {
template<typename T, typename Tag, typename ... M>
struct hash<::strong::type<T, Tag, M...>>
: std::conditional_t<
std::is_base_of<
::strong::hashable::modifier<
::strong::type<T, Tag, M...>
>,
::strong::type<T, Tag, M...>
>::value,
hash<T>,
std::false_type>
{
using type = ::strong::type<T, Tag, M...>;
STRONG_NODISCARD
decltype(auto)
operator()(
const ::strong::hashable::modifier<type> &t)
const
noexcept(noexcept(std::declval<hash<T>>()(
value_of(std::declval<const type &>()))))
{
auto &tt = static_cast<const type &>(t);
return hash<T>::operator()(value_of(tt));
}
};
}
#endif //STRONG_TYPE_HASHABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_DIFFERENCE_HPP
#define STRONG_TYPE_DIFFERENCE_HPP
namespace strong
{
namespace impl
{
struct conditionally_ordered
{
template <typename T>
class modifier;
};
template <typename T, typename Tag, typename ... M>
class conditionally_ordered::modifier<::strong::type<T, Tag, M...>>
{
using type = ::strong::type<T, Tag, M...>;
public:
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator<(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const TT&>() < std::declval<const TT&>()))
-> decltype(std::declval<const TT&>() < std::declval<const TT&>())
{
return value_of(lh) < value_of(rh);
}
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator<=(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const TT&>() <= std::declval<const TT&>()))
-> decltype(std::declval<const TT&>() <= std::declval<const TT&>())
{
return value_of(lh) <= value_of(rh);
}
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator>(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const TT&>() > std::declval<const TT&>()))
-> decltype(std::declval<const TT&>() > std::declval<const TT&>())
{
return value_of(lh) > value_of(rh);
}
template <typename TT = T>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto
operator>=(
const type& lh,
const type& rh)
noexcept(noexcept(std::declval<const TT&>() >= std::declval<const TT&>()))
-> decltype(std::declval<const TT&>() >= std::declval<const TT&>())
{
return value_of(lh) >= value_of(rh);
}
};
}
struct difference
{
template <typename T>
class modifier;
};
template <typename T, typename Tag, typename ... M>
class difference::modifier<::strong::type<T, Tag, M...>>
: public impl::conditionally_ordered::modifier<::strong::type<T, Tag, M...>>
, public equality::modifier<::strong::type<T, Tag, M...>>
{
using type = ::strong::type<T, Tag, M...>;
public:
friend
STRONG_CONSTEXPR
type& operator+=(type& lh, const type& rh)
noexcept(noexcept(value_of(lh) += value_of(rh)))
{
value_of(lh) += value_of(rh);
return lh;
}
friend
STRONG_CONSTEXPR
type& operator-=(type& lh, const type& rh)
noexcept(noexcept(value_of(lh) -= value_of(rh)))
{
value_of(lh) -= value_of(rh);
return lh;
}
friend
STRONG_CONSTEXPR
type& operator*=(type& lh, const T& rh)
noexcept(noexcept(value_of(lh) *= rh))
{
value_of(lh) *= rh;
return lh;
}
friend
STRONG_CONSTEXPR
type& operator/=(type& lh, const T& rh)
noexcept(noexcept(value_of(lh) /= rh))
{
value_of(lh) /= rh;
return lh;
}
template <typename TT = T, typename = decltype(std::declval<TT&>()%= std::declval<const TT&>())>
friend
STRONG_CONSTEXPR
type& operator%=(type& lh, const T& rh)
noexcept(noexcept(value_of(lh) %= rh))
{
value_of(lh)%= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type operator+(type lh, const type& rh)
{
lh += rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type operator-(type lh, const type& rh)
{
lh -= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type operator*(type lh, const T& rh)
{
lh *= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type operator*(const T& lh, type rh)
{
rh *= lh;
return rh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type operator/(type lh, const T& rh)
{
lh /= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
T operator/(const type& lh, const type& rh)
{
return value_of(lh) / value_of(rh);
}
template <typename TT = T, typename = decltype(std::declval<TT&>() %= std::declval<const TT&>())>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type operator%(type lh, const T& rh)
noexcept(noexcept(lh%= rh))
{
lh %= rh;
return lh;
}
template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
T operator%(type lh, type rh)
noexcept(noexcept(value_of(lh) % value_of(rh)))
{
return value_of(lh) % value_of(rh);
}
};
}
#endif //STRONG_TYPE_DIFFERENCE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_AFFINE_POINT_HPP
#define STRONG_TYPE_AFFINE_POINT_HPP
namespace strong
{
template <typename D = void>
struct affine_point
{
template <typename T>
class modifier;
};
namespace impl
{
template <typename T, typename = void>
struct subtractable : std::false_type {};
template <typename T>
struct subtractable<T, void_t<decltype(std::declval<const T&>() - std::declval<const T&>())>>
: std::true_type {};
}
template <typename D>
template <typename T, typename Tag, typename ... M>
class affine_point<D>::modifier<::strong::type<T, Tag, M...>>
{
using type = ::strong::type<T, Tag, M...>;
static_assert(impl::subtractable<T>::value, "it must be possible to subtract instances of your underlying type");
using base_diff_type = decltype(std::declval<const T&>() - std::declval<const T&>());
public:
using difference = std::conditional_t<std::is_same<D, void>{}, strong::type<base_diff_type, Tag, strong::difference>, D>;
static_assert(std::is_constructible<difference, base_diff_type>::value, "");
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
difference
operator-(
const type& lh,
const type& rh)
{
return difference(value_of(lh) - value_of(rh));
}
friend
STRONG_CONSTEXPR
type&
operator+=(
type& lh,
const difference& d)
noexcept(noexcept(value_of(lh) += impl::access(d)))
{
value_of(lh) += impl::access(d);
return lh;
}
friend
STRONG_CONSTEXPR
type&
operator-=(
type& lh,
const difference& d)
noexcept(noexcept(value_of(lh) -= impl::access(d)))
{
value_of(lh) -= impl::access(d);
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator+(
type lh,
const difference& d)
{
return lh += d;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator+(
const difference& d,
type rh)
{
return rh+= d;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator-(
type lh,
const difference& d)
{
return lh -= d;
}
};
}
#endif //STRONG_TYPE_AFFINE_POINT_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_ARITHMETIC_HPP
#define STRONG_TYPE_ARITHMETIC_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#include <limits>
#endif
namespace strong
{
struct arithmetic {
template<typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type must support arithmeric operations");
};
};
template <typename T, typename Tag, typename ... Ms>
class arithmetic::modifier<strong::type<T, Tag, Ms...>, impl::void_t<decltype(std::declval<T>() * std::declval<T>() - std::declval<T>() / std::declval<T>())>>
{
using type = strong::type<T, Tag, Ms...>;
public:
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator-(
const type &lh)
{
return type{-value_of(lh)};
}
friend
STRONG_CONSTEXPR
type&
operator+=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) += value_of(rh)))
{
value_of(lh) += value_of(rh);
return lh;
}
friend
STRONG_CONSTEXPR
type&
operator-=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) -= value_of(rh)))
{
value_of(lh) -= value_of(rh);
return lh;
}
friend
STRONG_CONSTEXPR
type&
operator*=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) *= value_of(rh)))
{
value_of(lh) *= value_of(rh);
return lh;
}
friend
STRONG_CONSTEXPR
type&
operator/=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) /= value_of(rh)))
{
value_of(lh) /= value_of(rh);
return lh;
}
template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())>
friend
STRONG_CONSTEXPR
type&
operator%=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) %= value_of(rh)))
{
value_of(lh) %= value_of(rh);
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator+(
type lh,
const type &rh)
{
lh += rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator-(
type lh,
const type &rh)
{
lh -= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator*(
type lh,
const type &rh)
{
lh *= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator/(
type lh,
const type &rh)
{
lh /= rh;
return lh;
}
template <typename TT = T, typename = decltype(std::declval<TT>() % std::declval<TT>())>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator%(
type lh,
const type &rh)
{
lh %= rh;
return lh;
}
};
}
template <typename T, typename Tag, typename ... Ms>
#if defined(__cpp_concepts)
requires strong::type_is_v<strong::type<T, Tag, Ms...>, strong::arithmetic>
class std::numeric_limits<strong::type<T, Tag, Ms...>>
: public std::numeric_limits<T>
#else
class std::numeric_limits<strong::type<T, Tag, Ms...>>
: public std::conditional<
strong::type_is_v<strong::type<T, Tag, Ms...>, strong::arithmetic>,
std::numeric_limits<T>,
std::numeric_limits<void>
>::type
#endif
{
using type = strong::type<T, Tag, Ms...>;
public:
STRONG_NODISCARD static constexpr type min() noexcept { return type{std::numeric_limits<T>::min()};}
STRONG_NODISCARD static constexpr type lowest() noexcept { return type{std::numeric_limits<T>::lowest()};}
STRONG_NODISCARD static constexpr type max() noexcept { return type{std::numeric_limits<T>::max()};}
STRONG_NODISCARD static constexpr type epsilon() noexcept { return type{std::numeric_limits<T>::epsilon()};}
STRONG_NODISCARD static constexpr type round_error() noexcept { return type{std::numeric_limits<T>::round_error()};}
STRONG_NODISCARD static constexpr type infinity() noexcept { return type{std::numeric_limits<T>::infinity()};}
STRONG_NODISCARD static constexpr type quiet_NaN() noexcept { return type{std::numeric_limits<T>::quiet_NaN()};}
STRONG_NODISCARD static constexpr type signaling_NaN() noexcept { return type{std::numeric_limits<T>::signaling_NaN()};}
STRONG_NODISCARD static constexpr type denorm_min() noexcept { return type{std::numeric_limits<T>::denorm_min()};}
};
#endif //STRONG_TYPE_ARITHMETIC_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_BITARITHMETIC_HPP
#define STRONG_TYPE_BITARITHMETIC_HPP
namespace strong
{
struct bitarithmetic
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T>,
"Underlying type must support bitarithmetic operations &, | and ^");
};
template <typename T, typename Tag, typename ... Ms>
class modifier<type<T, Tag, Ms...>, impl::void_t<decltype(((std::declval<T&>() |= std::declval<T>()) &= std::declval<T>()) ^= std::declval<T>())>>
{
using type = strong::type<T, Tag, Ms...>;
public:
friend
STRONG_CONSTEXPR
type&
operator&=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) &= value_of(rh)))
{
value_of(lh) = T(value_of(lh) & value_of(rh));
return lh;
}
friend
STRONG_CONSTEXPR
type&
operator|=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) |= value_of(rh)))
{
value_of(lh) = T(value_of(lh) | value_of(rh));
return lh;
}
friend
STRONG_CONSTEXPR
type&
operator^=(
type &lh,
const type &rh)
noexcept(noexcept(value_of(lh) ^= value_of(rh)))
{
value_of(lh) = T(value_of(lh) ^ value_of(rh));
return lh;
}
template <typename C>
friend
STRONG_CONSTEXPR
type&
operator<<=(
type &lh,
C c)
noexcept(noexcept(value_of(lh) <<= c))
{
value_of(lh) = T(value_of(lh) << c);
return lh;
}
template <typename C>
friend
STRONG_CONSTEXPR
type&
operator>>=(
type &lh,
C c)
noexcept(noexcept(value_of(lh) >>= c))
{
value_of(lh) = T(value_of(lh) >> c);
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator~(
const type &lh)
{
auto v = value_of(lh);
return type(T(~v));
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator&(
type lh,
const type &rh)
{
lh &= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator|(
type lh,
const type &rh)
{
lh |= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator^(
type lh,
const type &rh)
{
lh ^= rh;
return lh;
}
template <typename C>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator<<(
type lh,
C c)
{
lh <<= c;
return lh;
}
template <typename C>
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
type
operator>>(
type lh,
C c)
{
lh >>= c;
return lh;
}
};
};
}
#endif //STRONG_TYPE_BITARITHMETIC_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_INDEXED_HPP
#define STRONG_TYPE_INDEXED_HPP
namespace strong
{
template <typename I = void>
struct indexed
{
template <typename T, typename = void>
class modifier
{
static_assert(impl::always_false<T, I>,
"Underlying type must support indexing using operator[]");
};
};
template <>
struct indexed<void> {
template<typename>
class modifier;
template <typename T, typename Tag, typename ... Ms>
class modifier<type<T, Tag, Ms...>> {
using ref = T&;
using cref = const T&;
using rref = T&&;
using type = strong::type<T, Tag, Ms...>;
public:
template<typename I>
STRONG_NODISCARD
auto
operator[](
const I &i)
const &
noexcept(noexcept(std::declval<cref>()[impl::access(i)]))
-> decltype(std::declval<cref>()[impl::access(i)]) {
auto& self = static_cast<const type&>(*this);
return value_of(self)[impl::access(i)];
}
template<typename I>
STRONG_NODISCARD
auto
operator[](
const I &i)
&
noexcept(noexcept(std::declval<ref>()[impl::access(i)]))
-> decltype(std::declval<ref>()[impl::access(i)]) {
auto& self = static_cast<type&>(*this);
return value_of(self)[impl::access(i)];
}
template<typename I>
STRONG_NODISCARD
auto
operator[](
const I &i)
&&
noexcept(noexcept(std::declval<rref>()[impl::access(i)]))
-> decltype(std::declval<rref>()[impl::access(i)]) {
auto& self = static_cast<type&>(*this);
return value_of(std::move(self))[impl::access(i)];
}
template<typename I, typename C = cref>
STRONG_NODISCARD
auto
at(
const I &i)
const &
-> decltype(std::declval<C>().at(impl::access(i))) {
auto& self = static_cast<const type&>(*this);
return value_of(self).at(impl::access(i));
}
template<typename I, typename R = ref>
STRONG_NODISCARD
auto
at(
const I &i)
&
-> decltype(std::declval<R>().at(impl::access(i))) {
auto& self = static_cast<type&>(*this);
return value_of(self).at(impl::access(i));
}
template<typename I, typename R = rref>
STRONG_NODISCARD
auto
at(
const I &i)
&&
-> decltype(std::declval<R>().at(impl::access(i))) {
auto& self = static_cast<type&>(*this);
return value_of(std::move(self)).at(impl::access(i));
}
};
};
template <typename I>
template <typename T, typename Tag, typename ... M>
class indexed<I>::modifier<
type<T, Tag, M...>,
impl::void_t< decltype( std::declval<const T&>()[std::declval<underlying_type_t<I>>()] ) >
>
{
using type = ::strong::type<T, Tag, M...>;
public:
STRONG_NODISCARD
auto
operator[](
const I& i)
const &
noexcept(noexcept(std::declval<const T&>()[impl::access(i)]))
-> decltype(std::declval<const T&>()[impl::access(i)])
{
auto& self = static_cast<const type&>(*this);
return value_of(self)[impl::access(i)];
}
STRONG_NODISCARD
auto
operator[](
const I& i)
&
noexcept(noexcept(std::declval<T&>()[impl::access(i)]))
-> decltype(std::declval<T&>()[impl::access(i)])
{
auto& self = static_cast<type&>(*this);
return value_of(self)[impl::access(i)];
}
STRONG_NODISCARD
auto
operator[](
const I& i)
&&
noexcept(noexcept(std::declval<T&&>()[impl::access(i)]))
-> decltype(std::declval<T&&>()[impl::access(i)])
{
auto& self = static_cast<type&>(*this);
return value_of(std::move(self))[impl::access(i)];
}
template <typename TT = T>
STRONG_NODISCARD
auto
at(
const I& i)
const &
-> decltype(std::declval<const TT&>().at(impl::access(i)))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).at(impl::access(i));
}
template <typename TT = T>
STRONG_NODISCARD
auto
at(
const I& i)
&
-> decltype(std::declval<TT&>().at(impl::access(i)))
{
auto& self = static_cast<type&>(*this);
return value_of(self).at(impl::access(i));
}
template <typename TT = T>
STRONG_NODISCARD
auto
at(
const I& i)
&&
-> decltype(std::declval<TT&&>().at(impl::access(i)))
{
auto& self = static_cast<type&>(*this);
return value_of(std::move(self)).at(impl::access(i));
}
};
}
#endif //STRONG_TYPE_INDEXED_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_ITERATOR_HPP
#define STRONG_TYPE_ITERATOR_HPP
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#include <iterator>
#endif
#if __cplusplus >= 202002L && (((! defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000)) && (!defined(__GLIBCXX__) || __GLIBCXX__ >= 20230528L))
#define STRONG_TYPE_CONTIGUOUS_ITERATOR 1
#else
#define STRONG_TYPE_CONTIGUOUS_ITERATOR 0
#endif
namespace strong
{
namespace internal {
template <typename I, typename = void>
struct iterator_traits
{
using iterator_category = std::input_iterator_tag;
using difference_type = typename I::difference_type;
using reference = decltype(*std::declval<I>());
using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
using pointer = value_type*;
};
template <typename I>
struct iterator_traits<I, impl::void_t<typename I::iterator_category>>
{
using iterator_category = typename I::iterator_category;
using difference_type = typename I::difference_type;
using reference = decltype(*std::declval<I>());
using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
using pointer = value_type*;
};
template <typename T>
struct iterator_traits<T*, void>
{
#if STRONG_TYPE_CONTIGUOUS_ITERATOR
using iterator_category = std::contiguous_iterator_tag;
#else
using iterator_category = std::random_access_iterator_tag;
#endif
using difference_type = std::ptrdiff_t;
using value_type = T;
using reference = T&;
using pointer = T*;
};
}
class iterator
{
public:
template <typename I,
typename category = typename internal::iterator_traits<underlying_type_t<I>>::iterator_category>
class modifier
: public pointer::modifier<I>
, public incrementable::modifier<I>
{
public:
using difference_type = typename internal::iterator_traits<underlying_type_t<I>>::difference_type;
using value_type = typename internal::iterator_traits<underlying_type_t<I>>::value_type;
using pointer = typename internal::iterator_traits<underlying_type_t<I>>::pointer;
using reference = typename internal::iterator_traits<underlying_type_t<I>>::reference;
using iterator_category = typename internal::iterator_traits<underlying_type_t<I>>::iterator_category;
};
template <typename I>
class modifier<I, std::forward_iterator_tag>
: public modifier<I, std::input_iterator_tag>
, public strong::equality::modifier<I>
{};
template <typename I>
class modifier<I, std::bidirectional_iterator_tag>
: public modifier<I, std::forward_iterator_tag>
, public decrementable::modifier<I>
{
};
template <typename I>
class modifier<I, std::random_access_iterator_tag>
: public modifier<I, std::bidirectional_iterator_tag>
, public affine_point<typename std::iterator_traits<underlying_type_t<I>>::difference_type>::template modifier<I>
, public indexed<>::modifier<I>
, public ordered::modifier<I>
{
};
#if STRONG_TYPE_CONTIGUOUS_ITERATOR
template <typename I>
class modifier<I, std::contiguous_iterator_tag>
: public modifier<I, std::bidirectional_iterator_tag>
, public affine_point<typename std::iterator_traits<underlying_type_t<I>>::difference_type>::template modifier<I>
, public indexed<>::modifier<I>
, public ordered::modifier<I>
{
};
#endif
};
}
#endif //STRONG_TYPE_ITERATOR_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_RANGE_HPP
#define STRONG_TYPE_RANGE_HPP
#if __has_include(<ranges>)
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
# include <ranges>
#endif
#endif
#if defined(_MSC_VER) && __cpp_lib_ranges >= 202110L
# define STRONG_TYPE_HAS_RANGES
#endif
#if __cplusplus >= 202101L
# if (not defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L)) && (__cpp_lib_ranges >= 202106L)
# define STRONG_TYPE_HAS_RANGES
# endif
# if (not defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 15000)
# define STRONG_TYPE_HAS_RANGES
# endif
#endif
namespace strong
{
namespace internal {
struct not_an_iterator {};
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L))
template <typename T>
auto begin_type(T* t) -> decltype(std::ranges::begin(*t));
#else
template <typename T>
auto begin_type(T* t) -> decltype(t->begin());
#endif
auto begin_type(...) -> not_an_iterator;
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L))
template <typename T>
auto const_begin_type(const T* t) -> decltype(std::ranges::begin(*t));
#else
template <typename T>
auto const_begin_type(const T* t) -> decltype(t->begin());
#endif
auto const_begin_type(...) -> not_an_iterator;
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L))
template <typename T>
auto end_type(T* t) -> decltype(std::ranges::end(*t));
#else
template <typename T>
auto end_type(T* t) -> decltype(t->end());
#endif
auto end_type(...) -> not_an_iterator;
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L))
template <typename T>
auto const_end_type(const T* t) -> decltype(std::ranges::end(*t));
#else
template <typename T>
auto const_end_type(const T* t) -> decltype(t->end());
#endif
auto const_end_type(...) -> not_an_iterator;
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L))
template <typename T>
auto cbegin_type(const T* t) -> decltype(std::ranges::cbegin(*t));
#else
template <typename T>
auto cbegin_type(const T* t) -> decltype(t->cbegin());
#endif
auto cbegin_type(...) -> not_an_iterator;
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230528L))
template <typename T>
auto cend_type(const T* t) -> decltype(std::ranges::cend(*t));
#else
template <typename T>
auto cend_type(const T* t) -> decltype(t->cend());
#endif
auto cend_type(...) -> not_an_iterator;
template <typename T>
struct begin_end_traits
{
using begin_iterator = decltype(begin_type(std::declval<T*>()));
using const_begin_iterator = decltype(const_begin_type(std::declval<const T*>()));
using end_iterator = decltype(end_type(std::declval<T*>()));
using const_end_iterator = decltype(const_end_type(std::declval<const T*>()));
using cbegin_iterator = decltype(cbegin_type(std::declval<const T*>()));
using cend_iterator = decltype(cend_type(std::declval<const T*>()));
};
constexpr bool is_random_access(std::random_access_iterator_tag) { return true;}
constexpr bool is_random_access(std::input_iterator_tag) { return false;}
constexpr bool is_random_access(std::output_iterator_tag) { return false;}
}
#if defined(STRONG_TYPE_HAS_RANGES) && (!defined(__GLIBCXX__) || (__GLIBCXX__ >= 20230601L))
#define STRONG_TYPE_BEGIN(x) std::ranges::begin(x)
#define STRONG_TYPE_END(x) std::ranges::end(x)
#define STRONG_TYPE_CBEGIN(x) std::ranges::cbegin(x)
#define STRONG_TYPE_CEND(x) std::ranges::cend(x)
#else
#define STRONG_TYPE_BEGIN(x) x.begin()
#define STRONG_TYPE_END(x) x.end()
#define STRONG_TYPE_CBEGIN(x) x.cbegin()
#define STRONG_TYPE_CEND(x) x.cend()
#endif
class range
{
public:
template <
typename R,
typename = typename internal::begin_end_traits<underlying_type_t<R>>::begin_iterator,
typename = typename internal::begin_end_traits<underlying_type_t<R>>::end_iterator,
typename = typename internal::begin_end_traits<underlying_type_t<R>>::const_begin_iterator,
typename = typename internal::begin_end_traits<underlying_type_t<R>>::const_end_iterator,
typename = typename internal::begin_end_traits<underlying_type_t<R>>::cbegin_iterator,
typename = typename internal::begin_end_traits<underlying_type_t<R>>::cend_iterator>
class modifier;
};
template <typename R>
class range::modifier<
R,
internal::not_an_iterator, internal::not_an_iterator,
internal::not_an_iterator, internal::not_an_iterator,
internal::not_an_iterator, internal::not_an_iterator
>
{
static_assert(impl::always_false<R>,
"Underlying type must have begin() and end()");
};
template <typename T, typename Tag, typename ... M, typename r_iterator>
class range::modifier<
type<T, Tag, M...>,
r_iterator, r_iterator,
r_iterator, r_iterator,
r_iterator, r_iterator>
{
using type = ::strong::type<T, Tag, M...>;
static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits<r_iterator>::iterator_category{});
public:
using const_iterator = std::conditional_t<random_access,
::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<r_iterator>, strong::ordered_with<r_iterator>>,
::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<r_iterator>>
>;
STRONG_NODISCARD
constexpr
const_iterator
begin()
const
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
end()
const
noexcept(noexcept(STRONG_TYPE_END(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_END(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
cbegin()
const
noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
cend()
const
noexcept(noexcept(STRONG_TYPE_CEND(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_CEND(value_of(self))};
}
template <typename TT = const T&>
STRONG_NODISCARD
constexpr
decltype(std::declval<TT>().size())
size()
const
noexcept(noexcept(std::declval<TT>().size()))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).size();
}
};
template <typename T, typename Tag, typename ... M, typename r_iterator, typename r_const_iterator>
class range::modifier<
type<T, Tag, M...>,
r_iterator, r_iterator,
r_const_iterator, r_const_iterator,
r_const_iterator, r_const_iterator
>
{
using type = ::strong::type<T, Tag, M...>;
static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits<r_iterator>::iterator_category{});
public:
using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>;
using const_iterator = std::conditional_t<random_access,
::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>, strong::ordered_with<iterator>>,
::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>>
>;
STRONG_NODISCARD
constexpr
iterator
begin()
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
iterator
end()
noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return iterator{STRONG_TYPE_END(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
begin()
const
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
end()
const
noexcept(noexcept(STRONG_TYPE_END(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_END(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
cbegin()
const
noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
cend()
const
noexcept(noexcept(STRONG_TYPE_CEND(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_CEND(value_of(self))};
}
template <typename TT = const T&>
STRONG_NODISCARD
constexpr
decltype(std::declval<TT>().size())
size()
const
noexcept(noexcept(std::declval<TT>().size()))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).size();
}
};
template <typename T, typename Tag, typename ... M, typename r_iterator, typename r_const_iterator, typename r_sentinel>
class range::modifier<
type<T, Tag, M...>,
r_iterator, r_sentinel,
r_iterator, r_sentinel,
r_const_iterator, r_sentinel
>
{
using type = ::strong::type<T, Tag, M...>;
static constexpr bool random_access = internal::is_random_access(typename internal::iterator_traits<r_iterator>::iterator_category{});
public:
using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>;
using const_iterator = std::conditional_t<random_access,
::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>, strong::ordered_with<iterator>>,
::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible, strong::equality_with<iterator>>
>;
using sentinel = strong::type<r_sentinel, Tag, strong::equality_with<iterator, const_iterator>>;
STRONG_NODISCARD
constexpr
iterator
begin()
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
sentinel
end()
noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return sentinel{STRONG_TYPE_END(value_of(self))};
}
STRONG_NODISCARD
constexpr
iterator
begin()
const
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
sentinel
end()
const
noexcept(noexcept(STRONG_TYPE_END(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return sentinel{STRONG_TYPE_END(value_of(self))};
}
STRONG_NODISCARD
constexpr
const_iterator
cbegin()
const
noexcept(noexcept(STRONG_TYPE_CBEGIN(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_CBEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
sentinel
cend()
const
noexcept(noexcept(STRONG_TYPE_CEND(std::declval<const T&>())))
{
auto& self = static_cast<const type&>(*this);
return sentinel{STRONG_TYPE_CEND(value_of(self))};
}
template <typename TT = const T&>
STRONG_NODISCARD
constexpr
decltype(std::declval<TT>().size())
size()
const
noexcept(noexcept(std::declval<TT>().size()))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).size();
}
};
template <typename T, typename Tag, typename ... M, typename r_iterator>
class range::modifier<
type<T, Tag, M...>,
r_iterator, r_iterator,
internal::not_an_iterator, internal::not_an_iterator,
internal::not_an_iterator, internal::not_an_iterator
>
{
using type = ::strong::type<T, Tag, M...>;
public:
using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>;
STRONG_NODISCARD
constexpr
iterator
begin()
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
iterator
end()
noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return iterator{STRONG_TYPE_END(value_of(self))};
}
template <typename TT = const T&>
STRONG_NODISCARD
constexpr
decltype(std::declval<TT>().size())
size()
const
noexcept(noexcept(std::declval<TT>().size()))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).size();
}
};
template <typename T, typename Tag, typename ... M, typename r_iterator, typename r_sentinel>
class range::modifier<
type<T, Tag, M...>,
r_iterator, r_sentinel,
internal::not_an_iterator, internal::not_an_iterator,
internal::not_an_iterator, internal::not_an_iterator
>
{
using type = ::strong::type<T, Tag, M...>;
public:
using iterator = ::strong::type<r_iterator, Tag, strong::iterator, strong::default_constructible>;
using sentinel = ::strong::type<r_sentinel, Tag, strong::equality_with<iterator>>;
STRONG_NODISCARD
constexpr
iterator
begin()
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
sentinel
end()
noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>())))
{
auto& self = static_cast<type&>(*this);
return sentinel{STRONG_TYPE_END(value_of(self))};
}
template <typename TT = const T&>
STRONG_NODISCARD
constexpr
decltype(std::declval<TT>().size())
size()
const
noexcept(noexcept(std::declval<TT>().size()))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).size();
}
};
template <typename T, typename Tag, typename ... M, typename r_const_iterator, typename r_sentinel>
class range::modifier<
type<T, Tag, M...>,
internal::not_an_iterator, internal::not_an_iterator,
r_const_iterator, r_sentinel,
internal::not_an_iterator, internal::not_an_iterator
>
{
using type = ::strong::type<T, Tag, M...>;
public:
using const_iterator = ::strong::type<r_const_iterator, Tag, strong::iterator, strong::default_constructible>;
using sentinel = ::strong::type<r_sentinel, Tag, strong::equality_with<const_iterator>>;
STRONG_NODISCARD
constexpr
const_iterator
begin()
const
noexcept(noexcept(STRONG_TYPE_BEGIN(std::declval<T&>())))
{
auto& self = static_cast<const type&>(*this);
return const_iterator{STRONG_TYPE_BEGIN(value_of(self))};
}
STRONG_NODISCARD
constexpr
sentinel
end()
const
noexcept(noexcept(STRONG_TYPE_END(std::declval<T&>())))
{
auto& self = static_cast<const type&>(*this);
return sentinel{STRONG_TYPE_END(value_of(self))};
}
template <typename TT = const T&>
STRONG_NODISCARD
constexpr
decltype(std::declval<TT>().size())
size()
const
noexcept(noexcept(std::declval<TT>().size()))
{
auto& self = static_cast<const type&>(*this);
return value_of(self).size();
}
};
}
#endif //STRONG_TYPE_RANGE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_CONVERTIBLE_TO_HPP
#define STRONG_TYPE_CONVERTIBLE_TO_HPP
namespace strong
{
namespace impl
{
template<typename T, typename D, typename = void>
struct converter
{
static_assert(always_false<T, D>,
"Underlying type must be convertible to target type");
};
template <typename T, typename Tag, typename ... Ms, typename D>
struct converter<
strong::type<T, Tag, Ms...>,
D,
impl::void_t<decltype(static_cast<D>(std::declval<const T&>()))>
>
{
STRONG_CONSTEXPR explicit operator D() const
noexcept(noexcept(static_cast<D>(std::declval<const T&>())))
{
auto& self = static_cast<const strong::type<T, Tag, Ms...>&>(*this);
return static_cast<D>(value_of(self));
}
};
}
template <typename ... Ts>
struct convertible_to
{
template <typename T>
struct modifier : impl::converter<T, Ts>...
{
};
};
}
#endif //STRONG_TYPE_CONVERTIBLE_TO_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP
#define STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP
namespace strong
{
namespace impl {
template<typename T, typename D, typename = void>
struct implicit_converter
{
static_assert(impl::always_false<T,D>,
"Underlying type must be convertible to target type");
};
template <typename T, typename Tag, typename ... Ms, typename D>
struct implicit_converter<
strong::type<T, Tag, Ms...>,
D,
void_t<decltype(static_cast<D>(std::declval<const T&>()))>
>
{
STRONG_CONSTEXPR operator D() const
noexcept(noexcept(static_cast<D>(std::declval<const T&>())))
{
auto& self = static_cast<const strong::type<T, Tag, Ms...>&>(*this);
return static_cast<D>(value_of(self));
}
};
}
template <typename ... Ts>
struct implicitly_convertible_to
{
template <typename T>
struct modifier : impl::implicit_converter<T, Ts>...
{
};
};
}
#endif //STRONG_TYPE_IMPLICITLY_CONVERTIBLE_TO_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_FORMATTABLE_HPP
#define STRONG_TYPE_FORMATTABLE_HPP
#ifndef STRONG_HAS_STD_FORMAT
#if __has_include(<version>)
#include <version>
#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907
#define STRONG_HAS_STD_FORMAT 1
#endif
#endif
#endif
#ifndef STRONG_HAS_STD_FORMAT
#define STRONG_HAS_STD_FORMAT 0
#endif
#ifndef STRONG_HAS_FMT_FORMAT
#if __has_include(<fmt/format.h>)
#define STRONG_HAS_FMT_FORMAT 1
#else
#define STRONG_HAS_FMT_FORMAT 0
#endif
#endif
#if STRONG_HAS_STD_FORMAT
#if !defined(STRONG_TYPE_IMPORT_STD_LIBRARY)
#include <format>
#endif
#endif
#if STRONG_HAS_FMT_FORMAT
#include <fmt/format.h>
#include <fmt/ostream.h>
#endif
namespace strong
{
struct formattable
{
template <typename T>
class modifier{};
};
template <typename T>
using is_formattable = std::is_base_of<formattable::modifier<T>, T>;
}
#if STRONG_HAS_STD_FORMAT
namespace std
{
template<typename T, typename Tag, typename... M, typename Char>
requires std::is_base_of_v<::strong::formattable::modifier<::strong::type<T, Tag, M...>>,
::strong::type<T, Tag, M...>>
struct formatter<::strong::type<T, Tag, M...>, Char> : formatter<T, Char>
{
template<typename FormatContext, typename Type>
STRONG_CONSTEXPR
decltype(auto)
format(const Type& t, FormatContext& fc) const
noexcept(noexcept(std::declval<formatter<T, Char>>().format(std::declval<const T&>(), fc)))
{
return formatter<T, Char>::format(value_of(t), fc);
}
template<typename FormatContext, typename Type>
STRONG_CONSTEXPR
decltype(auto)
format(const Type& t, FormatContext& fc)
noexcept(noexcept(std::declval<formatter<T, Char>>().format(std::declval<const T&>(), fc)))
{
return formatter<T, Char>::format(value_of(t), fc);
}
};
}
#endif
#if STRONG_HAS_FMT_FORMAT
namespace strong {
template <typename T, typename Char>
struct formatter;
template <typename T, typename Tag, typename ... M, typename Char>
struct formatter<type<T, Tag, M...>, Char> : fmt::formatter<T, Char>
{
template<typename FormatContext, typename Type>
STRONG_CONSTEXPR
decltype(auto)
format(const Type& t, FormatContext& fc) const
noexcept(noexcept(std::declval<fmt::formatter<T, Char>>().format(std::declval<const T&>(), fc)))
{
return fmt::formatter<T, Char>::format(value_of(t), fc);
}
template<typename FormatContext, typename Type>
STRONG_CONSTEXPR
decltype(auto)
format(const Type& t, FormatContext& fc)
noexcept(noexcept(std::declval<fmt::formatter<T, Char>>().format(std::declval<const T&>(), fc)))
{
return fmt::formatter<T, Char>::format(value_of(t), fc);
}
};
#if FMT_VERSION >= 90000
template <typename T, typename Char, bool = is_formattable<T>::value>
struct select_formatter;
template <typename T, typename Char>
struct select_formatter<T, Char, true>
{
using type = formatter<T, Char>;
};
template <typename T, typename Char>
struct select_formatter<T, Char, false>
{
using type = fmt::ostream_formatter;
};
#endif
}
namespace fmt
{
#if FMT_VERSION >= 90000
template <typename T, typename Tag, typename ... M, typename Char>
struct formatter<::strong::type<T, Tag, M...>,
Char,
::strong::impl::void_t<std::enable_if_t<::strong::is_ostreamable<::strong::type<T, Tag, M...>>::value ||
::strong::is_formattable<::strong::type<T, Tag, M...>>::value>>>
: ::strong::select_formatter<::strong::type<T, Tag, M...>, Char>::type
{
};
#else
template<typename T, typename Tag, typename... M, typename Char>
struct formatter<::strong::type<T, Tag, M...>,
Char,
::strong::impl::void_t<std::enable_if_t<::strong::is_formattable<::strong::type<T, Tag, M...>>::value>>
>
: ::strong::formatter<::strong::type<T, Tag, M...>, Char>
{
};
#endif
}
#endif
#endif //STRONG_TYPE_FORMATTABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef STRONG_TYPE_SCALABLE_HPP
#define STRONG_TYPE_SCALABLE_HPP
namespace strong
{
namespace impl
{
template <typename ...>
struct first_type;
template <typename T>
struct first_type<T>
{
using type = T;
};
template <typename T, typename ...Ts>
struct first_type<T, Ts...> {
using type = T;
};
template <typename ... Ts>
using first_type_t = typename first_type<Ts...>::type;
template <typename T, typename Other, typename = void>
class typed_scalable
{
static_assert(impl::always_false<T, Other>,
"Underlying type must be multiplyable and divisible by other type");
};
template <typename T, typename Other>
class typed_scalable<
T,
Other,
impl::void_t<decltype((std::declval<underlying_type_t<T>&>()/=std::declval<underlying_type_t<Other>>())*=std::declval<underlying_type_t<Other>>())>
>
{
using TT = underlying_type_t<T>;
using OT = underlying_type_t<Other>;
public:
friend
STRONG_CONSTEXPR
auto operator/=(T& lh, const Other& rh)
noexcept(noexcept(std::declval<TT&>() / std::declval<const OT&>())
&& std::is_nothrow_move_assignable<TT>::value)
-> T&
{
value_of(lh) = static_cast<TT>(value_of(lh) / impl::access(rh));
return lh;
}
friend
STRONG_CONSTEXPR
auto operator*=(T& lh, const Other& rh)
noexcept(noexcept(std::declval<TT&>() * std::declval<const OT&>())
&& std::is_nothrow_move_assignable<TT>::value)
-> T&
{
value_of(lh) = static_cast<TT>(value_of(lh) * impl::access(rh));
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator/(T lh, const Other& rh)
noexcept(noexcept(lh /= rh))
-> T
{
lh /= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator*(T lh, const Other& rh)
noexcept(noexcept(lh *= rh))
-> T
{
lh *= rh;
return lh;
}
STRONG_NODISCARD
friend
STRONG_CONSTEXPR
auto operator*(const Other& lh, T rh)
noexcept(noexcept(rh *= lh))
-> T
{
rh *= lh;
return rh;
}
};
}
template <typename ... Ts>
struct scalable_with
{
template <typename T>
class modifier : public impl::typed_scalable<T, Ts>...
{
public:
using scalable_modifier_result_type = impl::first_type_t<Ts...>;
};
};
}
template <
typename TT,
typename UT = strong::underlying_type_t<TT>,
typename R = typename TT::scalable_modifier_result_type,
typename = std::enable_if_t<std::is_constructible<R, decltype(std::declval<const UT&>() / std::declval<const UT&>())>::value>
>
STRONG_NODISCARD
inline
STRONG_CONSTEXPR
auto operator/(const TT& lh, const TT& rh)
noexcept(noexcept(std::declval<const UT&>() / std::declval<const UT&>()))
-> R
{
return R{value_of(lh) / value_of(rh)};
}
#endif //STRONG_TYPE_SCALABLE_HPP
/*
* strong_type C++14/17/20 strong typedef library
*
* Copyright (C) Björn Fahller
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* Project home: https://github.com/rollbear/strong_type
*/
#ifndef ROLLBEAR_STRONG_TYPE_HPP_INCLUDED
#define ROLLBEAR_STRONG_TYPE_HPP_INCLUDED
#endif //ROLLBEAR_STRONG_TYPE_HPP_INCLUDED
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment