MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
slice_algo.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
19#ifndef MTCORE_SLICE_ALGO_H
20#define MTCORE_SLICE_ALGO_H
21
22#include "optional.hpp"
23#include "slice.hpp"
24
29namespace mtcore::slices {
39 template<typename T>
40 bool starts_with(const Slice<T> &needle, const Slice<T> &haystack) {
41 if (needle.empty()) {
42 mtcore_warn_trace("Empty needle provided!");
43 return false;
44 }
45 if (needle.size() > haystack.size()) {
46 return false;
47 }
48 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
49 for (size_t i = 0; i < needle.size(); ++i) {
50 if (needle[i] != haystack[i]) {
51 return false;
52 }
53 }
54 return true;
55 }
56
57 template<typename T>
58 void shift(Slice<T> slice, size_t amt) {
59 for (size_t i = slice.size(); i > 0; --i) {
60 auto destIndex = i - 1;
61 if (destIndex < amt) {
62 break;
63 }
64 auto srcIndex = destIndex - amt;
65 slice[destIndex] = slice[srcIndex];
66 }
67 }
68
79 template<typename T>
80 bool starts_with(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
81 if (haystack.empty()) {
82 return false;
83 }
84 return haystack[0] == needle;
85 }
86
97 template<typename T>
98 bool contains(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
99 if (haystack.empty()) {
100 return false;
101 }
102 for (size_t i = 0; i < haystack.size(); ++i) {
103 if (needle == haystack[i]) {
104 return true;
105 }
106 }
107 return false;
108 }
109
119 template<typename T>
120 bool contains(const Slice<T> &needle, const Slice<T> &haystack) {
121 if (needle.empty()) {
122 mtcore_warn_trace("Empty needle provided!");
123 return false;
124 }
125 if (needle.size() > haystack.size()) {
126 return false;
127 }
128 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
129 for (size_t i = 0; i < haystack.size() - needle.size() + 1; ++i) {
130 if (needle[0] == haystack[i]) {
131 bool looking = true;
132 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
133 if (needle[ni] != haystack[i + ni]) {
134 looking = false;
135 }
136 }
137 if (looking) {
138 return true;
139 }
140 }
141 }
142 return false;
143 }
144
153 template<typename T>
154 mtcore::Optional<size_t> first_index_not_proceeded_by(const std::remove_const_t<T> &prefix,
155 const std::remove_const_t<T> &needle,
156 const Slice<T> &haystack) {
157 if (haystack.empty()) {
158 return nullopt;
159 }
160 bool skip = false;
161 for (size_t i = 0; i < haystack.size(); ++i) {
162 if (skip) {
163 skip = false;
164 continue;
165 }
166 if (haystack[i] == prefix) {
167 skip = true;
168 }
169 else if (needle == haystack[i]) {
170 return i;
171 }
172 }
173 return nullopt;
174 }
175
184 template<typename T>
185 mtcore::Optional<size_t> first_index_not_proceeded_by(const std::remove_const_t<T> &prefix, const Slice<T> &needle,
186 const Slice<T> &haystack) {
187 if (needle.empty()) {
188 mtcore_warn_trace("Empty needle provided!");
189 return nullopt;
190 }
191 if (needle.size() > haystack.size()) {
192 return nullopt;
193 }
194 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
195 bool skip = false;
196 for (size_t i = 0; i < haystack.size() - needle.size() + 1; ++i) {
197 if (skip) {
198 skip = false;
199 continue;
200 }
201 if (haystack[i] == prefix) {
202 skip = true;
203 }
204 else if (needle[0] == haystack[i]) {
205 bool looking = true;
206 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
207 if (needle[ni] != haystack[i + ni]) {
208 looking = false;
209 }
210 }
211 if (looking) {
212 return i;
213 }
214 }
215 }
216 return nullopt;
217 }
218
227 template<typename T>
228 mtcore::Optional<size_t> first_index(const Slice<T> &needle, const Slice<T> &haystack) {
229 if (needle.empty()) {
230 mtcore_warn_trace("Empty needle provided!");
231 return nullopt;
232 }
233 if (needle.size() > haystack.size()) {
234 return nullopt;
235 }
236 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
237 for (size_t i = 0; i < haystack.size() - needle.size() + 1; ++i) {
238 if (needle[0] == haystack[i]) {
239 bool looking = true;
240 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
241 if (needle[ni] != haystack[i + ni]) {
242 looking = false;
243 }
244 }
245 if (looking) {
246 return i;
247 }
248 }
249 }
250 return nullopt;
251 }
252
261 template<typename T>
262 mtcore::Optional<size_t> first_index_not(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
263 if (haystack.empty()) {
264 return nullopt;
265 }
266
267 size_t i = 0;
268 for (; i < haystack.size() && needle == haystack[i]; ++i) {}
269
270 if (i >= haystack.size()) {
271 return nullopt;
272 }
273 return i;
274 }
275
284 template<typename T>
285 mtcore::Optional<size_t> first_index(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
286 if (haystack.empty()) {
287 return nullopt;
288 }
289 for (size_t i = 0; i < haystack.size(); ++i) {
290 if (needle == haystack[i]) {
291 return i;
292 }
293 }
294 return nullopt;
295 }
296
305 template<typename T>
306 mtcore::Optional<size_t> last_index(const Slice<T> &needle, const Slice<T> &haystack) {
307 if (needle.empty()) {
308 mtcore_warn_trace("Empty needle provided!");
309 return nullopt;
310 }
311 if (needle.size() > haystack.size()) {
312 return nullopt;
313 }
314 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
315 for (size_t indx = haystack.size() - needle.size() + 1; indx > 0; --indx) {
316 const auto i = indx - 1;
317 if (needle[0] == haystack[i]) {
318 bool looking = true;
319 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
320 if (needle[ni] != haystack[i + ni]) {
321 looking = false;
322 }
323 }
324 if (looking) {
325 return i;
326 }
327 }
328 }
329 return nullopt;
330 }
331
340 template<typename T>
341 mtcore::Optional<size_t> last_index(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
342 if (haystack.empty()) {
343 return nullopt;
344 }
345 for (size_t indx = haystack.size(); indx > 0; --indx) {
346 const auto i = indx - 1;
347 if (needle == haystack[i]) {
348 return i;
349 }
350 }
351 return nullopt;
352 }
353
354 template<typename T, typename N>
358 size_t cur = 0;
359
361 if (cur >= haystack.size()) {
362 return nullopt;
363 }
364
365 auto nxt = haystack.sub(cur);
366 const auto opt = slices::first_index(needle, nxt);
367 if (!opt.has_value()) {
368 return nullopt;
369 }
370
371 mtdefer { cur += opt.value() + 1; };
372 return cur + opt.value();
373 }
374 };
375
384 template<typename T>
385 SearchIndexes<T, Slice<T>> indexes_of(const Slice<T> &needle, const Slice<T> &haystack) {
386 return {needle, haystack};
387 }
388
397 template<typename T>
398 SearchIndexes<T, std::remove_const_t<T>> indexes_of(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
399 return {needle, haystack};
400 }
401
402 template<typename T, typename N>
403 struct SplitIter;
404
405 template<typename T>
406 struct SplitIter<T, Slice<T>> {
409 bool emittedLast = true;
410
412 if (haystack.empty()) {
413 if (emittedLast) {
414 return nullopt;
415 }
416 emittedLast = true;
417 return haystack;
418 }
419
420 auto nxt = first_index(needle, haystack);
421 if (!nxt.has_value()) {
422 emittedLast = true;
423 auto res = haystack;
424 haystack = haystack.sub(haystack.size());
425 return res;
426 }
427
428 emittedLast = false;
429 auto res = haystack.sub(0, nxt.value());
430 haystack = haystack.sub(nxt.value() + needle.size());
431 return res;
432 }
433 };
434
435 template<typename T, typename N>
436 struct SplitIter {
439 bool emittedLast = true;
440
442 if (haystack.empty()) {
443 if (emittedLast) {
444 return nullopt;
445 }
446 emittedLast = true;
447 return haystack;
448 }
449
450 auto nxt = first_index(needle, haystack);
451 if (!nxt.has_value()) {
452 emittedLast = true;
453 auto res = haystack;
454 haystack = haystack.sub(haystack.size());
455 return res;
456 }
457
458 emittedLast = false;
459 auto res = haystack.sub(0, nxt.value());
460 haystack = haystack.sub(nxt.value() + 1);
461 return res;
462 }
463 };
464
473 template<typename T>
474 SplitIter<T, Slice<T>> split(const Slice<T> &needle, const Slice<T> &haystack) {
475 return {needle, haystack};
476 }
477
486 template<typename T>
487 SplitIter<T, std::remove_const_t<T>> split(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
488 return {needle, haystack};
489 }
490} // namespace mtcore::slices
491
492#endif // MTCORE_SLICE_ALGO_H
#define mtcore_warn_trace(...)
Prints a warning message in debug builds Does nothing in release builds`.
SplitIter< T, Slice< T > > split(const Slice< T > &needle, const Slice< T > &haystack)
Splits a slice into smaller sub slices.
SearchIndexes< T, Slice< T > > indexes_of(const Slice< T > &needle, const Slice< T > &haystack)
Returns an iterator of all indexes of occurrences of a needle in a haystack If the needle isn't prese...
bool starts_with(const Slice< T > &needle, const Slice< T > &haystack)
Checks whether a slice (the haystack) starts with elements in another slice in the same order (the ne...
mtcore::Optional< size_t > last_index(const Slice< T > &needle, const Slice< T > &haystack)
Gets the last index that a needle appears in the haystack, or nullopt if the needle does not appear -...
constexpr auto nullopt
Placeholder value for an empty Optional.
Definition optional.hpp:409
mtcore::Optional< size_t > first_index_not_proceeded_by(const std::remove_const_t< T > &prefix, const std::remove_const_t< T > &needle, const Slice< T > &haystack)
Gets the first index that a needle appears in the haystack, or nullopt if the needle does not appear ...
mtcore::Optional< size_t > first_index(const Slice< T > &needle, const Slice< T > &haystack)
Gets the first index that a needle appears in the haystack, or nullopt if the needle does not appear ...
mtcore::Optional< size_t > first_index_not(const std::remove_const_t< T > &needle, const Slice< T > &haystack)
Gets the first index that a needle appears in the haystack, or nullopt if the needle does not appear ...
bool contains(const std::remove_const_t< T > &needle, const Slice< T > &haystack)
Checks whether a slice (the haystack) contains an element (the needle) Uses the equality operator of ...
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
#define mtdefer
Defer statement that will mtdefer execution until the scope is left, at which point the code will run...
Additional algorithms that can be performed on slices, such as comparisons, searching,...
void shift(Slice< T > slice, size_t amt)
Represents a value that may or may not exist (an "Optional" value) Similar concept to std::optional,...
Definition optional.hpp:235
A Slice which is just a pointer + length Accessing elements through the array operator will do bounds...
constexpr size_t size() const noexcept
Gets the size of a Slice.
constexpr bool empty() const noexcept
Checks if a Slice is empty.
Optional< size_t > next()
Optional< Slice< T > > next()