Skip to content

Commit

Permalink
Start using concepts
Browse files Browse the repository at this point in the history
  • Loading branch information
jimporter committed Jul 30, 2024
1 parent c00953a commit 81a1f53
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 92 deletions.
6 changes: 0 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ jobs:
matrix:
include:
# GCC builds
- {os: ubuntu-20.04, compiler: gcc, version: '8',
options: '--std=c++2a', flags: '-Wsuggest-override'}
- {os: ubuntu-latest, compiler: gcc, version: '9',
options: '--std=c++2a', flags: '-Wsuggest-override'}
- {os: ubuntu-latest, compiler: gcc, version: '10',
flags: '-Wsuggest-override'}
- {os: ubuntu-latest, compiler: gcc, version: '11',
Expand All @@ -39,8 +35,6 @@ jobs:
flags: '-Wsuggest-override'}

# Clang builds
- {os: ubuntu-20.04, compiler: clang, version: '9',
options: '--std=c++2a'}
- {os: ubuntu-20.04, compiler: clang, version: '10'}
- {os: ubuntu-20.04, compiler: clang, version: '11'}
- {os: ubuntu-20.04, compiler: clang, version: '12'}
Expand Down
4 changes: 2 additions & 2 deletions doc/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ ninja install
Before you get started with mettle, you'll need to install its dependencies:

* A C++20-compliant compiler
* [Clang](http://clang.llvm.org/) 9.0+
* [GCC](https://gcc.gnu.org/) 8.1+
* [Clang](http://clang.llvm.org/) 10.0+
* [GCC](https://gcc.gnu.org/) 10.1+
* [MSVC](https://www.visualstudio.com/) 2022+
* [Boost](http://www.boost.org/) 1.67+
* [bencode.hpp](https://github.com/jimporter/bencode.hpp)
Expand Down
10 changes: 5 additions & 5 deletions include/mettle/detail/any_capture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace mettle::detail {

template<typename T, typename Enable = void>
template<typename T>
class any_capture {
public:
using type = T;
Expand All @@ -18,8 +18,8 @@ namespace mettle::detail {
T value;
};

template<typename T, std::size_t N>
class any_capture<T[N], std::enable_if_t<std::is_trivial_v<T>>> {
template<typename T, std::size_t N> requires(std::is_trivial_v<T>)
class any_capture<T[N]> {
public:
using type = T[N];

Expand All @@ -41,8 +41,8 @@ namespace mettle::detail {
# pragma warning(disable:4503)
#endif

template<typename T, std::size_t N>
class any_capture<T[N], std::enable_if_t<!std::is_trivial_v<T>>> {
template<typename T, std::size_t N>// requires(!std::is_trivial_v<T>)
class any_capture<T[N]> {
public:
using type = T[N];

Expand Down
2 changes: 1 addition & 1 deletion include/mettle/matchers/collection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace mettle {
public:
template<typename T, typename U>
each_impl(T begin, T end, U &&meta_matcher) {
static_assert(is_matcher_v<decltype(meta_matcher(*begin))>,
static_assert(any_matcher<decltype(meta_matcher(*begin))>,
"meta_matcher must be a function that returns a matcher");
for(; begin != end; ++begin)
matchers_.push_back(meta_matcher(*begin));
Expand Down
13 changes: 5 additions & 8 deletions include/mettle/matchers/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,14 @@ namespace mettle {
struct matcher_tag {};

template<typename T>
struct is_matcher : public std::is_base_of<
matcher_tag, std::remove_reference_t<T>
> {};

template<typename T>
constexpr bool is_matcher_v = is_matcher<T>::value;
concept any_matcher = std::derived_from<
std::remove_reference_t<T>, matcher_tag
>;

namespace detail {
template<typename T>
inline auto matcher_desc(T &&t) {
if constexpr(is_matcher_v<T>) {
if constexpr(any_matcher<T>) {
return std::forward<T>(t).desc();
} else {
return to_printable(std::forward<T>(t));
Expand Down Expand Up @@ -96,7 +93,7 @@ namespace mettle {

template<typename T>
inline auto ensure_matcher(T &&t) {
if constexpr(is_matcher_v<T>) {
if constexpr(any_matcher<T>) {
return std::forward<T>(t);
} else {
return equal_to(std::forward<T>(t));
Expand Down
6 changes: 2 additions & 4 deletions include/mettle/matchers/expect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ namespace mettle {
using std::runtime_error::runtime_error;
};

template<typename T, typename Matcher,
typename = std::enable_if_t< is_matcher_v<Matcher> >>
template<typename T, any_matcher Matcher>
void expect(T &&value, const Matcher &matcher,
detail::source_location loc =
detail::source_location::current()) {
Expand All @@ -44,8 +43,7 @@ namespace mettle {
}
}

template<typename T, typename Matcher,
typename = std::enable_if_t< is_matcher_v<Matcher> >>
template<typename T, any_matcher Matcher>
void expect(const std::string &desc, T &&value, const Matcher &matcher,
detail::source_location loc =
detail::source_location::current()) {
Expand Down
2 changes: 1 addition & 1 deletion include/mettle/matchers/result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace mettle {
return {!m.matched, std::move(m.message)};
}

// Ignore warnings about const-qualified function types
// Ignore warnings about const-qualified function types.
#if defined(_MSC_VER) && !defined(__clang__)
# pragma warning(push)
# pragma warning(disable:4180)
Expand Down
14 changes: 2 additions & 12 deletions include/mettle/output/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,12 @@ namespace mettle {
# pragma GCC diagnostic pop
#endif

template<typename, typename = std::void_t<>>
struct is_string_convertible : std::false_type {};

template<typename T>
struct is_string_convertible<T, std::void_t<
decltype(convert_string(std::declval<T&>()))
>> : std::true_type {};

template<typename T>
inline constexpr bool is_string_convertible_v =
is_string_convertible<T>::value;
concept string_convertible = requires(T &t) { convert_string(t); };

template<typename String>
template<string_convertible String>
inline auto
represent_string(const String &s, char delim = '"') {
static_assert(is_string_convertible_v<String>);
return escape_string(convert_string(s), delim);
}

Expand Down
28 changes: 12 additions & 16 deletions include/mettle/output/to_printable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ namespace mettle {
}

template<typename Char, typename Traits, typename Alloc>
inline auto to_printable(const std::basic_string<Char, Traits, Alloc> &s) ->
std::enable_if_t<is_string_convertible_v<
std::basic_string<Char, Traits, Alloc>>, std::string> {
inline std::string to_printable(
const std::basic_string<Char, Traits, Alloc> &s
) requires string_convertible<std::basic_string<Char, Traits, Alloc>> {
return represent_string(s);
}

template<typename Char, typename Traits>
inline auto to_printable(const std::basic_string_view<Char, Traits> &s) ->
std::enable_if_t<is_string_convertible_v<
std::basic_string_view<Char, Traits>>, std::string> {
inline std::string to_printable(
const std::basic_string_view<Char, Traits> &s
) requires string_convertible<std::basic_string_view<Char, Traits>> {
return represent_string(s);
}

Expand Down Expand Up @@ -81,10 +81,8 @@ namespace mettle {
return to_printable(static_cast<unsigned char>(b));
}

template<typename T>
inline auto to_printable(const T *s) -> std::enable_if_t<
is_any_char_v<T>, std::string
> {
template<character T>
inline std::string to_printable(const T *s) {
if(!s) return to_printable(nullptr);
return represent_string(s);
}
Expand Down Expand Up @@ -112,9 +110,7 @@ namespace mettle {
}

template<typename T, std::size_t N>
auto to_printable(const T (&v)[N]) -> std::enable_if_t<
!is_any_char_v<T>, std::string
> {
std::string to_printable(const T (&v)[N]) requires(!character<T>) {
return to_printable(std::begin(v), std::end(v));
}

Expand Down Expand Up @@ -146,13 +142,13 @@ namespace mettle {
) + ")";
} else if constexpr(std::is_same_v<std::remove_cv_t<T>, bool>) {
return t ? "true" : "false";
} else if constexpr(is_printable_v<T>) {
} else if constexpr(printable<T>) {
return t;
} else if constexpr(is_exception_v<T>) {
} else if constexpr(any_exception<T>) {
std::ostringstream ss;
ss << type_name(t) << "(" << to_printable(t.what()) << ")";
return ss.str();
} else if constexpr(is_iterable_v<T>) {
} else if constexpr(iterable<T>) {
return to_printable(std::begin(t), std::end(t));
} else {
return type_name<T>();
Expand Down
54 changes: 20 additions & 34 deletions include/mettle/output/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,36 @@
#include <type_traits>

namespace mettle {
template<typename T> struct is_any_char : std::false_type {};
template<typename T> struct is_any_char<const T> : is_any_char<T> {};
template<typename T> struct is_any_char<volatile T> : is_any_char<T> {};
template<typename T> struct is_any_char<const volatile T> : is_any_char<T> {};

template<> struct is_any_char<char> : std::true_type {};
template<> struct is_any_char<wchar_t> : std::true_type {};
template<typename T> struct is_character : std::false_type {};
template<typename T> struct is_character<const T> : is_character<T> {};
template<typename T> struct is_character<volatile T> : is_character<T> {};
template<typename T> struct is_character<const volatile T>
: is_character<T> {};

template<> struct is_character<char> : std::true_type {};
template<> struct is_character<wchar_t> : std::true_type {};
#if __cpp_char8_t
template<> struct is_any_char<char8_t> : std::true_type {};
template<> struct is_character<char8_t> : std::true_type {};
#endif
template<> struct is_any_char<char16_t> : std::true_type {};
template<> struct is_any_char<char32_t> : std::true_type {};

template<typename T>
using is_exception = std::is_base_of<std::exception, T>;

template<typename, typename = std::void_t<>>
struct is_printable : std::false_type {};

template<typename T>
struct is_printable<T, std::void_t<
decltype(std::declval<std::ostream&>() << std::declval<T>())
>> : std::true_type {};

template<typename, typename = std::void_t<>>
struct is_iterable : std::false_type {};

template<typename T>
struct is_iterable<T, std::void_t<
decltype(std::begin(std::declval<T&>()), std::end(std::declval<T&>()))
>> : std::true_type {};

template<> struct is_character<char16_t> : std::true_type {};
template<> struct is_character<char32_t> : std::true_type {};

template<typename T>
inline constexpr bool is_any_char_v = is_any_char<T>::value;
concept character = is_character<T>::value;

template<typename T>
inline constexpr bool is_exception_v = is_exception<T>::value;
concept any_exception = std::derived_from<T, std::exception>;

template<typename T>
inline constexpr bool is_iterable_v = is_iterable<T>::value;
concept iterable = requires(T &t) {
std::begin(t);
std::end(t);
};

template<typename T>
inline constexpr bool is_printable_v = is_printable<T>::value;
concept printable = requires(std::ostream &os, T &t) {
os << t;
};

} // namespace mettle

Expand Down
7 changes: 4 additions & 3 deletions include/mettle/suite/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ namespace mettle {
class bind_factory_t {
using tuple_type = std::tuple<detail::any_capture<Args>...>;
public:
template<typename ...CallArgs, typename = std::enable_if_t<
std::is_constructible<tuple_type, CallArgs...>::value
>> explicit bind_factory_t(CallArgs &&...args) : args_(args...) {}
template<typename ...CallArgs>
explicit bind_factory_t(CallArgs &&...args)
requires std::constructible_from<tuple_type, CallArgs...> :
args_(args...) {}

template<typename T>
T make() const {
Expand Down

0 comments on commit 81a1f53

Please sign in to comment.