Last active
June 4, 2024 04:02
-
-
Save ppcamp/729a88fd985b34b34dc5dfe05590d63f to your computer and use it in GitHub Desktop.
A collection of functions for cpp coding. It includes methods for split/join strings; cpf validations/gen; datetime validations; random gen; sorting; and math functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> // transform | |
#include <cstdlib> // atoi | |
// invalid_argument https://en.cppreference.com/w/cpp/error/exception | |
// see https://en.cppreference.com/w/cpp/error/out_of_range | |
// https://softwareengineering.stackexchange.com/questions/430984/what-are-the-best-practices-when-implementing-c-error-handling | |
#include <chrono> | |
#include <cmath> // pow, sqrt | |
#include <exception> | |
#include <fstream> // For file-based logging | |
#include <iostream> // cout | |
#include <iterator> | |
#include <optional> | |
#include <random> | |
#include <sstream> // split string | |
#include <string> | |
#include <vector> | |
#ifndef DUMB_UTILS | |
#define DUMB_UTILS | |
#define BOOL_REPR(val) (val ? "true" : "false") | |
#define PTR_REPR(p, v) std::cout << std::hex << p << ' ' << v << std::endl; | |
#ifdef ENABLE_DEBUG | |
#define __DEBUG_INFO(str) std::cout << "[DEBUG] " << str << std::endl; | |
#else | |
#define __DEBUG_INFO(str) | |
#endif // DEBUG | |
namespace logging { | |
enum LogLevel { ERROR, WARNING, INFO, DEBUG }; | |
class Logger { | |
public: | |
Logger(bool enable = true) : stream(std::cout.rdbuf()), shouldLog(enable) {} | |
Logger(const std::string& filename, bool enable = true) | |
: file(filename), stream(file.rdbuf()), shouldLog(enable) {} | |
~Logger() { | |
if (!file.is_open()) file.close(); | |
} | |
void log(LogLevel level, const std::string& message) { | |
if (!shouldLog) return; | |
std::string prefix; | |
switch (level) { | |
case ERROR: | |
prefix = "[ERROR]"; | |
break; | |
case WARNING: | |
prefix = "[WARNING]"; | |
break; | |
case INFO: | |
prefix = "[INFO]"; | |
break; | |
case DEBUG: | |
prefix = "[DEBUG]"; | |
break; | |
} | |
if (!prefix.empty()) | |
stream << prefix << " " << message << std::endl; | |
else | |
stream << message << std::endl; | |
} | |
void info(const std::string& message) { log(LogLevel::INFO, message); } | |
void debug(const std::string& message) { log(LogLevel::DEBUG, message); } | |
void warn(const std::string& message) { log(LogLevel::WARNING, message); } | |
void error(const std::string& message) { log(LogLevel::ERROR, message); } | |
private: | |
std::ostream stream; | |
std::ofstream file; | |
bool shouldLog = true; | |
}; | |
int example() { | |
Logger logger; // Create a logger instance | |
logger.info("Application started."); | |
logger.warn("Something might be wrong."); | |
logger.error("Critical error occurred."); | |
logger.debug("Debug information."); | |
Logger l(false); | |
l.info("Should not log"); | |
return EXIT_SUCCESS; | |
} | |
} // namespace logging | |
namespace itertools { | |
template <typename T, typename It = std::vector<T>::iterator, typename Out> | |
std::vector<Out> map(It begin, It end, | |
std::function<Out(const T)>& callback) { | |
std::vector<Out> out; | |
for (auto it = begin; it != end; ++it) { | |
out.push_back(callback(*it)); | |
} | |
return out; | |
} | |
int example() { | |
std::vector<int> number = {1, 2, 3, 4, 5, 6, 7}; | |
std::function<std::string(const int)> cb = [](const int v) { | |
return std::to_string(v); | |
}; | |
auto numberstr = map(number.begin(), number.end(), cb); | |
for (auto&& i : numberstr) std::cout << i << std::endl; | |
return EXIT_SUCCESS; | |
} | |
} // namespace itertools | |
namespace string { | |
std::vector<std::string> split(const std::string str, const char sep, | |
size_t start = 0) { | |
int found = str.find_first_of(sep, start); | |
std::vector<std::string> response; | |
auto begin = str.begin(); | |
auto it = str.begin(); | |
for (; it != str.end(); ++it) { | |
if (*it == sep) { | |
response.push_back(std::string(begin, it)); | |
begin = it; | |
begin++; | |
} | |
} | |
if (begin != it) { | |
response.push_back(std::string(begin, it)); | |
} | |
return response; | |
} | |
/** | |
* @brief "A kludge" (quick fix) to solve the problem with mingW compiler, | |
* that doesn't accepted the method to_string, which compound the C++11 | |
*/ | |
std::string to_string(const int i) { | |
std::stringstream ss; | |
ss << i; | |
return ss.str(); | |
} | |
template <typename T> | |
std::string join(const std::vector<T>& val, | |
const std::string delimiter = "") { | |
std::stringstream ss; | |
for (size_t i = 0; i < val.size(); i++) { | |
ss << val[i]; | |
if (i < val.size() - 1) { | |
ss << delimiter; | |
} | |
} | |
return ss.str(); | |
} | |
/** | |
* render a table as string using provided header and data | |
* @todo center data basing on spacers | |
*/ | |
std::optional<std::string> table( | |
const std::vector<std::string>& headers, | |
const std::vector<std::vector<std::string>>& data, | |
const char delimiter = ' ') { | |
if (headers.size() != data.size() || data.empty()) return {}; | |
std::stringstream ss; | |
std::vector<size_t> spacers(headers.size()); | |
size_t len; | |
for (size_t col = 0; col < headers.size(); col++) { | |
spacers.push_back(headers[col].length()); | |
for (size_t row = 0; row < data.size(); row++) { | |
len = data[col][row].length(); | |
if (spacers[col] < len) spacers[col] = len; | |
} | |
} | |
// headers | |
for (size_t header = 0; header < headers.size(); header++) { | |
ss << headers[header]; | |
if (header < headers.size() - 1) { | |
len = spacers[header] - headers[header].length(); | |
ss << ' ' << std::string(len, ' ') << delimiter << ' '; | |
} | |
} | |
ss << '\n'; | |
ss << std::string(ss.str().length(), '-'); | |
ss << '\n'; | |
// rows | |
for (size_t row = 0; row < data[0].size(); row++) { | |
for (size_t col = 0; col < data.size(); col++) { | |
ss << data[col][row]; | |
if (col < headers.size() - 1) { | |
len = spacers[col] - data[col][row].length(); | |
ss << ' ' << std::string(len, ' ') << delimiter << ' '; | |
} | |
} | |
ss << '\n'; | |
} | |
return ss.str(); | |
} | |
template <typename T> | |
char __type_to_char(T i) { | |
return std::to_string(i)[0]; | |
} | |
int example() { | |
std::string foo = "Some,random,splitted,by commas"; | |
auto splitted = split(foo, ','); | |
for (auto s : splitted) std::cout << s << std::endl; | |
std::cout << foo << std::endl; | |
std::cout << join(splitted, ",") << std::endl; | |
const std::vector<std::string> headers = {"Name", "X", "Y", "Sum"}; | |
const std::vector<std::string> names = {"Cain", "Albert", "Joseph", | |
"Stuart"}; | |
const std::vector<std::string> xs = {"1", "1", "1", "1"}; | |
const std::vector<std::string> ys = {"1", "2", "3", "4"}; | |
const std::vector<std::string> sum = {"2", "3", "4", "5"}; | |
std::cout << std::endl | |
<< table(headers, | |
{ | |
names, | |
xs, | |
ys, | |
sum, | |
}, | |
' ') | |
.value_or("") | |
<< std::endl; | |
return EXIT_SUCCESS; | |
} | |
} // namespace string | |
namespace rd { | |
std::mt19937 seed() { | |
// Create a random number generator with a random seed | |
std::random_device rd; | |
std::mt19937 gen(rd()); | |
return gen; | |
} | |
/** | |
* @param from (inclusive) | |
* @param to (inclusive) | |
*/ | |
int rand(size_t from, size_t to, std::mt19937 _seed = rd::seed()) { | |
// Define a uniform integer distribution between 1 and 100 (inclusive) | |
std::uniform_int_distribution<> dis(from, to); | |
// Generate a random number | |
return dis(_seed); | |
} | |
int example() { | |
std::cout << rand(1, 9) << rand(1, 9) << rand(1, 9) << std::endl; | |
return EXIT_SUCCESS; | |
} | |
} // namespace rd | |
namespace cpf { | |
int __calc_sum(const std::vector<int>& cpf, size_t start_at) { | |
int sum = 0; | |
for (int i = start_at, j = 0; i >= 2; i--, j++) { | |
sum += cpf[j] * i; | |
} | |
return sum; | |
} | |
int __calc_rand(int sum) { | |
auto calc = (sum * 10) % 11; | |
return (calc == 10) ? 0 : calc; | |
} | |
/** | |
* @example | |
* auto isValid = cpf::is_valid("01234567890"); // false | |
*/ | |
std::optional<bool> is_valid(const std::vector<int>& cpf) { | |
if (cpf.size() != 11) return {}; | |
int n = 11; | |
while (--n > 0 && cpf[n] == cpf[0]); | |
if (n == 0) return false; // equal numbers are invalids cpf | |
int sum, calc; | |
sum = __calc_sum(cpf, 10); | |
calc = __calc_rand(sum); | |
if (calc != cpf[9]) return false; | |
sum = __calc_sum(cpf, 11); | |
calc = __calc_rand(sum); | |
return calc == cpf[10]; | |
} | |
/** | |
* @example | |
* std::string cpf = "01234567890"; | |
*/ | |
std::optional<bool> is_valid(const std::string& cpf) { | |
if (cpf.length() < 11) return {}; | |
std::string filter = cpf; | |
filter.erase(std::remove_if(filter.begin(), filter.end(), | |
[](const char c) { return !std::isdigit(c); }), | |
filter.end()); | |
if (filter.length() != 11) return {}; | |
auto cpfArr = std::vector<int>(11); | |
std::transform(filter.cbegin(), filter.cend(), cpfArr.begin(), | |
[](const char c) { return atoi(&c); }); | |
return is_valid(cpfArr); | |
} | |
/** | |
* Generate a valid cpf number | |
*/ | |
std::string generate() { | |
std::string output; | |
std::vector<int> gen(11); | |
do { | |
for (size_t i = 0; i < 9; i++) { | |
gen[i] = rd::rand(1, 9); | |
} | |
gen[9] = __calc_rand(__calc_sum(gen, 10)); | |
gen[10] = __calc_rand(__calc_sum(gen, 11)); | |
} while (!is_valid(gen)); | |
for (size_t i = 0; i < 11; i++) { | |
if ((i > 0 && i < 9) && i % 3 == 0) { | |
output.push_back('.'); | |
} else if (i == 9) { | |
output.push_back('-'); | |
} | |
output.push_back(std::to_string(gen[i])[0]); | |
} | |
return output; | |
} | |
int example() { | |
auto tests = std::vector<std::string>{ | |
"111", "111.111.111-11", "222.222.222-22", | |
cpf::generate(), cpf::generate(), cpf::generate()}; | |
for (auto test : tests) { | |
auto isValid = cpf::is_valid(test); | |
if (!isValid.has_value()) { | |
std::cerr << test << "\t\tWrong number of characters" << std::endl; | |
continue; | |
} | |
std::cout << test << "\t" << (isValid.value() ? "Is valid" : "Not valid") | |
<< std::endl; | |
} | |
return EXIT_SUCCESS; | |
} | |
} // namespace cpf | |
namespace math { | |
// More useful functions at cmath package | |
/** | |
* @return The quadrant of the greater angle | |
*/ | |
int angle_quadrant(int angle) { | |
auto q = angle % 360; | |
if (q < 0) q = q + 360; | |
if ((q == 0) || (q == 90) || (q == 180) || (q == 270) || (q == 360)) | |
return 0; | |
else if (q < 90) | |
return 1; | |
else if (q < 180) | |
return 2; | |
else if (q < 270) | |
return 3; | |
else | |
return 4; | |
} | |
/** | |
* @brief A function to calculate the bhaskara form. Formula: sqrt(b²-4ac) | |
*/ | |
template <typename T, std::enable_if<std::is_arithmetic<T>::value, T>> | |
T delta(const T& a, const T& b, const T& c) { | |
return sqrt(pow(b, 2) - 4 * a * c); | |
} | |
/** | |
* @brief A function to calculate the bhaskara form. | |
* Formula: [-b +- delta]/2a | |
*/ | |
template <typename T, typename O> | |
std::optional<std::pair<O, O>> bhaskara(T a, T b, T c) { | |
if (a == 0) return {}; | |
auto dt = delta(a, b, c); | |
auto den = 2 * a; | |
auto first = (-b + dt) / den; | |
auto second = (-b - dt) / den; | |
return std::make_pair(first, second); | |
} | |
/** | |
* bitwise operation to check if number is even or odd; | |
* @example | |
* 100 (4) 101 (5) | |
* 001 (1) 001 (1) | |
* 000 (even) 001 (1) (odd) | |
*/ | |
bool is_even(int num) { return (num & 1) == 0; } | |
/** | |
* @note that 0 isn't neither prime or composite (so if number is zero), and 1 | |
* is | |
* @return True for it's prime and false to otherwise. | |
*/ | |
std::optional<bool> prime(const int& a) { | |
// edge cases | |
if (a == 0) return {}; | |
if (a == 1) return false; | |
if (a == 2) return true; | |
if (is_even(a)) return false; // bitwise ignore all even numbers | |
for (int i = 3; i < a; i += 2) { // check only odd numbers | |
if (a % i == 0) return false; | |
} | |
return true; | |
} | |
/** | |
* @param Number of interactions. | |
* @brief A function to calculate the fibonacci value. | |
*/ | |
long long fib(const uint32_t n) { | |
if (n <= 1) return n; | |
long long prev = 0, curr = 1, tmp = 0; | |
for (uint32_t i = 2; i <= n; i++) { | |
tmp = prev; | |
prev = curr; | |
curr += tmp; | |
} | |
return curr; | |
} | |
/** | |
* @param Number wich you wanna extract decimal value. | |
* @return The decimal value of this number. * | |
*/ | |
inline long double decimal_part(double n) { return abs(n - (int)n); } | |
/** | |
* @return Factorial number value. | |
*/ | |
inline long long factorial(uint32_t n) { | |
if (n == 0) return 1; | |
long long num = n; | |
while (n-- > 1) num *= n; | |
return num; | |
} | |
int example() { | |
std::vector<int> tests = {7, 121, 263, 270, 360, 40, 230, 280}; | |
for (const auto& t : tests) { | |
printf("%d\tQuadrant %d \tEven? %s \tPrime? %s\n", t, angle_quadrant(t), | |
BOOL_REPR(is_even(t)), BOOL_REPR(prime(t).value_or(false))); | |
} | |
printf("Fib(1)=%lld\tFib(5)=%lld\tFib(11)=%lld\n", fib(1), fib(5), fib(11)); | |
printf("factorial(0)=%lld\tfactorial(5)=%lld\tfactorial(11)=%lld\n", | |
factorial(0), factorial(5), factorial(11)); | |
return EXIT_SUCCESS; | |
} | |
} // namespace math | |
namespace datetime { | |
enum Weekday { | |
Undefined, | |
Sunday, | |
Monday, | |
Tuesday, | |
Wednesday, | |
Thursday, | |
Friday, | |
Saturday | |
}; | |
std::string weekday_repr(Weekday day) { | |
const std::string days[] = {"Undefined", "Sunday", "Monday", "Tuesday", | |
"Wednesday", "Thursday", "Friday", "Saturday"}; | |
return days[static_cast<int>(day)]; | |
} | |
/* | |
* name: day_week | |
* @param Day in format "dd". | |
* @param Month in format "mm". | |
* @param Year in format "yyyy". | |
* @return The number correponding the day. | |
* @brief A function to say the day of the week. Formula: k = | |
* day+2*month+((3*(month+1))/5)+year+year/4-year/100+year/400+2. | |
*/ | |
Weekday day_of_week(int day, int month, int year) { | |
// January and February count as 13 and 14 months of the past year int | |
// this formula. | |
if (month == 1) { | |
month = 13; | |
year--; | |
} else if (month == 2) { | |
month = 14; | |
year--; | |
} | |
const int k = day + 2 * month + ((3 * (month + 1)) / 5) + year + year / 4 - | |
year / 100 + year / 400 + 2; | |
switch (k % 7) { | |
case 0: | |
return Weekday::Saturday; | |
case 1: | |
return Weekday::Sunday; | |
case 2: | |
return Weekday::Monday; | |
case 3: | |
return Weekday::Tuesday; | |
case 4: | |
return Weekday::Wednesday; | |
case 5: | |
return Weekday::Thursday; | |
case 6: | |
return Weekday::Friday; | |
default: | |
return Weekday::Undefined; | |
} | |
} | |
/** | |
* Check if february has 29 days | |
* @param Year in format "yyyy"; | |
* @return True for exist and False to otherwise. | |
* @brief A function to validate if year exist. | |
*/ | |
inline bool leap_year(int year) { | |
return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))); | |
} | |
/** | |
* @param Day in format "dd". | |
* @param Month in format "mm". | |
* @param Year in format "yyyy". | |
* @return True for exist, false to otherwise. | |
* @brief Verify if the date exist. | |
*/ | |
inline bool valid(int d, int m, int year) { | |
if (!(m >= 1 && m <= 12) || !(year >= 1800 && year <= 3000)) return false; | |
int daysarr[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | |
if (leap_year(year)) daysarr[1] = 29; | |
return d >= 1 && d <= daysarr[m]; | |
} | |
int example() { | |
std::cout << (leap_year(2024) ? "true" : "false") << std::endl; | |
std::cout << weekday_repr(day_of_week(18, 5, 2024)) << std::endl; | |
return EXIT_SUCCESS; | |
} | |
} // namespace datetime | |
namespace sort { | |
enum Order { ASC, DESC }; | |
/** | |
* in-place replacement sort | |
*/ | |
template <typename T> | |
void selection(std::vector<T>& v, Order order = Order::ASC) { | |
auto compare = [&](size_t i, size_t j) { | |
return order == Order::ASC ? v[j] > v[i] : v[j] < v[i]; | |
}; | |
for (int i = 0; i < v.size(); i++) { | |
for (int j = 0; j < v.size(); j++) { | |
if (compare(i, j)) { | |
int aux = v[i]; | |
v[i] = v[j]; | |
v[j] = aux; | |
} | |
} | |
} | |
} | |
int example() { | |
std::vector<int> v = {1, 4, 3, 2, 5}; | |
// ascending | |
selection(v); | |
for (auto i : v) std::cout << i << std::endl; | |
std::cout << std::endl; | |
// descending | |
selection(v, Order::DESC); | |
for (auto i : v) std::cout << i << std::endl; | |
return EXIT_SUCCESS; | |
} | |
} // namespace sort | |
namespace list { | |
template <typename T> | |
class Linked { | |
public: | |
struct Node { | |
T value; | |
Node *prev, *next; | |
Node() {} | |
Node(T val) : value(val), next(nullptr), prev(nullptr) {} | |
Node(T val, Node* prev) : value(val), next(nullptr), prev(prev) {} | |
}; | |
Linked() {} | |
Linked(const Linked& cp_src) { | |
for (auto it = cp_src.begin(); it != cp_src.end(); it++) insert(*it); | |
} | |
Linked(Linked&& mv_src) { | |
m_head = mv_src.m_head; | |
m_leaf = mv_src.m_leaf; | |
m_size = mv_src.m_size; | |
} | |
~Linked() { | |
this->clear(); | |
__DEBUG_INFO("Linked::~Linked()"); | |
} | |
bool empty() { return m_head == nullptr; } | |
const size_t size() const { return m_size; } | |
void clear() { | |
Node* curr = m_head; | |
__DEBUG_INFO("Linked::clear()"); | |
while (m_head != nullptr) { | |
curr = m_head; | |
m_head = m_head->next; | |
delete curr; | |
} | |
m_head = nullptr; | |
m_leaf = nullptr; | |
} | |
void insert(T item) { | |
Node* newNode = new Node(item, m_leaf); | |
if (m_leaf == nullptr) { | |
m_leaf = newNode; | |
m_head = newNode; | |
return; | |
} | |
m_leaf->next = newNode; | |
m_leaf = newNode; | |
m_size++; | |
} | |
bool remove(T item) { | |
Node* current = m_head; | |
while (current != nullptr && current->value != item) { | |
current = current->next; | |
} | |
// FIXME | |
if (current == nullptr) return false; | |
if (current == m_head) m_head = m_head->next; | |
if (current == m_leaf) m_leaf = m_leaf->prev; | |
if (current->prev != nullptr) { | |
current->prev->next = current->next; | |
} | |
delete current; | |
m_size--; | |
return true; | |
} | |
class Iterator { // very usefull for non array positions | |
private: | |
Node* curr; | |
public: | |
Iterator(Node* node) : curr(node) {} | |
// Overload the pre-increment operator | |
Iterator& operator++() { | |
curr = curr->next; | |
return *this; | |
} | |
Iterator& operator--() { | |
curr = curr->prev; | |
return *this; | |
} | |
// Overload the dereference operator | |
int operator*() { return curr->value; } | |
// Overload the inequality operator | |
bool operator!=(const Iterator& other) { return curr != other.curr; } | |
}; | |
Iterator begin() { return Iterator(m_head); } // used by | |
Iterator end() { return Iterator(nullptr); } // for ranged loop | |
const Iterator begin() const { return Iterator(m_head); } // used by | |
const Iterator end() const { return Iterator(nullptr); } // for ranged loop | |
Node& operator[](std::size_t idx) { | |
Node* cursor = m_head; | |
while (idx-- && cursor != nullptr) cursor = cursor->next; | |
return *cursor; | |
} | |
const Node& operator[](std::size_t idx) const { | |
auto it = operator[](idx); | |
return it; | |
} | |
private: | |
Node *m_head, *m_leaf; | |
size_t m_size; | |
}; | |
template <typename T> | |
class Slice { | |
public: | |
Slice(size_t capacity = 10) : arr(new T[capacity]), cap(capacity) {} | |
Slice(const Slice& cp_src) { // cp constructor | |
cap = cp_src.cap; | |
size = cp_src.size; | |
arr = new int[cap]; | |
std::copy(cp_src.arr, cp_src.arr + cap, arr); | |
} | |
Slice(Slice&& mv_src) { // mv constructor | |
cap = mv_src.cap; | |
size = mv_src.size; | |
arr = mv_src.arr; | |
} | |
~Slice() { | |
clear(); | |
__DEBUG_INFO("Slice::~Slice()"); | |
} | |
bool empty() { return arr == nullptr; } | |
void clear() { | |
__DEBUG_INFO("Slice::clear()"); | |
delete[] arr; | |
size = 0; | |
cap = 0; | |
} | |
void push_back(T item) { | |
++size; | |
if (size == cap) grew(cap + 100); | |
arr[size - 1] = item; | |
} | |
bool pop() { | |
if (size > 0) return false; | |
size--; | |
return true; | |
} | |
bool remove(size_t pos) { | |
if (pos < 0 || pos >= size) return false; | |
// shift elements | |
for (size_t i = pos; i < size - 1; i++) arr[i] = arr[i + 1]; | |
size--; | |
return true; | |
} | |
T& operator[](std::size_t idx) { return arr[idx]; } | |
const T& operator[](std::size_t idx) const { return arr[idx]; } | |
const T* begin() const { return arr; } | |
T* begin() { return arr; } | |
const T* end() const { return arr + size; } | |
T* end() { return arr + size; } | |
private: | |
T* arr; | |
size_t size, cap; | |
void grew(int capacity) { | |
cap = capacity; | |
T* aux = new T[capacity]; | |
std::copy(arr, arr + cap, aux); | |
delete[] arr; | |
arr = aux; | |
__DEBUG_INFO("Slice::Slice() grewing arr"); | |
} | |
}; | |
int example() { | |
Slice<int> slice; | |
Linked<int> linked; | |
for (size_t i = 1; i <= 15; i++) { | |
slice.push_back(i); | |
linked.insert(i); | |
} | |
std::cout << BOOL_REPR(linked.remove(5)) << std::endl; | |
std::cout << BOOL_REPR(slice.remove(3)) << std::endl; | |
for (auto&& i : slice) std::cout << i << " "; | |
std::cout << std::endl; | |
for (auto&& i : linked) std::cout << i << " "; | |
std::cout << std::endl; | |
// l.~Linked(); | |
// std::cout << l.empty() << std::endl; | |
std::cout << std::string(80, '-') << std::endl; | |
std::cout << "Slice [3,4] " << slice[3] << ' ' << slice[4] << std::endl; | |
std::cout << "Linked [3,4] " << linked[3].value << ' ' << linked[4].value | |
<< std::endl; | |
return EXIT_FAILURE; | |
} | |
} // namespace list | |
#endif // DUMB_UTILS | |
int main() { return list::example(); } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
g++ -DENABLE_DEBUG=true -std=c++20 main.cpp -o ./main && ./main