File: test_types.hpp

package info (click to toggle)
foonathan-memory 0.7.3-2.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,644 kB
  • sloc: cpp: 12,394; xml: 139; sh: 48; makefile: 25
file content (207 lines) | stat: -rw-r--r-- 8,285 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
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 <george@irrequietus.eu>
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