Skip to content

Commit

Permalink
Clean up (#3)
Browse files Browse the repository at this point in the history
Clean up some visibility specs, update doc and readme
  • Loading branch information
Yuki-cpp authored Dec 17, 2023
1 parent 7ece8b9 commit 9a2d6c6
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 37 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(
CMAKE_EXPORT_COMPILE_COMMANDS
ON
)

find_package(Catch2 REQUIRED)

add_executable(typelist_utils test/main.cpp test/test_utils.cpp test/test_sort.cpp)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typelist_utils
# typelist_utils, a metaprogramming library
[![Build and Test Package](https://github.com/cpp-playground/typelist-utils/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/cpp-playground/typelist-utils/actions/workflows/build_and_test.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=cpp-playground_typelist-utils&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=cpp-playground_typelist-utils)
[![codecov](https://codecov.io/gh/cpp-playground/typelist-utils/branch/main/graph/badge.svg?token=ZDSZZLN6MP)](https://codecov.io/gh/cpp-playground/typelist-utils)
12 changes: 10 additions & 2 deletions include/typelist_utils/sort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ template <typename A,
template <typename, typename>
typename Predicate>
requires tl::concepts::binary_value_predicate<Predicate, A, B>
struct merge<std::tuple<A, As...>, std::tuple<B, Bs...>, Predicate>
class merge<std::tuple<A, As...>, std::tuple<B, Bs...>, Predicate>
{
using list_a = std::tuple<A, As...>;
using list_b = std::tuple<B, Bs...>;

public:
using type = std::conditional_t<
Predicate<A, B>::value,
tl::concat_t<std::tuple<A>, typename merge<std::tuple<As...>, list_b, Predicate>::type>,
Expand All @@ -60,6 +62,11 @@ using merge_t = typename merge<A, B, Predicate>::type;

} // namespace sort_impl

/**
* @brief Sorts a tuple-like type using the given predicate.
* @tparam T The tuple-like type.
* @tparam Predicate The binary value predicate to use for sorting.
*/
template <tl::concepts::tuple T, template <typename, typename> typename Predicate>
struct sort;

Expand All @@ -77,12 +84,13 @@ struct sort<std::tuple<T>, Predicate>

// Inductive step
template <typename T, typename... Ts, template <typename, typename> typename Predicate>
struct sort<std::tuple<T, Ts...>, Predicate>
class sort<std::tuple<T, Ts...>, Predicate>
{
using input_t = std::tuple<T, Ts...>;
using left_sort_t = typename sort<tl::sort_impl::split_half_l_t<input_t>, Predicate>::type;
using right_sort_t = typename sort<tl::sort_impl::split_half_r_t<input_t>, Predicate>::type;

public:
using type = tl::sort_impl::merge_t<left_sort_t, right_sort_t, Predicate>;
};

Expand Down
119 changes: 99 additions & 20 deletions include/typelist_utils/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,28 @@
#include <tuple>
#include <type_traits>

/**
* @brief Namespace containing trait types
*/
namespace tl::traits
{

/**
* @brief Trait type used to check if a given type is a tuple
* Inherits std::true_type if so, std::false_type otherwise.
*
* @tparam T Type to check
*/
template <typename>
struct is_tuple : std::false_type
{};

/**
* @brief Trait type used to check if a given type is a tuple
* Inherits std::true_type if so, std::false_type otherwise.
*
* @tparam T Type to check
*/
template <typename... Ts>
struct is_tuple<std::tuple<Ts...>> : std::true_type
{};
Expand All @@ -17,40 +34,102 @@ constexpr auto is_tuple_v = is_tuple<T>::value;

} // namespace tl::traits

/**
* @brief Namespace containing concepts
*/
namespace tl::concepts
{

/**
* @brief Concept checking that 2 given types are the same
* @tparam T First type to check
* @tparam U Second type to check
*/
template <typename T, typename U>
concept same_as = std::is_same_v<T, U>;

/**
* @brief Concept checking a given type is a tuple type
* @tparam T Type to check
*/
template <typename T>
concept tuple = tl::traits::is_tuple_v<T>;

/**
* @brief Concept checking that a given type can be used as a binary value predicate for
* 2 other types.
*
* A binary value predicate is a type that, given 2 types exposes a static field
* value of type bool
*
* @tparam P Predicate type to check
* @tparam T First type for the predicate to be used on
* @tparam U Second type for the predicate to be used on
*/
template <template <typename, typename> typename P, typename T, typename U>
concept binary_value_predicate = requires
{
{
P<T, U>::value
} -> same_as<const bool&>;
};
concept binary_value_predicate = requires {
{
P<T, U>::value
} -> same_as<const bool&>;
};

/**
* @brief Concept checking that a given type can be used as a unary value predicate for
* another type.
*
* A unary value predicate is a type that, given another types exposes a static field
* value of type bool
*
* @tparam P Predicate type to check
* @tparam T Type for the predicate to be used on
*/
template <template <typename> typename P, typename T>
concept unary_value_predicate = requires
{
{
P<T>::value
} -> same_as<const bool&>;
};
concept unary_value_predicate = requires {
{
P<T>::value
} -> same_as<const bool&>;
};

/**
* @brief Concept checking that a given type can be used as a binary type predicate for
* 2 other types.
*
* A binary type predicate is a type that, given 2 types exposes a type member named type
*
* @tparam P Predicate type to check
* @tparam T First type for the predicate to be used on
* @tparam U Second type for the predicate to be used on
*/
template <template <typename, typename> typename P, typename T, typename U>
concept binary_type_predicate = requires
{
typename P<T, U>;
};
concept binary_type_predicate = requires { typename P<T, U>::type; };

/**
* @brief Concept checking that a given type can be used as a unary type predicate for
* another type.
*
* A unary type predicate is a type that, given another type exposes a type member named type
*
* @tparam P Predicate type to check
* @tparam T Type for the predicate to be used on
*/
template <template <typename> typename P, typename T>
concept unary_type_predicate = requires
{
typename P<T>::type;
};
concept unary_type_predicate = requires { typename P<T>::type; };

/**
* @brief Concept checking that a pair of indices are valid swap indices for a given tuple
*
* 2 indices are valid if the first is strictly smaller than the second and that the second
* is strictly smaller than the provided tuple size
*
* @tparam T Tuple to check indices validity against
* @tparam first First index
* @tparam second Second index
*/
template <typename T, std::size_t first, std::size_t second>
concept valid_swap_indices = requires {
requires tl::concepts::tuple<T>;
requires first < second;
requires second < std::tuple_size_v<T>;
};

} // namespace tl::concepts
60 changes: 46 additions & 14 deletions include/typelist_utils/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

namespace tl
{
/**
* @brief Checks if a tuple-like type starts with a given type.
*
* @tparam T The tuple-like type.
* @tparam E The type to check for.
*/
template <tl::concepts::tuple T, typename E>
struct start_with
{
Expand All @@ -21,15 +27,22 @@ struct start_with<std::tuple<T, Ts...>, E>
template <tl::concepts::tuple T, typename E>
constexpr auto start_with_v = start_with<T, E>::value;

/**
* @brief Counts the number of times a type appears in a tuple-like type.
*
* @tparam T The tuple-like type.
* @tparam E The type to count.
*/
template <tl::concepts::tuple T, typename E>
struct count
class count
{
template <std::size_t... indexes>
static constexpr auto impl(std::index_sequence<indexes...>)
{
return ((std::is_same_v<E, std::tuple_element_t<indexes, T>> ? 1 : 0) + ... + 0);
}

public:
static constexpr auto value =
impl(std::make_integer_sequence<std::size_t, std::tuple_size_v<T>>{});
};
Expand All @@ -40,6 +53,11 @@ constexpr auto count_v = count<T, E>::value;
template <tl::concepts::tuple T, typename E>
constexpr auto contains_v = 0 < count_v<T, E>;

/**
* @brief Checks if a tuple-like type contains all of the given types.
* @tparam T The tuple-like type.
* @tparam Es The types to check for.
*/
template <tl::concepts::tuple T, typename... Es>
struct contains_all
{
Expand All @@ -50,6 +68,11 @@ struct contains_all
template <tl::concepts::tuple T, typename... Es>
constexpr auto contains_all_v = contains_all<T, Es...>::value;

/**
* @brief Concatenates two tuple-like types.
* @tparam T The first tuple-like type.
* @tparam U The second tuple-like type.
*/
template <tl::concepts::tuple T, tl::concepts::tuple U>
struct concat;
template <typename... Ts, typename... Us>
Expand All @@ -60,16 +83,22 @@ struct concat<std::tuple<Ts...>, std::tuple<Us...>>
template <tl::concepts::tuple T, tl::concepts::tuple U>
using concat_t = typename tl::concat<T, U>::type;

/**
* @brief split a tuple-like type in 2 at the given index.
* @tparam T The tuple-like type.
* @tparam split_index The index to split at.
*/
template <tl::concepts::tuple T, std::size_t split_index>
requires(split_index <= std::tuple_size_v<T>)
struct split
class split
{
template <std::size_t start, std::size_t... indexes>
static constexpr auto impl(std::index_sequence<indexes...>)
{
return std::tuple<std::tuple_element_t<start + indexes, T>...>{};
}

public:
using l = decltype(impl<0>(std::make_integer_sequence<std::size_t, split_index>()));
using r = decltype(impl<split_index>(
std::make_integer_sequence<std::size_t, std::tuple_size_v<T> - split_index>()));
Expand All @@ -83,6 +112,11 @@ template <tl::concepts::tuple T, std::size_t split_index>
requires(split_index <= std::tuple_size_v<T>)
using split_l_t = typename split<T, split_index>::l;

/**
* @brief Applies a unary type predicate to each type in a tuple-like type.
* @tparam T The tuple-like type.
* @tparam F The unary type predicate.
*/
template <tl::concepts::tuple T, template <typename> typename F>
struct for_each;

Expand All @@ -102,22 +136,19 @@ struct for_each<std::tuple<T, Ts...>, F>
template <tl::concepts::tuple T, template <typename> typename F>
using for_each_t = typename for_each<T, F>::type;

/**
* @brief Swap 2 elements in a tuple-like type.
* @tparam T The tuple-like type.
* @tparam first The first index.
* @tparam second The second index.
*/
template <tl::concepts::tuple T, std::size_t first, std::size_t second>
requires requires
{
requires first < second;
requires second < std::tuple_size_v<T>;
}
struct swap_elements
requires tl::concepts::valid_swap_indices<T, first, second>
class swap_elements
{
template <std::size_t... start_to_first_indexes,
std::size_t... first_to_second_indexes,
std::size_t... second_to_end_indexes>
requires requires
{
requires first < second;
requires second < std::tuple_size_v<T>;
}
static constexpr auto swap_helper(std::index_sequence<start_to_first_indexes...>,
std::index_sequence<first_to_second_indexes...>,
std::index_sequence<second_to_end_indexes...>)
Expand All @@ -140,10 +171,11 @@ struct swap_elements
return swap_helper(start_to_first, first_to_second, second_to_end);
}

public:
using type = decltype(swap_helper_boilerplate());
};

template <tl::concepts::tuple T, std::size_t first, std::size_t second>
using swap_elements_t = typename swap_elements<T, first, second>::type;

} // namespace tl
} // namespace tl

0 comments on commit 9a2d6c6

Please sign in to comment.