Skip to content

Instantly share code, notes, and snippets.

@ppcamp
Last active June 4, 2024 04:02
Show Gist options
  • Save ppcamp/729a88fd985b34b34dc5dfe05590d63f to your computer and use it in GitHub Desktop.
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
#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(); }
@ppcamp
Copy link
Author

ppcamp commented May 21, 2024

g++ -DENABLE_DEBUG=true -std=c++20 main.cpp -o ./main && ./main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment