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 "pair.hpp"
24#include "slice.hpp"
25
30namespace mtcore::slices {
40 template<typename T>
41 bool starts_with(const Slice<T> &needle, const Slice<T> &haystack) {
42 if (needle.empty()) {
43 mtcore_warn_trace("Empty needle provided!");
44 return false;
45 }
46 if (needle.size() > haystack.size()) {
47 return false;
48 }
49 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
50 for (size_t i = 0; i < needle.size(); ++i) {
51 if (needle[i] != haystack[i]) {
52 return false;
53 }
54 }
55 return true;
56 }
57
65 template<typename T>
66 void shift_right(Slice<T> slice, size_t amt) {
67 for (size_t i = 0; i < slice.size() - amt; ++i) {
68 auto destIndex = i + amt;
69 if (destIndex < amt) {
70 break;
71 }
72 auto srcIndex = destIndex - amt;
73 slice[destIndex] = slice[srcIndex];
74 }
75 }
76
84 template<typename T>
85 void shift_left(Slice<T> slice, size_t amt) {
86 for (size_t i = slice.size(); i > 0; --i) {
87 auto destIndex = i - amt;
88 if (destIndex < amt) {
89 break;
90 }
91 auto srcIndex = destIndex - amt;
92 slice[destIndex] = slice[srcIndex];
93 }
94 }
95
106 template<typename T>
107 bool starts_with(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
108 if (haystack.empty()) {
109 return false;
110 }
111 return haystack[0] == needle;
112 }
113
124 template<typename T>
125 bool contains(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
126 if (haystack.empty()) {
127 return false;
128 }
129 for (size_t i = 0; i < haystack.size(); ++i) {
130 if (needle == haystack[i]) {
131 return true;
132 }
133 }
134 return false;
135 }
136
146 template<typename T>
147 bool contains(const Slice<T> &needle, const Slice<T> &haystack) {
148 if (needle.empty()) {
149 mtcore_warn_trace("Empty needle provided!");
150 return false;
151 }
152 if (needle.size() > haystack.size()) {
153 return false;
154 }
155 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
156 for (size_t i = 0; i < haystack.size() - needle.size() + 1; ++i) {
157 if (needle[0] == haystack[i]) {
158 bool looking = true;
159 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
160 if (needle[ni] != haystack[i + ni]) {
161 looking = false;
162 }
163 }
164 if (looking) {
165 return true;
166 }
167 }
168 }
169 return false;
170 }
171
180 template<typename T>
181 mtcore::Optional<size_t> first_index_not_proceeded_by(const std::remove_const_t<T> &prefix,
182 const std::remove_const_t<T> &needle,
183 const Slice<T> &haystack) {
184 if (haystack.empty()) {
185 return nullopt;
186 }
187 bool skip = false;
188 for (size_t i = 0; i < haystack.size(); ++i) {
189 if (skip) {
190 skip = false;
191 continue;
192 }
193 if (haystack[i] == prefix) {
194 skip = true;
195 }
196 else if (needle == haystack[i]) {
197 return i;
198 }
199 }
200 return nullopt;
201 }
202
211 template<typename T>
212 mtcore::Optional<size_t> first_index_not_proceeded_by(const std::remove_const_t<T> &prefix, const Slice<T> &needle,
213 const Slice<T> &haystack) {
214 if (needle.empty()) {
215 mtcore_warn_trace("Empty needle provided!");
216 return nullopt;
217 }
218 if (needle.size() > haystack.size()) {
219 return nullopt;
220 }
221 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
222 bool skip = false;
223 for (size_t i = 0; i < haystack.size() - needle.size() + 1; ++i) {
224 if (skip) {
225 skip = false;
226 continue;
227 }
228 if (haystack[i] == prefix) {
229 skip = true;
230 }
231 else if (needle[0] == haystack[i]) {
232 bool looking = true;
233 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
234 if (needle[ni] != haystack[i + ni]) {
235 looking = false;
236 }
237 }
238 if (looking) {
239 return i;
240 }
241 }
242 }
243 return nullopt;
244 }
245
254 template<typename T>
255 mtcore::Optional<size_t> first_index(const Slice<T> &needle, const Slice<T> &haystack) {
256 if (needle.empty()) {
257 mtcore_warn_trace("Empty needle provided!");
258 return nullopt;
259 }
260 if (needle.size() > haystack.size()) {
261 return nullopt;
262 }
263 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
264 for (size_t i = 0; i < haystack.size() - needle.size() + 1; ++i) {
265 if (needle[0] == haystack[i]) {
266 bool looking = true;
267 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
268 if (needle[ni] != haystack[i + ni]) {
269 looking = false;
270 }
271 }
272 if (looking) {
273 return i;
274 }
275 }
276 }
277 return nullopt;
278 }
279
288 template<typename T>
290 if (needles.empty()) {
291 mtcore_warn_trace("Empty needle provided!");
292 return nullopt;
293 }
294 for (size_t i = 0; i < haystack.size(); ++i) {
295 if (contains(haystack[i], needles)) {
296 return i;
297 }
298 }
299 return nullopt;
300 }
301
310 template<typename T>
311 mtcore::Optional<size_t> first_index_not(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
312 if (haystack.empty()) {
313 return nullopt;
314 }
315
316 size_t i = 0;
317 for (; i < haystack.size() && needle == haystack[i]; ++i) {}
318
319 if (i >= haystack.size()) {
320 return nullopt;
321 }
322 return i;
323 }
324
333 template<typename T>
334 mtcore::Optional<size_t> first_index(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
335 if (haystack.empty()) {
336 return nullopt;
337 }
338 for (size_t i = 0; i < haystack.size(); ++i) {
339 if (needle == haystack[i]) {
340 return i;
341 }
342 }
343 return nullopt;
344 }
345
354 template<typename T>
355 mtcore::Optional<size_t> last_index(const Slice<T> &needle, const Slice<T> &haystack) {
356 if (needle.empty()) {
357 mtcore_warn_trace("Empty needle provided!");
358 return nullopt;
359 }
360 if (needle.size() > haystack.size()) {
361 return nullopt;
362 }
363 ensure(needle.size() <= haystack.size(), "BAD SIZE COMP");
364 for (size_t indx = haystack.size() - needle.size() + 1; indx > 0; --indx) {
365 const auto i = indx - 1;
366 if (needle[0] == haystack[i]) {
367 bool looking = true;
368 for (size_t ni = 1; looking && ni < needle.size(); ++ni) {
369 if (needle[ni] != haystack[i + ni]) {
370 looking = false;
371 }
372 }
373 if (looking) {
374 return i;
375 }
376 }
377 }
378 return nullopt;
379 }
380
389 template<typename T>
390 mtcore::Optional<size_t> last_index(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
391 if (haystack.empty()) {
392 return nullopt;
393 }
394 for (size_t indx = haystack.size(); indx > 0; --indx) {
395 const auto i = indx - 1;
396 if (needle == haystack[i]) {
397 return i;
398 }
399 }
400 return nullopt;
401 }
402
403 template<typename T, typename N>
407 size_t cur = 0;
408
410 if (cur >= haystack.size()) {
411 return nullopt;
412 }
413
414 auto nxt = haystack.sub(cur);
415 const auto opt = slices::first_index(needle, nxt);
416 if (!opt.has_value()) {
417 return nullopt;
418 }
419
420 mtdefer { cur += opt.value() + 1; };
421 return cur + opt.value();
422 }
423 };
424
433 template<typename T>
434 SearchIndexes<T, Slice<T>> indexes_of(const Slice<T> &needle, const Slice<T> &haystack) {
435 return {needle, haystack};
436 }
437
446 template<typename T>
447 SearchIndexes<T, std::remove_const_t<T>> indexes_of(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
448 return {needle, haystack};
449 }
450
456 template<typename T, typename N>
457 struct SplitIter;
458
459 template<typename T>
460 struct SplitIter<T, Slice<T>> {
463 bool emittedLast = true;
464
466 if (haystack.empty()) {
467 if (emittedLast) {
468 return nullopt;
469 }
470 emittedLast = true;
471 return haystack;
472 }
473
474 auto nxt = first_index(needle, haystack);
475 if (!nxt.has_value()) {
476 emittedLast = true;
477 auto res = haystack;
478 haystack = haystack.sub(haystack.size());
479 return res;
480 }
481
482 emittedLast = false;
483 auto res = haystack.sub(0, nxt.value());
484 haystack = haystack.sub(nxt.value() + needle.size());
485 return res;
486 }
487 };
488
489 template<typename T, typename N>
490 struct SplitIter {
493 bool emittedLast = true;
494
496 if (haystack.empty()) {
497 if (emittedLast) {
498 return nullopt;
499 }
500 emittedLast = true;
501 return haystack;
502 }
503
504 auto nxt = first_index(needle, haystack);
505 if (!nxt.has_value()) {
506 emittedLast = true;
507 auto res = haystack;
508 haystack = haystack.sub(haystack.size());
509 return res;
510 }
511
512 emittedLast = false;
513 auto res = haystack.sub(0, nxt.value());
514 haystack = haystack.sub(nxt.value() + 1);
515 return res;
516 }
517 };
518
527 template<typename T>
528 SplitIter<T, Slice<T>> split(const Slice<T> &needle, const Slice<T> &haystack) {
529 return {needle, haystack};
530 }
531
540 template<typename T>
541 SplitIter<T, std::remove_const_t<T>> split(const std::remove_const_t<T> &needle, const Slice<T> &haystack) {
542 return {needle, haystack};
543 }
544
545 template<typename T>
550 bool emittedLast = true;
551
553 if (haystack.empty()) {
554 mtdefer { emittedLast = true; };
555 if (emittedLast) {
556 return nullopt;
557 }
559 }
560
562 if (!nxt.has_value()) {
563 mtdefer {
565 haystack = haystack.sub(haystack.size());
566 emittedLast = true;
567 };
569 }
570
571 mtdefer {
572 foundNeedle = haystack[nxt.value()];
573 haystack = haystack.sub(nxt.value() + 1);
574 emittedLast = false;
575 };
576
577 return make_pair(haystack.sub(0, nxt.value()), foundNeedle);
578 }
579 };
580
589 template<typename T>
590 SplitOneOfIter<T> split_one_of(const Slice<std::add_const_t<T>> &needles, const Slice<T> &haystack) {
591 return {needles, haystack};
592 }
593} // namespace mtcore::slices
594
595#endif // MTCORE_SLICE_ALGO_H
#define mtcore_warn_trace(...)
Prints a warning message in debug builds Does nothing in release builds`.
SplitOneOfIter< T > split_one_of(const Slice< std::add_const_t< T > > &needles, const Slice< T > &haystack)
Splits a slice into smaller sub slices.
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 ...
Pair< T1, T2 > make_pair(T1 first, T2 second)
Helper to make a pair with type inference.
Definition pair.hpp:45
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 ...
mtcore::Optional< size_t > first_index_one_of(const Slice< T > &needles, const Slice< T > &haystack)
Gets the first index that one of the provided needles appears in the haystack, or nullopt if the need...
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_left(Slice< T > slice, size_t amt)
Shifts elements to the left by a certain number of places Does not loop around.
void shift_right(Slice< T > slice, size_t amt)
Shifts elements to the right by a certain number of places Does not loop around.
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()
Splits a slice and iterates over the split portions.
Optional< Slice< T > > next()
Slice< std::add_const_t< T > > needles
Optional< std::remove_const_t< T > > foundNeedle
Optional< Pair< Slice< T >, Optional< std::remove_const_t< T > > > > next()