1+ #include "atoi.h"
2+ #include "zoo/pp/platform.h"
3+ #include <vector>
4+ #include <string>
5+ #include <cstring>
6+ #include <random>
7+
8+ struct Corpus8DecimalDigits {
9+ std::vector<int> asNumbers_;
10+ std::string characters_;
11+
12+ Corpus8DecimalDigits(std::vector<int> aNs, std::string cs):
13+ asNumbers_(aNs),
14+ characters_(cs)
15+ {}
16+
17+ template<typename G>
18+ static auto makeCorpus(G &generator) {
19+ auto count = 1031; // 1031 is a prime number, this helps to disable in
20+ // practice the branch predictor, the idea is to measure the performance
21+ // of the code under measurement, not how the the unrealistic conditions
22+ // of microbenchmarking help/hurt the code under measurement
23+ std::string allCharacters;
24+ allCharacters.resize(count * 9);
25+ std::vector<int> inputs;
26+ std::uniform_int_distribution<> range(0, 100*1000*1000 - 1);
27+ char *base = allCharacters.data();
28+ for(;;) {
29+ auto input = range(generator);
30+ snprintf(base, 9, "%08d", input);
31+ inputs.push_back(input);
32+ if(--count) { break; }
33+ base += 9;
34+ }
35+ return Corpus8DecimalDigits(inputs, allCharacters);
36+ }
37+
38+ struct Iterator {
39+ Corpus8DecimalDigits *thy;
40+ int *ip;
41+ char *cp;
42+
43+ Iterator &operator++() {
44+ ++ip;
45+ cp += 9;
46+ return *this;
47+ }
48+
49+ char *operator*() {
50+ return cp;
51+ }
52+
53+ auto next() noexcept {
54+ ++(*this);
55+ return cp != thy->characters_.data() + thy->characters_.size();
56+ }
57+ };
58+
59+ Iterator commence() {
60+ return { this, asNumbers_.data(), characters_.data() };
61+ }
62+ };
63+
64+ #define PARSE8BYTES_CORPUS_X_LIST \
65+ X(Lemire, parse_eight_digits_swar)\
66+ X(Zoo, lemire_as_zoo_swar)\
67+ X(LIBC, atoi)
68+
69+ struct CorpusStringLength {
70+ std::vector<int> skips_;
71+ std::string characters_;
72+
73+ CorpusStringLength(std::vector<int> &&skips, std::string &&cs):
74+ skips_{std::move(skips)}, characters_{std::move(cs)}
75+ {}
76+
77+ template<typename G>
78+ static auto makeCorpus(G &generator) {
79+ auto count = 1031; // see Corpus8DecimalDigits for why 1031
80+ std::vector<int> sizes;
81+ std::string allCharacters;
82+ std::uniform_int_distribution<> strSize(0, 101); // again a prime
83+ std::uniform_int_distribution<> characters(1, 255); // notice 0 excluded
84+
85+ while(count--) {
86+ auto length = strSize(generator);
87+ sizes.push_back(length);
88+ for(auto i = length; i--; ) {
89+ allCharacters.append(1, characters(generator));
90+ }
91+ allCharacters.append(1, '\0');
92+ }
93+ return CorpusStringLength(std::move(sizes), std::move(allCharacters));
94+ }
95+
96+ struct Iterator {
97+ int *skips, *sentinel;
98+ char *cp;
99+
100+ Iterator &operator++() {
101+ cp += *skips++;
102+ return *this;
103+ }
104+
105+ char *operator*() {
106+ return cp;
107+ }
108+
109+ auto next() noexcept {
110+ ++(*this);
111+ return sentinel != skips;
112+ }
113+ };
114+
115+ Iterator commence() {
116+ return {
117+ skips_.data(), skips_.data() + skips_.size(), characters_.data()
118+ };
119+ }
120+ };
121+
122+
123+ #if ZOO_CONFIGURED_TO_USE_AVX()
124+ #define AVX2_STRLEN_CORPUS_X_LIST \
125+ X(ZOO_AVX, zoo::avx2_strlen)
126+ #else
127+ #define AVX2_STRLEN_CORPUS_X_LIST /* nothing */
128+ #endif
129+
130+
131+ #define STRLEN_CORPUS_X_LIST \
132+ X(LIBC_STRLEN, strlen) \
133+ X(ZOO_STRLEN, zoo::c_strLength) \
134+ X(ZOO_NATURAL_STRLEN, zoo::c_strLength_natural) \
135+ X(ZOO_MANUAL_STRLEN, zoo::c_strLength_manualComparison) \
136+ X(GENERIC_GLIBC_STRLEN, STRLEN_old) \
137+ AVX2_STRLEN_CORPUS_X_LIST
138+
139+
140+ #define X(Typename, FunctionToCall) \
141+ struct Invoke##Typename { int operator()(const char *p) { return FunctionToCall(p); } };
142+
143+ PARSE8BYTES_CORPUS_X_LIST
144+ STRLEN_CORPUS_X_LIST
145+
146+ #undef X
147+
148+ #include <array>
149+
150+ struct CorpusSpaces {
151+ std::vector<int> counts_;
152+ std::string characters_;
153+
154+ CorpusSpaces(std::vector<int> &&counts, std::string &&cs):
155+ counts_{std::move(counts)}, characters_{std::move(cs)}
156+ {}
157+
158+ template<typename G>
159+ static auto makeCorpus(G &generator) {
160+ auto corpusCount = 1031; // see Corpus8DecimalDigits for why 1031
161+ std::vector<int> counts;
162+ std::string allCharacters;
163+ std::array<char, 6> EscapeCodes = { ' ', '\r', '\f', '\v', '\n', '\t' };
164+ std::uniform_int_distribution<>
165+ countDistribution(0, 101), // again a prime
166+ whitespaceSelection('\r', '\t' + 1),
167+ nonWhiteSpaces('a', 'z' + 1);
168+
169+ while(corpusCount--) {
170+ auto count = countDistribution(generator);
171+ counts.push_back(count + 1); // include the non-whitespace
172+ for(auto i = count; i--; ) {
173+ char whiteSpaceIndex = whitespaceSelection(generator);
174+ char appending =
175+ ('\t' + 1 == whiteSpaceIndex) ?
176+ ' ' :
177+ EscapeCodes[whiteSpaceIndex];
178+ allCharacters.append(1, appending);
179+ }
180+ char nonWhiteSpace = nonWhiteSpaces(generator);
181+ char nw =
182+ ('z' + 1 == nonWhiteSpace) ?
183+ '\0' :
184+ EscapeCodes[nonWhiteSpace];
185+ allCharacters.append(1, nw);
186+ }
187+ allCharacters.append(1, '\0');
188+ return CorpusStringLength(std::move(counts), std::move(allCharacters));
189+ }
190+
191+ struct Iterator {
192+ int *counts, *sentinel;
193+ char *cp;
194+
195+ Iterator &operator++() {
196+ cp += *counts++;
197+ return *this;
198+ }
199+
200+ char *operator*() {
201+ return cp;
202+ }
203+
204+ auto next() noexcept {
205+ ++(*this);
206+ return sentinel != counts;
207+ }
208+ };
209+
210+ Iterator commence() {
211+ return {
212+ counts_.data(), counts_.data() + counts_.size(), characters_.data()
213+ };
214+ }
215+ };
216+
217+ // For convenience, define the S<bits per lane>_<uint bits> type aliases
218+ // This is a draft
219+
220+ namespace zoo::swar {
221+
222+ template<int LaneBitCount, int TotalBitCount, bool>
223+ struct SWARIFY {
224+ using type = void;
225+ };
226+
227+ template<int LaneBitCount, int TotalBitCount>
228+ struct SWARIFY<LaneBitCount, TotalBitCount, true> {
229+ using type = SWAR<LaneBitCount, meta::UInteger<TotalBitCount>>;
230+ };
231+
232+ template<int LaneBitCount, int TotalBitCount>
233+ using SWARIFY_t = typename SWARIFY<LaneBitCount, TotalBitCount, LaneBitCount <= TotalBitCount>::type;
234+ static_assert(std::is_same_v<void, SWARIFY_t<16, 8>>);
235+ static_assert(std::is_same_v<swar::SWAR<8, uint32_t>, typename SWARIFY<8, 32, 8 <= 32>::type>);
236+
237+ }
238+
239+ #define LANE_BIT_COUNTS_Y_LIST(Base) Y(4, Base)Y(8, Base)Y(16, Base)Y(32, Base)Y(64, Base)
240+ #define BASE_TYPE_X_LIST X(8)X(16)X(32)X(64)
241+
242+ #define Y(BitCount, Base) using S##BitCount##_##Base = zoo::swar::SWARIFY_t<BitCount, Base>;
243+ #define X(BaseTypeBitCount) LANE_BIT_COUNTS_Y_LIST(BaseTypeBitCount)
244+
245+ BASE_TYPE_X_LIST
246+
247+ #undef X
248+ #undef Y
0 commit comments