Skip to content

Commit

Permalink
refactor: use concepts more (#5537)
Browse files Browse the repository at this point in the history
* refactor: use `Arithmetic`

* refactor: use `SupportsProportional`, `SupportsRelative`

* refactor: MemberType
  • Loading branch information
scarf005 authored Oct 8, 2024
1 parent 1bf4793 commit 1510f81
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 44 deletions.
5 changes: 3 additions & 2 deletions src/assign.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "json.h"
#include "units.h"
#include "units_serde.h"
#include "concepts_utility.h"

namespace detail
{
Expand All @@ -43,7 +44,7 @@ bool is_strict_enabled( const std::string &src );
void report_strict_violation( const JsonObject &jo, const std::string &message,
const std::string &name );

template <typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
template <Arithmetic T>
bool assign( const JsonObject &jo, const std::string &name, T &val, bool strict = false,
T lo = std::numeric_limits<T>::lowest(), T hi = std::numeric_limits<T>::max() )
{
Expand Down Expand Up @@ -95,7 +96,7 @@ bool assign( const JsonObject &jo, const std::string &name, T &val, bool strict
// and also to avoid potentially nonsensical interactions between relative and proportional.
bool assign( const JsonObject &jo, const std::string &name, bool &val, bool strict = false );

template <typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
template <Arithmetic T>
bool assign( const JsonObject &jo, const std::string &name, std::pair<T, T> &val,
bool strict = false, T lo = std::numeric_limits<T>::lowest(), T hi = std::numeric_limits<T>::max() )
{
Expand Down
62 changes: 29 additions & 33 deletions src/generic_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,48 +657,45 @@ std::true_type {};
template<>
struct supports_proportional<bool> : std::false_type {};

template<typename T>
concept SupportsProportional = supports_proportional<T>::value;

// This checks that all units:: types will support relative and proportional
static_assert( supports_relative<units::energy>::value, "units should support relative" );
static_assert( supports_proportional<units::energy>::value, "units should support proportional" );
static_assert( SupportsRelative<units::energy>, "units should support relative" );
static_assert( SupportsProportional<units::energy>, "units should support proportional" );

static_assert( supports_relative<int>::value, "ints should support relative" );
static_assert( supports_proportional<int>::value, "ints should support proportional" );
static_assert( SupportsRelative<int>, "ints should support relative" );
static_assert( SupportsProportional<int>, "ints should support proportional" );

static_assert( !supports_relative<bool>::value, "bools should not support relative" );
static_assert( !supports_proportional<bool>::value, "bools should not support proportional" );
static_assert( !SupportsRelative<bool>, "bools should not support relative" );
static_assert( !SupportsProportional<bool>, "bools should not support proportional" );

// Using string ids with ints doesn't make sense in practice, but it doesn't matter here
// The type that it is templated with does not change it's behavior
static_assert( !supports_relative<string_id<int>>::value,
"string ids should not support relative" );
static_assert( !supports_proportional<string_id<int>>::value,
static_assert( !SupportsRelative<string_id<int>>, "string ids should not support relative" );
static_assert( !SupportsProportional<string_id<int>>,
"string ids should not support proportional" );

// Using int ids with ints doesn't make sense in practice, but it doesn't matter here
// The type that it is templated with does not change it's behavior
static_assert( !supports_relative<int_id<int>>::value,
"int ids should not support relative" );
static_assert( !supports_proportional<int_id<int>>::value,
"int ids should not support proportional" );
static_assert( !SupportsRelative<int_id<int>>, "int ids should not support relative" );
static_assert( !SupportsProportional<int_id<int>>, "int ids should not support proportional" );

static_assert( !supports_relative<std::string>::value, "strings should not support relative" );
static_assert( !supports_proportional<std::string>::value,
"strings should not support proportional" );
static_assert( !SupportsRelative<std::string>, "strings should not support relative" );
static_assert( !SupportsProportional<std::string>, "strings should not support proportional" );

// Grab an enum class from debug.h
static_assert( !supports_relative<DebugOutput>::value, "enum classes should not support relative" );
static_assert( !supports_proportional<DebugOutput>::value,
"enum classes should not support proportional" );
static_assert( !SupportsRelative<DebugOutput>, "enum classes should not support relative" );
static_assert( !SupportsProportional<DebugOutput>, "enum classes should not support proportional" );

// Grab a normal enum from there too
static_assert( !supports_relative<DL>::value, "enums should not support relative" );
static_assert( !supports_proportional<DL>::value, "enums should not support relative" );
static_assert( !SupportsRelative<DL>, "enums should not support relative" );
static_assert( !SupportsProportional<DL>, "enums should not support relative" );

// Dummy template:
// Warn if it's trying to use proportional where it cannot, but otherwise just
// return.
template < typename MemberType, std::enable_if_t < !supports_proportional<MemberType>::value > * =
nullptr >
template<typename MemberType> requires( !SupportsProportional<MemberType> )
inline bool handle_proportional( const JsonObject &jo, const std::string &name, MemberType & )
{
if( jo.has_object( "proportional" ) ) {
Expand All @@ -717,7 +714,7 @@ inline bool handle_proportional( const JsonObject &jo, const std::string &name,
// this, so member will contain the value of the thing we inherit from
// So, check if there is a proportional entry, check if it's got a valid value
// and if it does, multiply the member by it.
template<typename MemberType, std::enable_if_t<supports_proportional<MemberType>::value>* = nullptr>
template<SupportsProportional MemberType>
inline bool handle_proportional( const JsonObject &jo, const std::string &name, MemberType &member )
{
if( jo.has_object( "proportional" ) ) {
Expand Down Expand Up @@ -745,9 +742,7 @@ inline bool handle_proportional( const JsonObject &jo, const std::string &name,
// Dummy template:
// Warn when trying to use relative when it's not supported, but otherwise,
// return
template < typename MemberType,
std::enable_if_t < !supports_relative<MemberType>::value > * = nullptr
>
template<typename MemberType> requires( !SupportsRelative<MemberType> )
inline bool handle_relative( const JsonObject &jo, const std::string &name, MemberType & )
{
if( jo.has_object( "relative" ) ) {
Expand All @@ -766,7 +761,7 @@ inline bool handle_relative( const JsonObject &jo, const std::string &name, Memb
// Copy-from makes it so the thing we're inheriting from is used to construct
// this, so member will contain the value of the thing we inherit from
// So, check if there is a relative entry, then add it to our member
template<typename MemberType, std::enable_if_t<supports_relative<MemberType>::value>* = nullptr>
template<SupportsRelative MemberType>
inline bool handle_relative( const JsonObject &jo, const std::string &name, MemberType &member )
{
if( jo.has_object( "relative" ) ) {
Expand Down Expand Up @@ -809,8 +804,8 @@ words: `MemberType foo( ReaderType(...) );` does not work. This is what `is_cons
If the 5. parameter can be used to construct a `MemberType`, it is assumed to be the default value,
otherwise it is assumed to be the reader.
*/
template<typename MemberType, typename DefaultType = MemberType,
typename = typename std::enable_if<std::is_constructible<MemberType, const DefaultType &>::value>::type>
template<typename MemberType, typename DefaultType = MemberType>
requires( std::is_constructible_v<MemberType, const DefaultType &> )
inline void optional( const JsonObject &jo, const bool was_loaded, const std::string &name,
MemberType &member, const DefaultType &default_value )
{
Expand All @@ -821,9 +816,9 @@ inline void optional( const JsonObject &jo, const bool was_loaded, const std::st
}
}
}
template < typename MemberType, typename ReaderType, typename DefaultType = MemberType,
typename = typename std::enable_if <
!std::is_constructible<MemberType, const ReaderType &>::value >::type >

template<typename MemberType, typename ReaderType, typename DefaultType = MemberType>
requires( !std::is_constructible_v<MemberType, const ReaderType &> )
inline void optional( const JsonObject &jo, const bool was_loaded, const std::string &name,
MemberType &member, const ReaderType &reader )
{
Expand All @@ -833,6 +828,7 @@ inline void optional( const JsonObject &jo, const bool was_loaded, const std::st
}
}
}

template<typename MemberType, typename ReaderType, typename DefaultType = MemberType>
inline void optional( const JsonObject &jo, const bool was_loaded, const std::string &name,
MemberType &member, const ReaderType &reader, const DefaultType &default_value )
Expand Down
17 changes: 9 additions & 8 deletions src/generic_readers.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@ struct supports_relative<bool> : std::false_type {};
template<>
struct supports_relative<std::string> : std::false_type {};

template<typename T> concept SupportsRelative = supports_relative<T>::value;

namespace reader_detail
{
template<typename T>
struct handler {
static constexpr bool is_container = false;
};

template<typename T> concept Container = handler<T>::is_container;

template<typename T> concept RelativeContainer = Container<T> &&SupportsRelative<T>;

template<typename T>
struct handler<std::set<T>> {
void clear( std::set<T> &container ) const {
Expand Down Expand Up @@ -237,10 +243,7 @@ class generic_typed_reader
* whereas these are reading values of the same type.
*/
// Type does not support relative
template < typename C, typename std::enable_if < !reader_detail::handler<C>::is_container,
int >::type = 0,
std::enable_if_t < !supports_relative<C>::value > * = nullptr
>
template<typename C> requires( !reader_detail::Container<C> || !SupportsRelative<C> )
bool do_relative( const JsonObject &jo, const std::string &name, C & ) const {
if( jo.has_object( "relative" ) ) {
JsonObject relative = jo.get_object( "relative" );
Expand All @@ -254,8 +257,7 @@ class generic_typed_reader
}

// Type supports relative
template < typename C, typename std::enable_if < !reader_detail::handler<C>::is_container,
int >::type = 0, std::enable_if_t<supports_relative<C>::value> * = nullptr >
template<reader_detail::RelativeContainer C>
bool do_relative( const JsonObject &jo, const std::string &name, C &member ) const {
if( jo.has_object( "relative" ) ) {
JsonObject relative = jo.get_object( "relative" );
Expand Down Expand Up @@ -287,8 +289,7 @@ class generic_typed_reader
*/
// was_loaded is ignored here, if the value is not found in JSON, report to
// the caller, which will take action on their own.
template < typename C, typename std::enable_if < !reader_detail::handler<C>::is_container,
int >::type = 0 >
template<typename C> requires( !reader_detail::Container<C> )
bool operator()( const JsonObject &jo, const std::string &member_name,
C &member, bool /*was_loaded*/ ) const {
return read_normal( jo, member_name, member ) ||
Expand Down
4 changes: 3 additions & 1 deletion src/numeric_interval.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
#include <limits>
#include <type_traits>

#include "concepts_utility.h"

/**
* An interval of numeric values between @ref min and @ref max (including both).
* By default it's [0, 0].
*/
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
template<Arithmetic T>
struct numeric_interval {
T min = static_cast<T>( 0 );
T max = static_cast<T>( 0 );
Expand Down

0 comments on commit 1510f81

Please sign in to comment.