forked from wpilibsuite/allwpilib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
446 additions
and
0 deletions.
There are no files selected for viewing
207 changes: 207 additions & 0 deletions
207
wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/test_types.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors | ||
// SPDX-License-Identifier: Zlib | ||
|
||
#ifndef FOONATHAN_MEMORY_TOOL_TEST_TYPES_HPP_INCLUDED | ||
#define FOONATHAN_MEMORY_TOOL_TEST_TYPES_HPP_INCLUDED | ||
|
||
#include <cstddef> | ||
#include <tuple> | ||
|
||
#if !defined(_MSC_VER) | ||
|
||
// erases duplicate alignments | ||
// adopted from https://github.com/irrequietus/clause/blob/alignutil/clause/ample/storage/alignutil.hh | ||
// Copyright (C) 2013 - 2016 George Makrydakis <[email protected]> | ||
namespace detail | ||
{ | ||
template <typename T> | ||
using M0 = typename T::type; | ||
|
||
/*~ | ||
* @note Forward declarations for several utility templates that are to be used | ||
* for emulating high order functions over a pack without using the rest | ||
* of the clause::ample library for two reasons: (1) alignof allows for | ||
* special optimizations when applied over a pack of types range for the | ||
* "sorting by alignof" step; (2) a single header solution was required | ||
* and depending on other parts would mean bring increasing compoments | ||
* of full-fledged metaprogramming library features. This header is to | ||
* provide utilities for aligned storage and it came up when a challenge | ||
* was thrown to me during a discussion with my fellow C++ programmers | ||
* Jonathan Müller and Manu Sánchez. Purpose of inclusion to `clause is | ||
* simple: it can be of use when analyzing boilerplate generation for | ||
* runtime containers and memory allocators by template metaprogramming. | ||
* | ||
* tl;dr: fully standalone header for getting a duplicate-free, sorted by | ||
* alignment list of types unique by alignment. | ||
*/ | ||
template <typename...> | ||
struct M1; // Insert by alignof (map) | ||
template <typename, typename> | ||
struct M2; // Remove by alignof (M1 map) | ||
template <typename...> | ||
struct M3; // A pack wrap instead of M1 | ||
template <typename, typename, typename> | ||
struct M4; // 'foldl,fmap' dups to M1<> | ||
template <typename, typename...> | ||
struct M5; // Remove M1<> | ||
template <typename, std::size_t, std::size_t, std::size_t...> | ||
struct M6; // Sort by alignof | ||
|
||
/*~ | ||
* @note Both `M1,`M2 are used as a mutable compile-time "map"; `M1 inheritance | ||
* of function signature of the kind: | ||
* | ||
* static auto C(int(*)[alignof(X)]) -> X | ||
* | ||
* is used as a key/value store in the first "fold", while `M2 is used for | ||
* a lookup removing occurences of duplicates in the second "fold" by | ||
* substituting each with `M1<>; this is orchestrated by `M4 while cleanup | ||
* is handled by `M5 (removal of those `M1<> markers). | ||
*/ | ||
template <typename X, typename... T> | ||
struct M1<X, T...> : M1<T...> | ||
{ | ||
using M1<T...>::C; | ||
|
||
static auto C(int (*)[alignof(X)]) -> X; | ||
|
||
static std::size_t constexpr min_val = | ||
alignof(X) < M1<T...>::min_val ? alignof(X) : M1<T...>::min_val; | ||
|
||
static std::size_t constexpr max_val = | ||
alignof(X) > M1<T...>::max_val ? alignof(X) : M1<T...>::max_val; | ||
|
||
template <template <typename...> class W> | ||
using rebind = W<X, T...>; | ||
}; | ||
|
||
template <> | ||
struct M1<> | ||
{ | ||
static M1<> C(...); | ||
static std::size_t constexpr min_val = 1; | ||
static std::size_t constexpr max_val = 1; | ||
|
||
template <template <typename...> class W> | ||
using rebind = W<>; | ||
}; | ||
|
||
template <typename W, typename X> | ||
struct M2 : W | ||
{ | ||
using W::C; | ||
static auto C(int (*)[alignof(X)]) -> M1<>; | ||
}; | ||
|
||
template <typename...> | ||
struct M3 | ||
{ /* one could use M1 instead, but it renders the code more cryptic */ | ||
}; | ||
|
||
/*~ | ||
* @note Scanning for duplicates while removing them at the same time. | ||
*/ | ||
template <typename S, typename A, template <typename...> class W, typename... X, typename... Y> | ||
struct M4<S, W<A, X...>, W<Y...>> | ||
: M4<M2<S, A>, W<X...>, W<Y..., decltype(S::C((int (*)[alignof(A)])(nullptr)))>> | ||
{ | ||
}; | ||
|
||
template <typename S, template <typename...> class W, typename... Y> | ||
struct M4<S, W<>, W<Y...>> | ||
{ | ||
using type = W<Y...>; | ||
}; | ||
|
||
template <typename A, typename...> | ||
struct M5 | ||
{ | ||
using type = A; | ||
}; | ||
|
||
/*~ | ||
* @note Cleaning up random empty `M1<> types after `M4. | ||
*/ | ||
template <template <typename...> class W, typename... A, typename... B, typename X> | ||
struct M5<W<A...>, W<X, B...>> : M5<W<A..., X>, W<B...>> | ||
{ | ||
}; | ||
|
||
template <template <typename...> class W, typename... A, typename... B> | ||
struct M5<W<A...>, W<M1<>, B...>> : M5<W<A...>, W<B...>> | ||
{ | ||
}; | ||
|
||
template <template <typename...> class W, typename... A> | ||
struct M5<W<A...>, W<>> : M5<M1<A...>> | ||
{ | ||
}; // ::type instantiates to M1<A...> ! | ||
|
||
/*~ | ||
* @note Sorting step; because of alignof(X) being a power of 2 and the way | ||
* our "map" in M1/M2 works, it is extremely simple to optimize using | ||
* linear expansion of a sequence of powers of two, then use intrinsic | ||
* "fmap" properties of the triple-dot operator for pack expansion to | ||
* yield the types remaining in the M1/M2 "map" (here, it is the S type | ||
* parameter). Iterates through min/max values (parameters A, B) by | ||
* creating that sequence then deploying it upon the ::C(int(*)[Z]) | ||
* function signature doing the lookup for M1/M2. | ||
*/ | ||
template <typename S, std::size_t A, std::size_t B, std::size_t... Z> | ||
struct M6 : M6<S, A * 2, B, Z..., A> | ||
{ | ||
}; | ||
|
||
template <typename S, std::size_t A, std::size_t... Z> | ||
struct M6<S, A, A, Z...> | ||
{ | ||
using type = | ||
M1<decltype(S::C((int (*)[Z])(nullptr)))..., decltype(S::C((int (*)[A])(nullptr)))>; | ||
}; | ||
|
||
/*~ | ||
* @note Assembling everything together; `M0 is just for convenience purposes | ||
* in order to avoid writing typename Type::type where applicable; while | ||
* the `M4 cleans up duplicates by replacement through `M1 and `M2 lookup | ||
* in combination with triple-dot expansion ("fmap"...). Notice that `M1 | ||
* is re-used many times as a plain linear container itself, upon which | ||
* `M4 partial specializations match through ordering. | ||
*/ | ||
template <typename... X> | ||
using M7 = M0< | ||
M5<M3<>, | ||
M0<M4<M1<decltype(M1<X...>::C((int (*)[alignof(X)])(nullptr)))...>, M3<X...>, M3<>>>>>; | ||
|
||
/*~ | ||
* @note The final result is given by this template alias, instantiating to a | ||
* `M1 wrapped pack containing everything that is used afterwards via | ||
* a ::template rebind instantiation to wrap to an end user defined | ||
* template template parameter type. Through this, `M6 will run only | ||
* through the necessary range of powers of 2 for the sorting to occur. | ||
*/ | ||
template <typename... X> | ||
using unisorted_aligned_ = M0<M6<M7<X...>, M1<X...>::min_val, M1<X...>::max_val>>; | ||
|
||
/*~ | ||
* @desc Given a sequence of types that may contain duplicates of both quality | ||
* (the kind of type X) and of alignment (result of alignedof(X)) provide | ||
* the equivalent sorted list of unique types by alignment. Semantics are | ||
* eager. | ||
* @parm W : template template parameter type wrapping a sequence of types. | ||
* @parm X...: parameter pack containing the aforementioned types. | ||
*/ | ||
template <template <typename...> class W, typename... X> | ||
using unisorted_aligned_wrap = typename unisorted_aligned_<X...>::template rebind<W>; | ||
} // namespace detail | ||
|
||
// All fundamental types that don't guarantee to have the same alignment (like int and unsigned int). | ||
// It thus covers all fundamental alignments and all possible node sizes. | ||
// Does not support extended alignments! | ||
// The cryptic template stuff above erases duplicate alignments | ||
using test_types = detail::unisorted_aligned_wrap<std::tuple, char, bool, short, int, long, | ||
long long, float, double, long double>; | ||
#else | ||
using test_types = std::tuple<char, bool, short, int, long, long long, float, double, long double>; | ||
#endif | ||
|
||
#endif // FOONATHAN_MEMORY_TOOL_TEST_TYPES_HPP_INCLUDED |
18 changes: 18 additions & 0 deletions
18
wpiutil/src/main/native/thirdparty/memory/src/get_align_of.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#include <cstddef> | ||
|
||
template<typename T, size_t alignment> | ||
struct align_of | ||
{ | ||
static_assert(alignment == 0, "this should fail, the purpose of this is to generate a compile error on this type that contains the alignment value on this target"); | ||
}; | ||
|
||
template<typename T> | ||
using get_align_of = align_of<T, alignof(T)>; | ||
|
||
// Workaround for environments that have issues passing in type names with spaces | ||
using LONG_LONG = long long; | ||
using LONG_DOUBLE = long double; | ||
|
||
#ifdef TEST_TYPE | ||
get_align_of<TEST_TYPE> dummy; | ||
#endif |
Oops, something went wrong.