#pragma once #include #include #include #include namespace base { namespace impl { template using IsConvertibleGuard = std::enable_if_t::value> *; } // namespace impl /// Creates a typesafe alias to a given numeric Type. template > class NewType { static_assert(std::is_integral::value || std::is_floating_point::value, "NewType can be used only with integral and floating point type."); public: using RepType = Type; template = nullptr> constexpr explicit NewType(V const & v) : m_value(v) { } constexpr NewType() = default; template = nullptr> NewType & Set(V const & v) { m_value = static_cast(v); return *this; } Type const & Get() const { return m_value; } Type & Get() { return m_value; } NewType & operator=(NewType const & v) { m_value = v.m_value; return *this; } 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 const & v) // NewType & operator>>=(NewType 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 std::string SimpleDebugPrint(NewType const & nt) { return ::DebugPrint(nt.Get()); } } // namespace newtype_default_output } // namespace base #define NEWTYPE(REPR, NAME) \ struct NAME##_tag; \ using NAME = base::NewType #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); \ }