Steppable 0.0.1
A CAS project written from scratch in C++
Loading...
Searching...
No Matches
util.hpp
1/**************************************************************************************************
2 * Copyright (c) 2023-2025 NWSOFT *
3 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy *
5 * of this software and associated documentation files (the "Software"), to deal *
6 * in the Software without restriction, including without limitation the rights *
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
8 * copies of the Software, and to permit persons to whom the Software is *
9 * furnished to do so, subject to the following conditions: *
10 * *
11 * The above copyright notice and this permission notice shall be included in all *
12 * copies or substantial portions of the Software. *
13 * *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
20 * SOFTWARE. *
21 **************************************************************************************************/
22
34
35#pragma once
36
37#ifdef WINDOWS
38 #include <windows.h>
39#endif
40
41#include "colors.hpp"
42#include "output.hpp"
43#include "platform.hpp"
44#include "types/concepts.hpp"
45
46#include <algorithm>
47#include <array>
48#include <charconv>
49#include <chrono>
50#include <clocale>
51#include <cstddef>
52#include <iomanip>
53#include <iostream>
54#include <sstream>
55#include <string>
56#include <vector>
57
58using namespace std::literals;
59
60#ifndef TIC
65 #define TIC(...) \
66 { \
67 const char* nameSection = #__VA_ARGS__; \
68 std::cout << colors::brightBlue << std::setw(80) << std::setfill('-') << reset << '\n'; \
69 std::cout << colors::brightBlue << "[Profiling: " << nameSection << ']' << reset << '\n'; \
70 auto start = std::chrono::high_resolution_clock::now();
71#endif
72
73#ifndef TOC
75 #define TOC() \
76 auto duration = \
77 std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - start) \
78 .count(); \
79 std::cout << colors::brightBlue << '[' << nameSection << " took " << duration << "(microseconds) to execute]" \
80 << reset << '\n'; \
81 std::cout << colors::brightBlue << std::setw(80) << std::setfill('-'); \
82 std::cout << reset << '\n'; \
83 }
84#endif
85
86#ifndef MAX_DECIMALS
88 #define MAX_DECIMALS 50
89#endif
90
92{
93#ifndef MS_STDLIB_BUGS
94 #if (_MSC_VER || __MINGW32__ || __MSVCRT__)
95 #define MS_STDLIB_BUGS 1
96 #else
97 #define MS_STDLIB_BUGS 0 // NOLINT(cppcoreguidelines-macro-usage)
98 #endif
99#endif
100
101#if MS_STDLIB_BUGS
102 #include <fcntl.h>
103 #include <io.h>
104#endif
105
106#ifdef WINDOWS
107 #include <fcntl.h>
108
114 inline DWORD enableVtMode()
115 {
116 // Set output mode to handle virtual terminal sequences
117 const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
118 if (hOut == INVALID_HANDLE_VALUE)
119 return -1;
120
121 DWORD dwMode = 0;
122 if (!GetConsoleMode(hOut, &dwMode))
123 return -1;
124 const DWORD dwModeOrig = dwMode;
125
126 dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
127 if (!SetConsoleMode(hOut, dwMode))
128 return -1;
129 return dwModeOrig;
130 }
131
138 inline bool restoreVtMode(const DWORD dwModeOrig)
139 {
140 const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
141 if (hOut == INVALID_HANDLE_VALUE)
142 return false;
143
144 if (!SetConsoleMode(hOut, dwModeOrig))
145 return false;
146 return true;
147 }
148
156 class Utf8CodePage
157 {
158 public:
165 Utf8CodePage() : oldCodePage(GetConsoleOutputCP())
166 {
167 SetConsoleOutputCP(CP_UTF8);
168 dwModeOrig = enableVtMode();
169 }
170
177 {
178 SetConsoleOutputCP(oldCodePage);
179 restoreVtMode(dwModeOrig);
180 }
181
182 private:
183 UINT oldCodePage;
184 DWORD dwModeOrig;
185 };
186#else
187
196 {
197 public:
199 };
200#endif
201
210 template<typename NumberT>
211 void checkDecimalArg(const NumberT* decimal)
212 {
213 if (*decimal > MAX_DECIMALS)
214 {
215 output::error("checkDecimalArg"s,
216 "The number of decimals ({0}) is more than the accepted {1} digits."s,
217 { std::to_string(*decimal), std::to_string(MAX_DECIMALS) });
219 }
220 }
221
226 template<size_t N>
228 {
233 constexpr StringLiteral(const char (&str)[N]) // NOLINT(*-pro-type-member-init, *-explicit-constructor)
234 { // NOLINT(*-avoid-c-arrays)
235 std::copy_n(str, N, value);
236 }
237
241 char value[N]; // NOLINT(*-avoid-c-arrays)
242 };
243} // namespace steppable::__internals::utils
244
250{
259 {
260 std::array<std::string, 4> splitNumberArray;
261 bool aIsNegative = false, bIsNegative = false;
262 };
263
273 std::string simplifyZeroPolarity(const std::string& string);
274
280 std::string simplifyPolarity(const std::string& _string);
281
288 std::string standardizeNumber(const std::string& _number);
289
299 constexpr bool isZeroString(const std::string& string)
300 {
301 if (string.empty())
302 return true;
303 return std::ranges::all_of(string, [](const char c) { return c == '0' or c == '.' or c == '-'; });
304 }
305
312 bool isNumber(const std::string& s);
313
326 SplitNumberResult splitNumber(const std::string& a,
327 const std::string& b,
328 bool padInteger = true,
329 bool padDecimal = true,
330 bool properlyFormat = true,
331 bool preserveNegative = false);
332
339 auto replaceLeadingZeros(const std::vector<int>& vector) -> std::decay_t<decltype(vector)>;
340
347 auto removeLeadingZeros(const std::vector<int>& vector) -> std::decay_t<decltype(vector)>;
348
355 auto removeLeadingZeros(const std::string& string) -> std::decay_t<decltype(string)>;
356
363 auto removeTrailingZeros(const std::vector<int>& _vector) -> std::decay_t<decltype(_vector)>;
364
371 auto removeTrailingZeros(const std::string& numStr) -> std::decay_t<decltype(numStr)>;
372
379 long long determineScale(const std::string& number);
380
387 bool isInteger(const std::string& number);
388
395 bool isDecimal(const std::string& number);
396
403 bool isPowerOfTen(const std::string& number);
404
411 bool isOdd(const std::string& number);
412
419 bool isEven(const std::string& number);
420} // namespace steppable::__internals::numUtils
421
427{
435 template<typename CharT>
436 auto split(std::basic_string<CharT> s, const CharT separator)
437 {
438 std::vector<decltype(s)> substrings;
439 std::basic_stringstream<CharT> ss(s);
440 decltype(s) token;
441
442 while (getline(ss, token, separator))
443 substrings.push_back(token);
444
445 return substrings;
446 }
447
455 template<typename CharT>
456 auto split(std::basic_string_view<CharT> s, const CharT separator)
457 {
458 std::vector<decltype(s)> result;
459 auto left = s.begin();
460 for (auto it = left; it != s.end(); ++it)
461 {
462 if (*it == separator)
463 {
464 result.emplace_back(&*left, it - left);
465 left = it + 1;
466 }
467 }
468 if (left != s.end())
469 result.emplace_back(&*left, s.end() - left);
470 return result;
471 }
472
487 template<typename CharT>
488 auto rReplace(const std::basic_string<CharT> s, const CharT t, const CharT replacement = '\0')
489 {
490 std::basic_string<CharT> out = s;
491 typename std::basic_string<CharT>::size_type count = 0;
492 while (out.back() == t)
493 {
494 out.pop_back();
495 ++count;
496 }
497 if (replacement != '\0')
498 out += std::basic_string<CharT>(count, replacement);
499 return out;
500 }
501
513 template<typename CharT>
514 auto lReplace(const std::basic_string<CharT> s, const CharT t, const CharT replacement = '\0')
515 {
516 std::basic_string<CharT> out = s;
517 typename std::basic_string<CharT>::size_type count = 0;
518 while (out[0] == t)
519 {
520 out.erase(out.begin());
521 ++count;
522 }
523 if (replacement != '\0')
524 out = std::basic_string<CharT>(count, replacement) + out;
525 return out;
526 }
527
542 template<typename CharT>
543 auto bothEndsReplace(const std::basic_string<CharT> s, const CharT t, const CharT replacement = '\0')
544 {
545 return lReplace(rReplace(s, t, replacement), t, replacement);
546 }
547
556 template<typename T>
557 auto join(const std::vector<T>& vector, const std::string& delimiter)
558 {
559 std::stringstream result;
560 for (const auto& item : vector)
561 result << item << delimiter;
562 return result.str();
563 }
564
571 std::string makeWider(const std::string& orig);
572
579 [[maybe_unused]] int utf8ToUnicode(const std::string& utf8_code);
580
590 std::string unicodeToUtf8(int unicode);
591
597 std::vector<std::string> duplicates(const std::vector<std::string>& vector);
598
599 template<typename ValueType>
600 std::string vectorToString(const std::vector<ValueType>& vector)
601 {
602 std::ostringstream out;
603 out << "[";
604 for (size_t i = 0; i < vector.size(); ++i)
605 {
606 out << vector[i];
607 if (i != vector.size() - 1)
608 out << ", ";
609 }
610 return out.str();
611 }
612
613 template<concepts::Numeric T>
614 T toNumeric(const std::string& s)
615 {
616 auto value = T{};
617
618 if (auto result = std::from_chars(s.data(), s.data() + s.size(), value); result.ec != std::errc{})
619 {
620 output::error("toNumeric"s, "Invalid argument"s);
622 }
623 return value;
624 }
625} // namespace steppable::__internals::stringUtils
A class that sets the console output code page to UTF-8 and enables VT mode.
Definition util.hpp:196
Utilities to operate numbers.
Definition factors.cpp:35
bool isEven(const std::string &number)
Checks if a number is even.
Definition util.cpp:309
auto removeLeadingZeros(const std::vector< int > &vector) -> std::decay_t< decltype(vector)>
Definition util.cpp:196
std::string simplifyPolarity(const std::string &_string)
Simplifies a string with non-standard polarity (e.g., –1, —1, etc.).
Definition util.cpp:79
std::string simplifyZeroPolarity(const std::string &string)
Simplifies a string that represents a number with non-standard polarity.
Definition util.cpp:69
auto removeTrailingZeros(const std::vector< int > &_vector) -> std::decay_t< decltype(_vector)>
Definition util.cpp:225
constexpr bool isZeroString(const std::string &string)
Checks if a given string is a zero string.
Definition util.hpp:299
bool isOdd(const std::string &number)
Checks if a number is odd.
Definition util.cpp:298
bool isPowerOfTen(const std::string &_number)
Determines whether the number is a power of 10.
Definition util.cpp:278
long long determineScale(const std::string &number)
Determines the scale of a number, i.e., the power of 10 when it is expressed in scientific notation.
Definition util.cpp:249
bool isInteger(const std::string &number)
Determines whether the number is an integer or not.
Definition util.cpp:269
bool isNumber(const std::string &s)
Checks if a given string is a valid number.
Definition util.cpp:42
auto replaceLeadingZeros(const std::vector< int > &vector) -> std::decay_t< decltype(vector)>
Definition util.cpp:182
std::string standardizeNumber(const std::string &_number)
Standardizes a number string.
Definition util.cpp:91
SplitNumberResult splitNumber(const std::string &_a, const std::string &_b, const bool padInteger, const bool padDecimal, bool properlyFormat, bool preserveNegative)
Definition util.cpp:114
bool isDecimal(const std::string &number)
Determines whether the number is a decimal or not.
Definition util.cpp:276
Utilities to operate strings.
Definition symbols.cpp:172
T toNumeric(const std::string &s)
Definition util.hpp:614
auto split(std::basic_string< CharT > s, const CharT separator)
Splits a string into substrings based on a separator.
Definition util.hpp:436
std::string vectorToString(const std::vector< ValueType > &vector)
Definition util.hpp:600
std::string unicodeToUtf8(const int unicode)
Converts a Unicode character to UTF-8 encoding.
Definition util.cpp:351
auto join(const std::vector< T > &vector, const std::string &delimiter)
Joins a vector of elements into a single string using a delimiter.
Definition util.hpp:557
auto lReplace(const std::basic_string< CharT > s, const CharT t, const CharT replacement='\0')
Replaces the leading occurrences of a character in a string with a replacement character.
Definition util.hpp:514
auto rReplace(const std::basic_string< CharT > s, const CharT t, const CharT replacement='\0')
Replaces the trailing occurrences of a character in a string with another character.
Definition util.hpp:488
std::string makeWider(const std::string &orig)
Makes the given string wider by adding 2 spaces between each character.
Definition util.cpp:322
std::vector< std::string > duplicates(const std::vector< std::string > &vector)
Gets the duplicates in a vector of strings.
auto bothEndsReplace(const std::basic_string< CharT > s, const CharT t, const CharT replacement='\0')
Replaces the leading and trailing occurrences of a character in a string with a replacement character...
Definition util.hpp:543
int utf8ToUnicode(const std::string &utf8_code)
Converts a UTF-8 encoded string to a Unicode string.
Definition util.cpp:334
The namespace containing utility functions for the Steppable library.
Definition argParse.cpp:40
void programSafeExit(const int status)
Exit the program safely.
Definition platform.hpp:61
void checkDecimalArg(const NumberT *decimal)
Checks whether the decimal number is correctly specified.
Definition util.hpp:211
void error(const std::string &name, const std::basic_string< T > &msg, const std::vector< std::string > &args={})
Prints an error message.
Definition output.hpp:80
A structure for storing split numbers.
Definition util.hpp:259
std::array< std::string, 4 > splitNumberArray
Definition util.hpp:260
char value[N]
The value of the wrapper class. Stores the string object.
Definition util.hpp:241
constexpr StringLiteral(const char(&str)[N])
Initializes the wrapper class.
Definition util.hpp:233
Untitled