mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-21 13:53:37 +00:00
committed by
Konstantin Pastbin
parent
c9cbb64f12
commit
76ffc99abd
170
libs/base/newtype.hpp
Normal file
170
libs/base/newtype.hpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace base
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
template <typename From, typename To>
|
||||
using IsConvertibleGuard = std::enable_if_t<std::is_convertible<From, To>::value> *;
|
||||
} // namespace impl
|
||||
|
||||
/// Creates a typesafe alias to a given numeric Type.
|
||||
template <typename Type, typename Tag, typename Hasher = std::hash<Type>>
|
||||
class NewType
|
||||
{
|
||||
static_assert(std::is_integral<Type>::value || std::is_floating_point<Type>::value,
|
||||
"NewType can be used only with integral and floating point type.");
|
||||
|
||||
public:
|
||||
using RepType = Type;
|
||||
|
||||
template <typename V, impl::IsConvertibleGuard<V, Type> = nullptr>
|
||||
constexpr explicit NewType(V const & v) : m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr NewType() = default;
|
||||
|
||||
template <typename V, impl::IsConvertibleGuard<V, Type> = nullptr>
|
||||
NewType & Set(V const & v)
|
||||
{
|
||||
m_value = static_cast<Type>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Type const & Get() const { return m_value; }
|
||||
Type & Get() { return m_value; }
|
||||
|
||||
NewType & operator++()
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType const operator++(int)
|
||||
{
|
||||
auto const copy = *this;
|
||||
++m_value;
|
||||
return copy;
|
||||
}
|
||||
|
||||
NewType & operator--()
|
||||
{
|
||||
--m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType const operator--(int)
|
||||
{
|
||||
auto const copy = *this;
|
||||
--m_value;
|
||||
return copy;
|
||||
}
|
||||
|
||||
NewType & operator+=(NewType const & v)
|
||||
{
|
||||
m_value += v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator-=(NewType const & v)
|
||||
{
|
||||
m_value -= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator*=(NewType const & v)
|
||||
{
|
||||
m_value *= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator/=(NewType const & v)
|
||||
{
|
||||
m_value /= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator%=(NewType const & v)
|
||||
{
|
||||
m_value %= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator^=(NewType const & v)
|
||||
{
|
||||
m_value ^= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator|=(NewType const & v)
|
||||
{
|
||||
m_value |= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
NewType & operator&=(NewType const & v)
|
||||
{
|
||||
m_value &= v.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO(mgsergio): Is it meaningful for a newtype to have << operator ?
|
||||
// NewType & operator<<=(NewType<V, VTag> const & v)
|
||||
// NewType & operator>>=(NewType<V, VTag> const & v)
|
||||
|
||||
bool operator==(NewType const & o) const { return m_value == o.m_value; }
|
||||
bool operator!=(NewType const & o) const { return !(m_value == o.m_value); }
|
||||
bool operator<(NewType const & o) const { return m_value < o.m_value; }
|
||||
bool operator>(NewType const & o) const { return m_value > o.m_value; }
|
||||
bool operator<=(NewType const & o) const { return !(m_value > o.m_value); }
|
||||
bool operator>=(NewType const & o) const { return !(m_value < o.m_value); }
|
||||
NewType operator+(NewType const & o) const { return NewType(m_value + o.m_value); }
|
||||
NewType operator-(NewType const & o) const { return NewType(m_value - o.m_value); }
|
||||
NewType operator*(NewType const & o) const { return NewType(m_value * o.m_value); }
|
||||
NewType operator/(NewType const & o) const { return NewType(m_value / o.m_value); }
|
||||
NewType operator%(NewType const & o) const { return NewType(m_value % o.m_value); }
|
||||
NewType operator^(NewType const & o) const { return NewType(m_value ^ o.m_value); }
|
||||
NewType operator|(NewType const & o) const { return NewType(m_value | o.m_value); }
|
||||
NewType operator&(NewType const & o) const { return NewType(m_value & o.m_value); }
|
||||
|
||||
struct Hash
|
||||
{
|
||||
size_t operator()(NewType const & v) const
|
||||
{
|
||||
Hasher h;
|
||||
return h(v.Get());
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
Type m_value;
|
||||
};
|
||||
|
||||
namespace newtype_default_output
|
||||
{
|
||||
template <typename Type, typename Tag>
|
||||
std::string SimpleDebugPrint(NewType<Type, Tag> const & nt)
|
||||
{
|
||||
return ::DebugPrint(nt.Get());
|
||||
}
|
||||
} // namespace newtype_default_output
|
||||
} // namespace base
|
||||
|
||||
#define NEWTYPE(REPR, NAME) \
|
||||
struct NAME##_tag; \
|
||||
using NAME = base::NewType<REPR, NAME##_tag>
|
||||
|
||||
#define NEWTYPE_SIMPLE_OUTPUT(NAME) \
|
||||
inline std::string DebugPrint(NAME const & nt) \
|
||||
{ \
|
||||
return base::newtype_default_output::SimpleDebugPrint(nt); \
|
||||
} \
|
||||
inline std::ostream & operator<<(std::ostream & ost, NAME const & nt) \
|
||||
{ \
|
||||
return ost << base::newtype_default_output::SimpleDebugPrint(nt); \
|
||||
}
|
||||
Reference in New Issue
Block a user