1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef BENCHMARK_GENERATE_INPUT_H |
10 | #define BENCHMARK_GENERATE_INPUT_H |
11 | |
12 | #include <algorithm> |
13 | #include <climits> |
14 | #include <concepts> |
15 | #include <cstddef> |
16 | #include <initializer_list> |
17 | #include <random> |
18 | #include <string> |
19 | #include <vector> |
20 | |
21 | static const char Letters[] = { |
22 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', |
23 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', |
24 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; |
25 | static const std::size_t = sizeof(Letters); |
26 | |
27 | inline std::default_random_engine& getRandomEngine() { |
28 | static std::default_random_engine RandEngine(std::random_device{}()); |
29 | return RandEngine; |
30 | } |
31 | |
32 | inline char getRandomChar() { |
33 | std::uniform_int_distribution<> LettersDist(0, LettersSize - 1); |
34 | return Letters[LettersDist(getRandomEngine())]; |
35 | } |
36 | |
37 | template <class IntT> |
38 | inline IntT getRandomInteger(IntT Min, IntT Max) { |
39 | std::uniform_int_distribution<unsigned long long> dist(Min, Max); |
40 | return static_cast<IntT>(dist(getRandomEngine())); |
41 | } |
42 | |
43 | inline std::string getRandomString(std::size_t Len) { |
44 | std::string str(Len, 0); |
45 | std::generate_n(first: str.begin(), n: Len, gen: &getRandomChar); |
46 | return str; |
47 | } |
48 | |
49 | template <class IntT> |
50 | inline std::vector<IntT> getDuplicateIntegerInputs(std::size_t N) { |
51 | std::vector<IntT> inputs(N, static_cast<IntT>(-1)); |
52 | return inputs; |
53 | } |
54 | |
55 | template <class IntT> |
56 | inline std::vector<IntT> getSortedIntegerInputs(std::size_t N) { |
57 | std::vector<IntT> inputs; |
58 | inputs.reserve(N); |
59 | for (std::size_t i = 0; i < N; i += 1) |
60 | inputs.push_back(i); |
61 | return inputs; |
62 | } |
63 | |
64 | template <class IntT> |
65 | std::vector<IntT> getSortedLargeIntegerInputs(std::size_t N) { |
66 | std::vector<IntT> inputs; |
67 | inputs.reserve(N); |
68 | for (std::size_t i = 0; i < N; ++i) |
69 | inputs.push_back(i + N); |
70 | return inputs; |
71 | } |
72 | |
73 | template <class IntT> |
74 | std::vector<IntT> getSortedTopBitsIntegerInputs(std::size_t N) { |
75 | std::vector<IntT> inputs = getSortedIntegerInputs<IntT>(N); |
76 | for (auto& E : inputs) |
77 | E <<= ((sizeof(IntT) / 2) * CHAR_BIT); |
78 | return inputs; |
79 | } |
80 | |
81 | template <class IntT> |
82 | inline std::vector<IntT> getReverseSortedIntegerInputs(std::size_t N) { |
83 | std::vector<IntT> inputs; |
84 | inputs.reserve(N); |
85 | std::size_t i = N; |
86 | while (i > 0) { |
87 | --i; |
88 | inputs.push_back(i); |
89 | } |
90 | return inputs; |
91 | } |
92 | |
93 | template <class IntT> |
94 | std::vector<IntT> getPipeOrganIntegerInputs(std::size_t N) { |
95 | std::vector<IntT> v; |
96 | v.reserve(N); |
97 | for (std::size_t i = 0; i < N / 2; ++i) |
98 | v.push_back(i); |
99 | for (std::size_t i = N / 2; i < N; ++i) |
100 | v.push_back(N - i); |
101 | return v; |
102 | } |
103 | |
104 | template <class IntT> |
105 | std::vector<IntT> getRandomIntegerInputs(std::size_t N) { |
106 | std::vector<IntT> inputs; |
107 | inputs.reserve(N); |
108 | for (std::size_t i = 0; i < N; ++i) |
109 | inputs.push_back(getRandomInteger<IntT>(0, std::numeric_limits<IntT>::max())); |
110 | return inputs; |
111 | } |
112 | |
113 | inline std::vector<std::string> getRandomStringInputsWithLength(std::size_t N, std::size_t len) { // N-by-len |
114 | std::vector<std::string> inputs; |
115 | inputs.reserve(n: N); |
116 | for (std::size_t i = 0; i < N; ++i) |
117 | inputs.push_back(x: getRandomString(Len: len)); |
118 | return inputs; |
119 | } |
120 | |
121 | inline std::vector<std::string> getDuplicateStringInputs(std::size_t N) { |
122 | std::vector<std::string> inputs(N, getRandomString(Len: 1024)); |
123 | return inputs; |
124 | } |
125 | |
126 | inline std::vector<std::string> getRandomStringInputs(std::size_t N) { |
127 | return getRandomStringInputsWithLength(N, len: 1024); |
128 | } |
129 | |
130 | template <class IntT> |
131 | std::vector<std::vector<IntT>> getRandomIntegerInputsWithLength(std::size_t N, std::size_t len) { // N-by-len |
132 | std::vector<std::vector<IntT>> inputs; |
133 | inputs.reserve(N); |
134 | for (std::size_t i = 0; i < N; ++i) |
135 | inputs.push_back(getRandomIntegerInputs<IntT>(len)); |
136 | return inputs; |
137 | } |
138 | |
139 | inline std::vector<std::string> getSSORandomStringInputs(size_t N) { |
140 | std::vector<std::string> inputs; |
141 | for (size_t i = 0; i < N; ++i) |
142 | inputs.push_back(x: getRandomString(Len: 10)); // SSO |
143 | return inputs; |
144 | } |
145 | |
146 | inline std::vector<std::string> getPrefixedRandomStringInputs(size_t N) { |
147 | std::vector<std::string> inputs; |
148 | inputs.reserve(n: N); |
149 | constexpr int kSuffixLength = 32; |
150 | const std::string prefix = getRandomString(Len: 1024 - kSuffixLength); |
151 | for (std::size_t i = 0; i < N; ++i) |
152 | inputs.push_back(x: prefix + getRandomString(Len: kSuffixLength)); |
153 | return inputs; |
154 | } |
155 | |
156 | inline std::vector<std::string> getSortedStringInputs(std::size_t N) { |
157 | std::vector<std::string> inputs = getRandomStringInputs(N); |
158 | std::sort(first: inputs.begin(), last: inputs.end()); |
159 | return inputs; |
160 | } |
161 | |
162 | inline std::vector<std::string> getReverseSortedStringInputs(std::size_t N) { |
163 | std::vector<std::string> inputs = getSortedStringInputs(N); |
164 | std::reverse(first: inputs.begin(), last: inputs.end()); |
165 | return inputs; |
166 | } |
167 | |
168 | inline std::vector<const char*> getRandomCStringInputs(std::size_t N) { |
169 | static std::vector<std::string> inputs = getRandomStringInputs(N); |
170 | std::vector<const char*> cinputs; |
171 | for (auto const& str : inputs) |
172 | cinputs.push_back(x: str.c_str()); |
173 | return cinputs; |
174 | } |
175 | |
176 | template <class T> |
177 | struct Generate { |
178 | // When the contents don't matter |
179 | static T arbitrary(); |
180 | |
181 | // Prefer a cheap-to-construct element if possible |
182 | static T cheap(); |
183 | |
184 | // Prefer an expensive-to-construct element if possible |
185 | static T expensive(); |
186 | }; |
187 | |
188 | template <class T> |
189 | requires std::integral<T> |
190 | struct Generate<T> { |
191 | static T arbitrary() { return 42; } |
192 | static T cheap() { return 42; } |
193 | static T expensive() { return 42; } |
194 | static T random() { return getRandomInteger<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max()); } |
195 | }; |
196 | |
197 | template <> |
198 | struct Generate<std::string> { |
199 | static std::string arbitrary() { return "hello world" ; } |
200 | static std::string cheap() { return "small" ; } |
201 | static std::string expensive() { return std::string(256, 'x'); } |
202 | static std::string random() { |
203 | auto length = getRandomInteger<std::size_t>(Min: 1, Max: 1024); |
204 | return getRandomString(Len: length); |
205 | } |
206 | }; |
207 | |
208 | template <class T> |
209 | T random_different_from(std::initializer_list<T> others) { |
210 | T value; |
211 | do { |
212 | value = Generate<T>::random(); |
213 | } while (std::find(others.begin(), others.end(), value) != others.end()); |
214 | return value; |
215 | } |
216 | |
217 | #endif // BENCHMARK_GENERATE_INPUT_H |
218 | |