Start implementing ValueType
This commit is contained in:
parent
04e3f0f34f
commit
df2f1d7a2f
@ -48,6 +48,7 @@ set(SOURCES
|
|||||||
system/time.cpp
|
system/time.cpp
|
||||||
system/diskspace.cpp
|
system/diskspace.cpp
|
||||||
value_type/ValueType.cpp
|
value_type/ValueType.cpp
|
||||||
|
value_type/ConfigBuilder.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||||
|
1
src/cpp-utils/value_type/ConfigBuilder.cpp
Normal file
1
src/cpp-utils/value_type/ConfigBuilder.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "ConfigBuilder.h"
|
61
src/cpp-utils/value_type/ConfigBuilder.h
Normal file
61
src/cpp-utils/value_type/ConfigBuilder.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef MESSMER_CPPUTILS_VALUETYPE_CONFIGBUILDER_H_
|
||||||
|
#define MESSMER_CPPUTILS_VALUETYPE_CONFIGBUILDER_H_
|
||||||
|
|
||||||
|
namespace cpputils {
|
||||||
|
|
||||||
|
template<class Config> class ValueType;
|
||||||
|
|
||||||
|
template<class tag, class underlyingType, bool valueAccessEnabled, bool explicitValueConstructorEnabled, bool incrementAndDecrementEnabled>
|
||||||
|
struct ValueTypeConfig final {
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* Accessors for building the ValueType<Config> class
|
||||||
|
*/
|
||||||
|
friend class ValueType<ValueTypeConfig>;
|
||||||
|
|
||||||
|
using underlying_type = underlyingType;
|
||||||
|
static constexpr bool value_access_enabled() { return valueAccessEnabled; }
|
||||||
|
static constexpr bool explicit_value_constructor_enabled() { return explicitValueConstructorEnabled; }
|
||||||
|
static constexpr bool increment_and_decrement_enabled() { return incrementAndDecrementEnabled; }
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Setters for builder pattern
|
||||||
|
*/
|
||||||
|
constexpr ValueTypeConfig<tag, underlyingType, true, explicitValueConstructorEnabled, incrementAndDecrementEnabled>
|
||||||
|
enable_value_access() {
|
||||||
|
static_assert(!valueAccessEnabled, "Can't call enable_value_access() twice");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ValueTypeConfig<tag, underlyingType, valueAccessEnabled, true, incrementAndDecrementEnabled>
|
||||||
|
enable_explicit_value_constructor() {
|
||||||
|
static_assert(!explicitValueConstructorEnabled, "Can't call enable_explicit_value_constructor() twice");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ValueTypeConfig<tag, underlyingType, valueAccessEnabled, explicitValueConstructorEnabled, true>
|
||||||
|
enable_increment_and_decrement_operators() {
|
||||||
|
static_assert(!incrementAndDecrementEnabled, "Can't call enable_increment_and_decrement_operators twice");
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
using type = ValueType<ValueTypeConfig>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr ValueTypeConfig() {/* not meant for instantiation*/}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start building a value type.
|
||||||
|
* tag: Some unique type to make sure the resulting value type is unique
|
||||||
|
* underlyingType: The type of the underlying values
|
||||||
|
*/
|
||||||
|
template<class tag, class underlyingType>
|
||||||
|
inline constexpr ValueTypeConfig<tag, underlyingType, false, false, false> valueType() { return {}; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,4 +1 @@
|
|||||||
//
|
#include "ValueType.h"
|
||||||
// Created by heinzi on 21/05/18.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
@ -1,29 +1,59 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef MESSMER_CPPUTILS_VALUETYPE_H_
|
#ifndef MESSMER_CPPUTILS_VALUETYPE_VALUETYPE_H_
|
||||||
#define MESSMER_CPPUTILS_VALUETYPE_H_
|
#define MESSMER_CPPUTILS_VALUETYPE_VALUETYPE_H_
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cpp-utils/assert/assert.h>
|
#include <cpp-utils/assert/assert.h>
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
// The Helper type is to allow the enable_if to depend on another type, say a local template type of the method.
|
||||||
|
// If enable_if depended only on class template parameters, it wouldn't work because they're already deduced when deducing the method.
|
||||||
|
template<class Helper, bool Condition, class Type>
|
||||||
|
using enable_if_t = std::enable_if_t<std::is_void<Helper>::value && Condition, Type>;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Test
|
// TODO Test
|
||||||
template<class Config>
|
template<class Config>
|
||||||
class ValueType final {
|
class ValueType final {
|
||||||
public:
|
public:
|
||||||
using underlying_type = typename Config::underlying_type;
|
using underlying_type = typename Config::underlying_type;
|
||||||
|
|
||||||
constexpr explicit ValueType(underlying_type value);
|
template<class U = void>
|
||||||
|
constexpr explicit ValueType(details::enable_if_t<U, Config::explicit_value_constructor_enabled(), underlying_type> value)
|
||||||
|
: _value(value) {}
|
||||||
|
|
||||||
template<class U = Config>
|
template<class U = void>
|
||||||
constexpr std::enable_if_t<sizeof(U) && Config::enable_value_access(), underlying_type> value() const {
|
constexpr details::enable_if_t<U, Config::value_access_enabled(), underlying_type> value() const {
|
||||||
return _value;
|
return _value;
|
||||||
};
|
}
|
||||||
|
|
||||||
constexpr ValueType& operator++();
|
template<class U = void>
|
||||||
constexpr ValueType operator++(int);
|
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType&> operator++() {
|
||||||
constexpr ValueType& operator--();
|
++_value;
|
||||||
constexpr ValueType operator--(int);
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = void>
|
||||||
|
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType> operator++(int) {
|
||||||
|
ValueType<Config> tmp = *this;
|
||||||
|
++(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = void>
|
||||||
|
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType&> operator--() {
|
||||||
|
--_value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U = void>
|
||||||
|
constexpr details::enable_if_t<U, Config::increment_and_decrement_enabled(), ValueType> operator--(int) {
|
||||||
|
ValueType<Config> tmp = *this;
|
||||||
|
--(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ValueType& operator+=(ValueType rhs);
|
constexpr ValueType& operator+=(ValueType rhs);
|
||||||
constexpr ValueType& operator-=(ValueType rhs);
|
constexpr ValueType& operator-=(ValueType rhs);
|
||||||
@ -65,35 +95,6 @@ inline constexpr ValueType<Config> operator "" _bytes(unsigned long long int val
|
|||||||
return ValueType<Config>(value);
|
return ValueType<Config>(value);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>::ValueType(typename Config::underlying_type value)
|
|
||||||
: _value(value) {}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator++() {
|
|
||||||
++_value;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> ValueType<Config>::operator++(int) {
|
|
||||||
ValueType<Config> tmp = *this;
|
|
||||||
++(*this);
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator--() {
|
|
||||||
--_value;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
|
||||||
inline constexpr ValueType<Config> ValueType<Config>::operator--(int) {
|
|
||||||
ValueType<Config> tmp = *this;
|
|
||||||
--(*this);
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Config>
|
template<class Config>
|
||||||
inline constexpr ValueType<Config>& ValueType<Config>::operator+=(ValueType<Config> rhs) {
|
inline constexpr ValueType<Config>& ValueType<Config>::operator+=(ValueType<Config> rhs) {
|
||||||
|
@ -1,30 +1,50 @@
|
|||||||
#include <cpp-utils/value_type/ValueType.h>
|
#include <cpp-utils/value_type/ValueType.h>
|
||||||
|
#include <cpp-utils/value_type/ConfigBuilder.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
using cpputils::ValueType;
|
using cpputils::valueType;
|
||||||
|
|
||||||
class AllEnabledConfig final {
|
struct Tag1{};
|
||||||
using underlying_type = int;
|
using AllEnabledValueType = decltype(valueType<Tag1, int>()
|
||||||
static constexpr bool allow_value_access() { return true; }
|
.enable_explicit_value_constructor()
|
||||||
};
|
.enable_value_access()
|
||||||
|
)::type;
|
||||||
|
|
||||||
using AllEnabledValueType = ValueType<AllEnabledConfig>;
|
|
||||||
|
/*
|
||||||
|
* Test value() access
|
||||||
|
*/
|
||||||
|
|
||||||
template<class T, class Enable = void> struct has_value_access : std::false_type {};
|
template<class T, class Enable = void> struct has_value_access : std::false_type {};
|
||||||
template<class T> struct has_value_access<T, std::void_t<T::value()>> : std::true_type {
|
template<class T> struct has_value_access<T, std::void_t<decltype(std::declval<T>().value())>> : std::true_type {
|
||||||
static_assert(std::is_same<typename T::underlying_type, std::result_of_t<T::value()>>::value, "value() method returns wrong 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 ConfigWithValueAccess final {
|
struct Tag2{};
|
||||||
using underlying_type = int;
|
using ValueTypeWithValueAccess = decltype(valueType<Tag2, double>()
|
||||||
static constexpr bool allow_value_access() { return true; }
|
.enable_explicit_value_constructor()
|
||||||
};
|
.enable_value_access()
|
||||||
|
)::type;
|
||||||
|
struct Tag3{};
|
||||||
|
using ValueTypeWithoutValueAccess = decltype(valueType<Tag3, double>()
|
||||||
|
.enable_explicit_value_constructor()
|
||||||
|
)::type;
|
||||||
|
|
||||||
struct ConfigWithoutValueAccess final {
|
static_assert(has_value_access<AllEnabledValueType>::value, "");
|
||||||
using underlying_type = int;
|
static_assert(has_value_access<ValueTypeWithValueAccess>::value, "");
|
||||||
static constexpr bool allow_value_access() { return false; }
|
static_assert(!has_value_access<ValueTypeWithoutValueAccess>::value, "");
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(has_value_access<ValueType<AllEnabledConfig>>::value, "");
|
TEST(ValueTypeTest, valueAccess){
|
||||||
static_assert(has_value_access<ValueType<ConfigWithValueAccess>>::value, "");
|
EXPECT_EQ(3, AllEnabledValueType(3).value());
|
||||||
static_assert(!has_value_access<ValueType<ConfigWithoutValueAccess>>::value, "");
|
EXPECT_EQ(5.5, ValueTypeWithValueAccess(5.5).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Tag4{};
|
||||||
|
using ValueTypeWithIncrementAndDecrement = decltype(valueType<Tag4, int>()
|
||||||
|
.enable_explicit_value_constructor()
|
||||||
|
.enable_value_access()
|
||||||
|
.enable_increment_and_decrement_operators()
|
||||||
|
)::type;
|
||||||
|
// TODO Test incrementAndDecrement
|
Loading…
Reference in New Issue
Block a user