Skip to content

Commit

Permalink
Move helper functions into ktl::detail namespace
Browse files Browse the repository at this point in the history
Use template struct for closest-power-of-2 in segragator_fwd
  • Loading branch information
KredeGC committed Jan 2, 2023
1 parent b9a2da6 commit ec31f7e
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 82 deletions.
35 changes: 19 additions & 16 deletions include/ktl/allocators/fallback_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,25 @@ namespace ktl
template<typename T, typename P, typename F>
using type_fallback_allocator = type_allocator<T, fallback<P, F>>;

// variadic builder
template<typename ...Args>
struct fallback_builder;

template<typename Primary, typename Fallback>
struct fallback_builder<Primary, Fallback>
{
using type = fallback<Primary, Fallback>;
};

template<typename Alloc, typename ...Args>
struct fallback_builder<Alloc, Args...>
namespace detail
{
using type = fallback<Alloc, typename fallback_builder<Args...>::type>;
};
// Recursive helper struct for generating the fallback type
template<typename ...Ts>
struct fallback_builder;

template<typename Primary, typename Fallback>
struct fallback_builder<Primary, Fallback>
{
using type = fallback<Primary, Fallback>;
};

template<typename Alloc, typename ...Ts>
struct fallback_builder<Alloc, Ts...>
{
using type = fallback<Alloc, typename fallback_builder<Ts...>::type>;
};
}

template<typename ...Args>
using fallback_builder_t = typename fallback_builder<Args...>::type;
template<typename ...Ts>
using fallback_builder_t = typename detail::fallback_builder<Ts...>::type;
}
138 changes: 73 additions & 65 deletions include/ktl/allocators/segragator_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,76 +17,84 @@ namespace ktl
template<typename T, size_t Threshold, typename P, typename F>
using type_segragator_allocator = type_allocator<T, segragator<Threshold, P, F>>;

// Helper function for getting the closest power of 2
constexpr size_t pow2_ceil(size_t v)
namespace detail
{
--v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return ++v;
// Helper struct for getting the closest power of 2
template<size_t x>
struct pow2
{
enum : size_t
{
a = x - 1,
b = a | (a >> 1),
c = b | (b >> 2),
d = c | (c >> 4),
e = d | (d >> 8),
f = e | (e >> 16),
g = f | (f >> 32),
result = g + 1
};
};

// Helper struct for splitting a tuple in 2
template<typename, typename, typename>
struct tuple_split;

template<std::size_t ...N, std::size_t ...M, typename T>
struct tuple_split<std::index_sequence<N...>, std::index_sequence<M...>, T>
{
// The middle point is at sizeof...(N)
using first = std::tuple<typename std::tuple_element_t<N, T>...>;

// Offset by N + 1, since we don't want the middle point in either
using second = std::tuple<typename std::tuple_element_t<M + 1 + sizeof...(N), T>...>;
};

// Recursive helper struct for generating the segragator type
template<typename ...Ts>
struct segragator_builder;

// When three types remain, use a segragator
template<typename Primary, typename Threshold, typename Secondary>
struct segragator_builder<std::tuple<Primary, Threshold, Secondary>>
{
using type = segragator<Threshold::value, Primary, Secondary>;
};

// When a single type remains, just return it
template<typename Alloc>
struct segragator_builder<std::tuple<Alloc>>
{
using type = Alloc;
};

// Takes in a tuple of types and returns the final segragator
template<typename ...Ts>
struct segragator_builder<std::tuple<Ts...>>
{
static_assert(sizeof...(Ts) % 2 != 0, "The number of allocators needs to match the number of thresholds + 1");

// The middle of the type is the root of a complete binary tree
// The root of a complete binary tree is (2^(log2(N)) - 1) / 2
static constexpr size_t max = sizeof...(Ts);
static constexpr size_t middle = (pow2<max>::result - 1) / 2;

using split = tuple_split<
std::make_index_sequence<middle>, // Up to, but not including the middle threshold
std::make_index_sequence<max - middle - 1>, // Anything after the middle threshold
std::tuple<Ts...>>;

using threshold = typename std::tuple_element_t<middle, std::tuple<Ts...>>;
using first = typename segragator_builder<typename split::first>::type;
using second = typename segragator_builder<typename split::second>::type;

using type = segragator<threshold::value, first, second>;
};
}

// Helper struct for splitting a tuple in 2
template<typename, typename, typename>
struct tuple_split;

template<std::size_t... N, std::size_t... M, typename T>
struct tuple_split<std::index_sequence<N...>, std::index_sequence<M...>, T>
{
// The middle point is at sizeof...(N)
using first = std::tuple<typename std::tuple_element_t<N, T>...>;

// Offset by N + 1, since we don't want the middle point in either
using second = std::tuple<typename std::tuple_element_t<M + 1 + sizeof...(N), T>...>;
};

// Recursive helper struct for generating the segragator type
template<typename... Ts>
struct segragator_builder;

// When three types remain, use a segragator
template<typename Primary, typename Threshold, typename Secondary>
struct segragator_builder<std::tuple<Primary, Threshold, Secondary>>
{
using type = segragator<Threshold::value, Primary, Secondary>;
};

// When a single type remains, just return it
template<typename Alloc>
struct segragator_builder<std::tuple<Alloc>>
{
using type = Alloc;
};

// Takes in a tuple of types and returns the final segragator
template<class... Ts>
struct segragator_builder<std::tuple<Ts...>>
{
static_assert(sizeof...(Ts) % 2 != 0, "The number of allocators needs to match the number of thresholds + 1");

// The middle of the type is the root of a complete binary tree
// The root of a complete binary tree is (2^(log2(N)) - 1) / 2
static constexpr size_t max = sizeof...(Ts);
static constexpr size_t middle = (pow2_ceil(max) - 1) / 2;

using split = tuple_split<
std::make_index_sequence<middle>, // Up to, but not including the middle threshold
std::make_index_sequence<max - middle - 1>, // Anything after the middle threshold
std::tuple<Ts...>>;

using threshold = typename std::tuple_element_t<middle, std::tuple<Ts...>>;
using first = typename segragator_builder<typename split::first>::type;
using second = typename segragator_builder<typename split::second>::type;

using type = segragator<threshold::value, first, second>;
};

// Helper type without the tuple
template<typename ...Ts>
using segragator_builder_t = typename segragator_builder<std::tuple<Ts...>>::type;
using segragator_builder_t = typename detail::segragator_builder<std::tuple<Ts...>>::type;

template<size_t N>
using threshold = std::integral_constant<size_t, N>;
Expand Down
3 changes: 3 additions & 0 deletions src/test/fallback_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ namespace ktl::test::fallback_allocator
fallback<
linear_allocator<4096>,
mallocator>>>;

Alloc1 alloc1;
Alloc2 alloc2;

static_assert(std::is_same_v<Alloc1, Alloc2>, "The allocator types don't match");
}
Expand Down
5 changes: 4 additions & 1 deletion src/test/segragator_allocator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ namespace ktl::test::segragator_allocator
linear_allocator<8192>>>,
mallocator>;

Alloc3 allocator;
Alloc1 alloc1;
Alloc2 alloc2;
Alloc3 alloc3;
Alloc4 alloc4;

static_assert(!std::is_same_v<Alloc1, Alloc2>, "The allocator types shouldn't match");
static_assert(std::is_same_v<Alloc3, Alloc4>, "The allocator types don't match");
Expand Down

0 comments on commit ec31f7e

Please sign in to comment.