Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorygorshenin <mipt.vi002@gmail.com>2016-08-22 18:59:13 +0300
committerGitHub <noreply@github.com>2016-08-22 18:59:13 +0300
commit14f20c22deafe44847b181c51d570a147b6b6dbc (patch)
tree41bc6976eb8b56b9f0bbe9e4092e308dcad5d765 /base
parentbca3d1daecbc53f6ba80be2f9de2b6cc76ed8035 (diff)
parentfb37f2ac3db5c2343263bbe23944a9e10565427f (diff)
Merge pull request #4123 from mgsergio/strong-typedefs
Add NewType class to have strong typedefs for primitive types.
Diffstat (limited to 'base')
-rw-r--r--base/base.pro1
-rw-r--r--base/base_tests/base_tests.pro1
-rw-r--r--base/base_tests/newtype_test.cpp99
-rw-r--r--base/newtype.hpp142
4 files changed, 243 insertions, 0 deletions
diff --git a/base/base.pro b/base/base.pro
index 49052f5b1a..d0976ea2f7 100644
--- a/base/base.pro
+++ b/base/base.pro
@@ -54,6 +54,7 @@ HEADERS += \
matrix.hpp \
mem_trie.hpp \
mutex.hpp \
+ newtype.hpp \
object_tracker.hpp \
observer_list.hpp \
range_iterator.hpp \
diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro
index 7624cc052f..7fa3e5a31b 100644
--- a/base/base_tests/base_tests.pro
+++ b/base/base_tests/base_tests.pro
@@ -23,6 +23,7 @@ SOURCES += \
const_helper.cpp \
containers_test.cpp \
logging_test.cpp \
+ newtype_test.cpp \
math_test.cpp \
matrix_test.cpp \
mem_trie_test.cpp \
diff --git a/base/base_tests/newtype_test.cpp b/base/base_tests/newtype_test.cpp
new file mode 100644
index 0000000000..0a5741eb11
--- /dev/null
+++ b/base/base_tests/newtype_test.cpp
@@ -0,0 +1,99 @@
+#include "testing/testing.hpp"
+
+#include "base/newtype.hpp"
+
+#include "std/sstream.hpp"
+#include "std/type_traits.hpp"
+
+namespace
+{
+NEWTYPE(int, Int);
+
+string DebugPrint(Int const & i)
+{
+ stringstream sstr;
+ sstr << "Int(" << i.Get() << ')';
+ return sstr.str();
+}
+
+UNIT_TEST(NewType_TypeChecks)
+{
+ TEST((is_constructible<Int, int>::value), ());
+ TEST((is_constructible<Int, char>::value), ());
+ TEST(!(is_convertible<int, Int>::value), ());
+ TEST(!(is_convertible<Int, int>::value), ());
+}
+
+UNIT_TEST(NewType_Base)
+{
+ Int a{10};
+ TEST_EQUAL(a.Get(), 10, ());
+
+ a.Set(100);
+ TEST_EQUAL(a.Get(), 100, ());
+}
+
+UNIT_TEST(NewType_Operations)
+{
+ TEST(Int(10) == Int(10), ());
+ TEST(Int(20) != Int(30), ());
+ TEST(Int(10) < Int(20), ());
+ TEST(Int(10) <= Int(20), ());
+ TEST(Int(20) > Int(10), ());
+ TEST(Int(20) >= Int(10), ());
+
+ TEST_EQUAL(Int(10) + Int(20), Int(30), ());
+ TEST_EQUAL(Int(10) - Int(20), Int(-10), ());
+ TEST_EQUAL(Int(10) / Int(2), Int(5), ());
+ TEST_EQUAL(Int(10) * Int(2), Int(20), ());
+ TEST_EQUAL(Int(10) % Int(3), Int(1), ());
+
+ TEST_EQUAL(Int(10) | Int(7), Int(10 | 7), ());
+ TEST_EQUAL(Int(10) & Int(7), Int(10 & 7), ());
+ TEST_EQUAL(Int(10) ^ Int(7), Int(10 ^ 7), ());
+}
+
+UNIT_TEST(NewTypeMember_Operations)
+{
+ Int a(10);
+ auto b = a--;
+ TEST_EQUAL(a, Int(9), ());
+ TEST_EQUAL(b, Int(10), ());
+
+ b = --a;
+ TEST_EQUAL(a, b, ());
+ TEST_EQUAL(a, Int(8), ());
+
+ b = ++a;
+ TEST_EQUAL(a, b, ());
+ TEST_EQUAL(a, Int(9), ());
+
+ b = a++;
+ TEST_EQUAL(a, Int(10), ());
+ TEST_EQUAL(b, Int(9), ());
+
+ a.Set(100);
+ b = Int(2);
+ a *= b;
+ TEST_EQUAL(a, Int(200), ());
+
+ a /= b;
+ TEST_EQUAL(a, Int(100), ());
+
+ b.Set(3);
+ a %= b;
+ TEST_EQUAL(a, Int(1), ());
+
+ a.Set(10);
+ a |= Int(7);
+ TEST_EQUAL(a, Int(10 | 7), ());
+
+ a.Set(10);
+ a &= Int(7);
+ TEST_EQUAL(a, Int(10 & 7), ());
+
+ a.Set(10);
+ a ^= Int(7);
+ TEST_EQUAL(a, Int(10 ^ 7), ());
+}
+} // namespace
diff --git a/base/newtype.hpp b/base/newtype.hpp
new file mode 100644
index 0000000000..0405e9866a
--- /dev/null
+++ b/base/newtype.hpp
@@ -0,0 +1,142 @@
+#pragma once
+
+#include "std/type_traits.hpp"
+
+namespace my
+{
+namespace impl
+{
+template <typename From, typename To>
+using IsConvertibleGuard = typename enable_if<is_convertible<From, To>::value>::type *;
+} // namespace impl
+
+/// Creates a typesafe alias to a given numeric Type.
+template <typename Type, typename Tag>
+class NewType
+{
+ static_assert(is_integral<Type>::value || is_floating_point<Type>::value,
+ "NewType can be used only with integral and floating point type.");
+
+public:
+ template <typename V, impl::IsConvertibleGuard<V, Type> = nullptr>
+ explicit NewType(V const & v) : m_value(v)
+ {
+ }
+
+ 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=(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<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); }
+
+private:
+ Type m_value;
+};
+} // namespace my
+
+#define NEWTYPE(REPR, NAME) \
+ struct NAME ## _tag; \
+ using NAME = my::NewType<REPR, NAME ## _tag>