Continue implementing ValueType. New approach.
This commit is contained in:
parent
df2f1d7a2f
commit
0e697eb1f6
@ -6,207 +6,204 @@
|
|||||||
#include <cpp-utils/assert/assert.h>
|
#include <cpp-utils/assert/assert.h>
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
|
namespace value_type {
|
||||||
|
|
||||||
namespace details {
|
/**
|
||||||
// The Helper type is to allow the enable_if to depend on another type, say a local template type of the method.
|
* This template simplifies generation of simple classes that wrap an id
|
||||||
// If enable_if depended only on class template parameters, it wouldn't work because they're already deduced when deducing the method.
|
* in a typesafe way. Namely, you can use it to create a very lightweight
|
||||||
template<class Helper, bool Condition, class Type>
|
* type that only offers equality comparators and hashing. Example:
|
||||||
using enable_if_t = std::enable_if_t<std::is_void<Helper>::value && Condition, Type>;
|
*
|
||||||
}
|
* struct MyIdType final : IdValueType<MyIdType, uint32_t> {
|
||||||
|
* constexpr explicit MyIdType(uint32_t id): IdValueType(id) {}
|
||||||
// TODO Test
|
* };
|
||||||
template<class Config>
|
*
|
||||||
class ValueType final {
|
* Then in the global top level namespace:
|
||||||
|
*
|
||||||
|
* DEFINE_HASH_FOR_VALUE_TYPE(MyIdType);
|
||||||
|
*
|
||||||
|
* That's it - equality operators and hash functions are automatically defined
|
||||||
|
* for you, given the underlying type supports it.
|
||||||
|
*
|
||||||
|
* OrderedIdValueType: Use this instead of IdValueType if you need an ordering relation on your id type.
|
||||||
|
* This will define the operators
|
||||||
|
* - val < val
|
||||||
|
* - val > val
|
||||||
|
* - val <= val
|
||||||
|
* - val >= val
|
||||||
|
*
|
||||||
|
* QuantityValueType: Use this if you want a full-blown value type with arithmetics.
|
||||||
|
* Additionally to what OrderedIdValueType offers, this also defines:
|
||||||
|
* - ++val, val++
|
||||||
|
* - --val, val--
|
||||||
|
* - val += val (returns val)
|
||||||
|
* - val -= val (returns val)
|
||||||
|
* - val *= scalar (returns val)
|
||||||
|
* - val /= scalar (returns val)
|
||||||
|
* - val %= scalar (returns val)
|
||||||
|
* - val + val (returns val)
|
||||||
|
* - val - val (returns val)
|
||||||
|
* - val * scalar, scalar * val (returns val)
|
||||||
|
* - val / scalar (returns val)
|
||||||
|
* - val % scalar (returns val)
|
||||||
|
* - val / val (returns scalar)
|
||||||
|
* - val % val (returns scalar)
|
||||||
|
*/
|
||||||
|
template <class ConcreteType, class UnderlyingType>
|
||||||
|
class IdValueType {
|
||||||
public:
|
public:
|
||||||
using underlying_type = typename Config::underlying_type;
|
using underlying_type = UnderlyingType;
|
||||||
|
using concrete_type = ConcreteType;
|
||||||
|
|
||||||
template<class U = void>
|
constexpr IdValueType(IdValueType&&) = default;
|
||||||
constexpr explicit ValueType(details::enable_if_t<U, Config::explicit_value_constructor_enabled(), underlying_type> value)
|
constexpr IdValueType(const IdValueType&) = default;
|
||||||
: _value(value) {}
|
constexpr IdValueType& operator=(IdValueType&&) = default;
|
||||||
|
constexpr IdValueType& operator=(const IdValueType&) = default;
|
||||||
|
|
||||||
template<class U = void>
|
protected:
|
||||||
constexpr details::enable_if_t<U, Config::value_access_enabled(), underlying_type> value() const {
|
constexpr explicit IdValueType(underlying_type value) : value_(value) {
|
||||||
return _value;
|
static_assert(std::is_base_of<IdValueType<ConcreteType, UnderlyingType>, ConcreteType>::value,
|
||||||
|
"CRTP violated. First template parameter of this class must be the concrete class.");
|
||||||
|
}
|
||||||
|
constexpr underlying_type& underlying_value() const {
|
||||||
|
return value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U = void>
|
friend struct std::hash<ConcreteType>;
|
||||||
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType&> operator++() {
|
|
||||||
++_value;
|
friend constexpr bool operator==(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return lhs.value_ == rhs.value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator!=(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
underlying_type value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFINE_HASH_FOR_VALUE_TYPE(ClassName) \
|
||||||
|
namespace std { \
|
||||||
|
template <> \
|
||||||
|
struct hash<ClassName> { \
|
||||||
|
size_t operator()(ClassName x) const { \
|
||||||
|
return std::hash<ClassName::underlying_type>()(x.value_); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class ConcreteType, class UnderlyingType>
|
||||||
|
class OrderedIdValueType : public IdValueType<ConcreteType, UnderlyingType> {
|
||||||
|
protected:
|
||||||
|
using IdValueType<ConcreteType, UnderlyingType>::IdValueType;
|
||||||
|
|
||||||
|
friend constexpr bool operator<(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return lhs.value_ < rhs.value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator>(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return lhs.value_ > rhs.value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator>=(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return !operator<(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator<=(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return !operator>(lhs, rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class ConcreteType, class UnderlyingType>
|
||||||
|
class QuantityValueType : public OrderedIdValueType<ConcreteType, UnderlyingType> {
|
||||||
|
protected:
|
||||||
|
using OrderedIdValueType<ConcreteType, UnderlyingType>::OrderedIdValueType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr ConcreteType& operator++() {
|
||||||
|
++this->value_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U = void>
|
constexpr ConcreteType operator++(int) {
|
||||||
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType> operator++(int) {
|
ConcreteType tmp = *this;
|
||||||
ValueType<Config> tmp = *this;
|
|
||||||
++(*this);
|
++(*this);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U = void>
|
constexpr ConcreteType& operator--() {
|
||||||
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType&> operator--() {
|
--this->value_;
|
||||||
--_value;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U = void>
|
constexpr ConcreteType operator--(int) {
|
||||||
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType> operator--(int) {
|
ConcreteType tmp = *this;
|
||||||
ValueType<Config> tmp = *this;
|
|
||||||
--(*this);
|
--(*this);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ValueType& operator+=(ValueType rhs);
|
constexpr ConcreteType& operator+=(ConcreteType rhs) {
|
||||||
constexpr ValueType& operator-=(ValueType rhs);
|
this->value_ += rhs.value_;
|
||||||
constexpr ValueType& operator*=(underlying_type rhs);
|
return *this;
|
||||||
constexpr ValueType& operator/=(underlying_type rhs);
|
}
|
||||||
constexpr ValueType& operator%=(underlying_type rhs);
|
|
||||||
|
constexpr ConcreteType& operator-=(ConcreteType rhs) {
|
||||||
|
this->value_ -= rhs.value_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ConcreteType& operator*=(UnderlyingType rhs) {
|
||||||
|
this->value_ *= rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ConcreteType& operator/=(UnderlyingType rhs) {
|
||||||
|
this->value_ /= rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ConcreteType& operator%=(UnderlyingType rhs) {
|
||||||
|
this->value_ %= rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct std::hash<ValueType>;
|
friend constexpr ConcreteType operator+(ConcreteType lhs, ConcreteType rhs) {
|
||||||
underlying_type _value;
|
return lhs += rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr ConcreteType operator-(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return lhs -= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr ConcreteType operator*(ConcreteType lhs, UnderlyingType rhs) {
|
||||||
|
return lhs *= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr ConcreteType operator*(UnderlyingType lhs, ConcreteType rhs) {
|
||||||
|
return rhs * lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr ConcreteType operator/(ConcreteType lhs, UnderlyingType rhs) {
|
||||||
|
return lhs /= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr UnderlyingType operator/(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return lhs.value_ / rhs.value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr ConcreteType operator%(ConcreteType lhs, UnderlyingType rhs) {
|
||||||
|
return lhs %= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr UnderlyingType operator%(ConcreteType lhs, ConcreteType rhs) {
|
||||||
|
return lhs.value_ % rhs.value_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*template<class Config>
|
}
|
||||||
constexpr ValueType<Config> operator "" _bytes(unsigned long long int value);*/
|
|
||||||
|
|
||||||
template<class Config> constexpr ValueType<Config> operator+(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr ValueType<Config> operator-(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr ValueType<Config> operator*(ValueType<Config> lhs, typename Config::underlying_type rhs);
|
|
||||||
template<class Config> constexpr ValueType<Config> operator*(typename Config::underlying_type lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr ValueType<Config> operator/(ValueType<Config> lhs, typename Config::underlying_type rhs);
|
|
||||||
template<class Config> constexpr typename Config::underlying_type operator/(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr ValueType<Config> operator%(ValueType<Config> lhs, typename Config::underlying_type rhs);
|
|
||||||
template<class Config> constexpr typename Config::underlying_type operator%(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
|
|
||||||
template<class Config> constexpr bool operator==(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr bool operator!=(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr bool operator<(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr bool operator>(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr bool operator<=(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
template<class Config> constexpr bool operator>=(ValueType<Config> lhs, ValueType<Config> rhs);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Implementation follows
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator "" _bytes(unsigned long long int value) {
|
|
||||||
return ValueType<Config>(value);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator+=(ValueType<Config> rhs) {
|
|
||||||
_value += rhs._value;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator-=(ValueType<Config> rhs) {
|
|
||||||
_value -= rhs._value;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator*=(typename Config::underlying_type rhs) {
|
|
||||||
_value *= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator/=(typename Config::underlying_type rhs) {
|
|
||||||
_value /= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator%=(typename Config::underlying_type rhs) {
|
|
||||||
_value %= rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator+(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs += rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator-(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs -= rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator*(ValueType<Config> lhs, typename Config::underlying_type rhs) {
|
|
||||||
return lhs *= rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator*(typename Config::underlying_type lhs, ValueType<Config> rhs) {
|
|
||||||
return rhs * lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator/(ValueType<Config> lhs, typename Config::underlying_type rhs) {
|
|
||||||
return lhs /= rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr typename Config::underlying_type operator/(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs.value() / rhs.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> operator%(ValueType<Config> lhs, typename Config::underlying_type rhs) {
|
|
||||||
return lhs %= rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr typename Config::underlying_type operator%(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs.value() % rhs.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr bool operator==(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs.value() == rhs.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr bool operator!=(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return !operator==(lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr bool operator<(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs.value() < rhs.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr bool operator>(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return lhs.value() > rhs.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr bool operator<=(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return !operator>(lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr bool operator>=(ValueType<Config> lhs, ValueType<Config> rhs) {
|
|
||||||
return !operator<(lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class Config>
|
|
||||||
struct hash<cpputils::ValueType<Config>> {
|
|
||||||
constexpr hash() = default;
|
|
||||||
constexpr size_t operator()(cpputils::ValueType<Config> v) {
|
|
||||||
return v._value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,49 +2,169 @@
|
|||||||
#include <cpp-utils/value_type/ConfigBuilder.h>
|
#include <cpp-utils/value_type/ConfigBuilder.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
using cpputils::valueType;
|
using cpputils::value_type::IdValueType;
|
||||||
|
using cpputils::value_type::OrderedIdValueType;
|
||||||
|
using cpputils::value_type::QuantityValueType;
|
||||||
|
|
||||||
struct Tag1{};
|
namespace {
|
||||||
using AllEnabledValueType = decltype(valueType<Tag1, int>()
|
|
||||||
.enable_explicit_value_constructor()
|
|
||||||
.enable_value_access()
|
|
||||||
)::type;
|
|
||||||
|
|
||||||
|
struct MyIdValueType : IdValueType<MyIdValueType, int64_t> {
|
||||||
/*
|
constexpr MyIdValueType(int64_t val): IdValueType(val) {}
|
||||||
* Test value() access
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<class T, class Enable = void> struct has_value_access : std::false_type {};
|
|
||||||
template<class T> struct has_value_access<T, std::void_t<decltype(std::declval<T>().value())>> : std::true_type {
|
|
||||||
using actual_result_type = std::result_of_t<decltype(&T::template value<void>)(T*)>;
|
|
||||||
static_assert(std::is_same<typename T::underlying_type, actual_result_type>::value, "value() method returns wrong type");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Tag2{};
|
struct MyOrderedIdValueType : OrderedIdValueType<MyOrderedIdValueType, int64_t> {
|
||||||
using ValueTypeWithValueAccess = decltype(valueType<Tag2, double>()
|
constexpr MyOrderedIdValueType(int64_t val): OrderedIdValueType(val) {}
|
||||||
.enable_explicit_value_constructor()
|
};
|
||||||
.enable_value_access()
|
|
||||||
)::type;
|
|
||||||
struct Tag3{};
|
|
||||||
using ValueTypeWithoutValueAccess = decltype(valueType<Tag3, double>()
|
|
||||||
.enable_explicit_value_constructor()
|
|
||||||
)::type;
|
|
||||||
|
|
||||||
static_assert(has_value_access<AllEnabledValueType>::value, "");
|
struct MyQuantityValueType : QuantityValueType<MyQuantityValueType, int64_t> {
|
||||||
static_assert(has_value_access<ValueTypeWithValueAccess>::value, "");
|
constexpr MyQuantityValueType(int64_t val): QuantityValueType(val) {}
|
||||||
static_assert(!has_value_access<ValueTypeWithoutValueAccess>::value, "");
|
};
|
||||||
|
|
||||||
TEST(ValueTypeTest, valueAccess){
|
}
|
||||||
EXPECT_EQ(3, AllEnabledValueType(3).value());
|
DEFINE_HASH_FOR_VALUE_TYPE(MyIdValueType);
|
||||||
EXPECT_EQ(5.5, ValueTypeWithValueAccess(5.5).value());
|
DEFINE_HASH_FOR_VALUE_TYPE(MyOrderedIdValueType);
|
||||||
|
DEFINE_HASH_FOR_VALUE_TYPE(MyQuantityValueType);
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
struct IdValueTypeTest_constexpr_test {
|
||||||
|
static constexpr Type test_constructor = Type(5);
|
||||||
|
static_assert(Type(5) == test_constructor, "");
|
||||||
|
|
||||||
|
static constexpr Type test_copy_constructor = test_constructor;
|
||||||
|
static_assert(Type(5) == test_copy_constructor, "");
|
||||||
|
|
||||||
|
static constexpr Type test_copy_assignment = (Type(4) = 3);
|
||||||
|
static_assert(test_copy_assignment == Type(3), "");
|
||||||
|
|
||||||
|
static_assert(Type(5) == Type(5), "");
|
||||||
|
static_assert(Type(5) != Type(6), "");
|
||||||
|
|
||||||
|
static constexpr bool success = true;
|
||||||
|
};
|
||||||
|
static_assert(IdValueTypeTest_constexpr_test<MyIdValueType>::success, "");
|
||||||
|
static_assert(IdValueTypeTest_constexpr_test<MyOrderedIdValueType>::success, "");
|
||||||
|
static_assert(IdValueTypeTest_constexpr_test<MyQuantityValueType>::success, "");
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type> class IdValueTypeTest : public testing::Test {
|
||||||
|
};
|
||||||
|
using IdValueTypeTest_types = testing::Types<MyIdValueType, MyOrderedIdValueType, MyQuantityValueType>;
|
||||||
|
TYPED_TEST_CASE(IdValueTypeTest, IdValueTypeTest_types);
|
||||||
|
|
||||||
|
|
||||||
|
TYPED_TEST(IdValueTypeTest, Equality) {
|
||||||
|
TypeParam obj1(4);
|
||||||
|
TypeParam obj2(4);
|
||||||
|
TypeParam obj3(5);
|
||||||
|
|
||||||
|
EXPECT_TRUE(obj1 == obj2);
|
||||||
|
EXPECT_TRUE(obj2 == obj1);;
|
||||||
|
EXPECT_FALSE(obj1 == obj3);
|
||||||
|
EXPECT_FALSE(obj3 == obj1);
|
||||||
|
|
||||||
|
EXPECT_FALSE(obj1 != obj2);
|
||||||
|
EXPECT_FALSE(obj2 != obj1);
|
||||||
|
EXPECT_TRUE(obj1 != obj3);
|
||||||
|
EXPECT_TRUE(obj3 != obj1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Tag4{};
|
TYPED_TEST(IdValueTypeTest, Constructor) {
|
||||||
using ValueTypeWithIncrementAndDecrement = decltype(valueType<Tag4, int>()
|
TypeParam obj(4);
|
||||||
.enable_explicit_value_constructor()
|
EXPECT_TRUE(obj == TypeParam(4));
|
||||||
.enable_value_access()
|
}
|
||||||
.enable_increment_and_decrement_operators()
|
|
||||||
)::type;
|
TYPED_TEST(IdValueTypeTest, CopyConstructor) {
|
||||||
// TODO Test incrementAndDecrement
|
TypeParam obj(2);
|
||||||
|
TypeParam obj2(obj);
|
||||||
|
EXPECT_TRUE(obj2 == TypeParam(2));
|
||||||
|
EXPECT_TRUE(obj == obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(IdValueTypeTest, MoveConstructor) {
|
||||||
|
TypeParam obj(2);
|
||||||
|
TypeParam obj2(std::move(obj));
|
||||||
|
EXPECT_TRUE(obj2 == TypeParam(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(IdValueTypeTest, CopyAssignment) {
|
||||||
|
TypeParam obj(3);
|
||||||
|
TypeParam obj2(2);
|
||||||
|
obj2 = obj;
|
||||||
|
EXPECT_TRUE(obj2 == TypeParam(3));
|
||||||
|
EXPECT_TRUE(obj == obj2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(IdValueTypeTest, MoveAssignment) {
|
||||||
|
TypeParam obj(3);
|
||||||
|
TypeParam obj2(2);
|
||||||
|
obj2 = std::move(obj);
|
||||||
|
EXPECT_TRUE(obj2 == TypeParam(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(IdValueTypeTest, Hash) {
|
||||||
|
TypeParam obj(3);
|
||||||
|
TypeParam obj2(3);
|
||||||
|
EXPECT_EQ(std::hash<TypeParam>()(obj), std::hash<TypeParam>()(obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(IdValueTypeTest, UnorderedSet) {
|
||||||
|
std::unordered_set<TypeParam> set;
|
||||||
|
set.insert(TypeParam(3));
|
||||||
|
EXPECT_EQ(1u, set.count(TypeParam(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
struct OrderedIdValueTypeTest_constexpr_test {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
static constexpr bool success = true;
|
||||||
|
};
|
||||||
|
static_assert(OrderedIdValueTypeTest_constexpr_test<MyOrderedIdValueType>::success, "");
|
||||||
|
static_assert(OrderedIdValueTypeTest_constexpr_test<MyQuantityValueType>::success, "");
|
||||||
|
|
||||||
|
template<class Type> class OrderedIdValueTypeTest : public testing::Test {};
|
||||||
|
using OrderedIdValueTypeTest_types = testing::Types<MyOrderedIdValueType, MyQuantityValueType>;
|
||||||
|
TYPED_TEST_CASE(OrderedIdValueTypeTest, OrderedIdValueTypeTest_types);
|
||||||
|
|
||||||
|
// TODO Test cases for OrderedIdValueTypeTest
|
||||||
|
|
||||||
|
TYPED_TEST(OrderedIdValueTypeTest, Set) {
|
||||||
|
std::set<TypeParam> set;
|
||||||
|
set.insert(TypeParam(3));
|
||||||
|
EXPECT_EQ(1u, set.count(TypeParam(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
struct QuantityValueTypeTest_constexpr_test {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
static constexpr bool success = true;
|
||||||
|
};
|
||||||
|
static_assert(QuantityValueTypeTest_constexpr_test<MyQuantityValueType>::success, "");
|
||||||
|
|
||||||
|
template<class Type> class QuantityValueTypeTest : public testing::Test {};
|
||||||
|
using QuantityValueTypeTest_types = testing::Types<MyQuantityValueType>;
|
||||||
|
TYPED_TEST_CASE(QuantityValueTypeTest, QuantityValueTypeTest_types);
|
||||||
|
|
||||||
|
// TODO Test cases for QuantityValueTypeTest
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user