From 01aeacfde3e88e987f741ca0d2c6301700ef81fc Mon Sep 17 00:00:00 2001 From: Recolic <git@me.recolic.net> Date: Tue, 31 Dec 2024 17:32:19 -0800 Subject: [PATCH] . --- standalone-toys/README.md | 13 + .../c-with-class.h | 0 standalone-toys/rdebug.h | 79 ++++++ standalone-toys/rlib.min.hpp | 243 ++++++++++++++++++ 4 files changed, 335 insertions(+) create mode 100644 standalone-toys/README.md rename c-with-class.h => standalone-toys/c-with-class.h (100%) create mode 100644 standalone-toys/rdebug.h create mode 100644 standalone-toys/rlib.min.hpp diff --git a/standalone-toys/README.md b/standalone-toys/README.md new file mode 100644 index 0000000..f951c64 --- /dev/null +++ b/standalone-toys/README.md @@ -0,0 +1,13 @@ +# Warning: This IS NOT single-file rlib header + +This directory contains useful standalone headers, for various c/cpp debugging. + +They **are not** part of rlib, and they are intended for situations while not practical to include a complete rlib. + +> DO NOT expect too much for these low-quality toys. + +|Header|Note| +|------|----| +|rdebug.h|Minimal C helper to print debug output| +|c-with-class.h|Old fashioned trick used in some C homeworks| +|rlib.min.hpp|Minimal io/string helper for solving OJ questions, or writing POC program| diff --git a/c-with-class.h b/standalone-toys/c-with-class.h similarity index 100% rename from c-with-class.h rename to standalone-toys/c-with-class.h diff --git a/standalone-toys/rdebug.h b/standalone-toys/rdebug.h new file mode 100644 index 0000000..c698284 --- /dev/null +++ b/standalone-toys/rdebug.h @@ -0,0 +1,79 @@ +/* +Usage: Put this in /usr/bin/stdio.h + +#if __has_include("/home/recolic/sh/rdebug.h") +#include "/home/recolic/sh/rdebug.h" +#endif + +DO NOT modify this file directly. Please commit any change to ~/sh/rdebug.h +version: 1.0.3 + +changelog: 1.0.3: add print_time for c +*/ + + +#ifndef RDB__H +#define RDB__H +#include <execinfo.h> +#include <stdio.h> +#include <stddef.h> +#define RDEBUG(fmt, ...) fprintf(stderr, "RDEBUG: %s:%d(%s), " #fmt "\n" , __FILE__, __LINE__, __func__ __VA_OPT__(,) __VA_ARGS__ ); + +#ifdef __cplusplus +#include <ostream> +#include <iomanip> +#include <cstdint> + +[[maybe_unused]] inline +#else +__attribute__((unused)) static +#endif +void printbt() { + void *array[32]; + int size; + + // get void*'s for all entries on the stack + size = backtrace(array, 32); + + // print out all the frames to stderr + backtrace_symbols_fd(array, size, 2); +} + + +#ifdef __cplusplus +template <typename CharT> +[[maybe_unused]] inline void print_buf(std::ostream& out, const char *title, const CharT *data, size_t dataLen) { + out << title << std::endl; + out << std::setfill('0'); + for(size_t i = 0; i < dataLen; ++i) { + out << std::hex << std::setw(2) << (0x000000ff & (int32_t)(((const char *)data)[i])); + // format + out << (((i + 1) % 16 == 0) ? "\n" : " "); + } + out << std::endl; +} +inline void print_buf(std::ostream& out, const char *title, const std::string &data) { + return print_buf(out, title, data.data(), data.size()); +} +#else +__attribute__((unused)) static void print_buf(FILE *stream, const char *title, const unsigned char *buf, size_t buf_len) +{ + size_t i = 0; + fprintf(stream, "%s\n", title); + for(i = 0; i < buf_len; ++i) + fprintf(stream, "%02X%s", buf[i], + ( i + 1 ) % 16 == 0 ? "\r\n" : " " ); + fprintf(stream, "\n"); +} +#include <time.h> +__attribute__((unused)) static void print_time(FILE *stream) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + // struct tm *my_tm = localtime(&ts.tv_sec); + fprintf(stream, "%lu.%lu\n", ts.tv_sec, ts.tv_nsec); +} +#endif + +#endif + + diff --git a/standalone-toys/rlib.min.hpp b/standalone-toys/rlib.min.hpp new file mode 100644 index 0000000..499f168 --- /dev/null +++ b/standalone-toys/rlib.min.hpp @@ -0,0 +1,243 @@ +/* + * + * string.hpp: string process utility. + * Recolic Keghart <root@recolic.net> + * MIT License + * + * Minified version: works on C++11. + * + */ + +#ifndef R_STRING_HPP +#define R_STRING_HPP + +#include <vector> +#include <string> +#include <stdexcept> + +namespace rlib { + class string : public std::string { + public: + using std::string::string; + string() : std::string() {} + string(const std::string &s) : std::string(s) {} + string(std::string &&s) : std::string(std::forward<std::string>(s)) {} + + private: + template <typename T> struct as_helper {}; + template <typename T> + T as(as_helper<T>) const { + if(empty()) return T(); + return T(*this); + } + const char *as(as_helper<const char *>) const { + return this->c_str(); + } + std::string as(as_helper<std::string>) const { + return std::move(*this); + } + rlib::string as(as_helper<rlib::string>) const { + return std::move(*this); + } + char as(as_helper<char>) const { + if(size() > 1) + throw std::invalid_argument("Can not convert rlib::string to char: size() > 1."); + return size() == 0 ? '\0' : *cbegin(); + } + // unsigned-char conflicts with uint8_t. I'll regard it as uint8_t. ("8".as<unsigned char> == 8) + //unsigned char as(as_helper<unsigned char>) const { + // return static_cast<unsigned char>(as<char>()); + //} + bool as(as_helper<bool>) const { + if(*this == "true") { + return true; + } + else if(*this == "false") { + return false; + } + // Nothing is slower than throw(); Just test more cases... + else if(*this == "1" || *this == "True" || *this == "TRUE") { + return true; + } + else if(*this == "0" || *this == "False" || *this == "FALSE") { + return false; + } + throw std::invalid_argument("Can not convert rlib::string to bool. Not matching any template."); + } + +#define RLIB_IMPL_GEN_AS_NUMERIC(type, std_conv) \ + type as(as_helper<type>) const { \ + if(empty()) return 0; \ + return std::std_conv(*this); \ + } + + RLIB_IMPL_GEN_AS_NUMERIC(int, stoi) + RLIB_IMPL_GEN_AS_NUMERIC(long, stol) + RLIB_IMPL_GEN_AS_NUMERIC(unsigned long, stoul) + RLIB_IMPL_GEN_AS_NUMERIC(unsigned long long, stoull) + RLIB_IMPL_GEN_AS_NUMERIC(long long, stoll) + RLIB_IMPL_GEN_AS_NUMERIC(float, stof) + RLIB_IMPL_GEN_AS_NUMERIC(double, stod) + RLIB_IMPL_GEN_AS_NUMERIC(long double, stold) + +#define RLIB_IMPL_GEN_AS_ALIAS(new_type, old_type) \ + new_type as(as_helper<new_type>) const { \ + return static_cast<new_type>(as<old_type>()); \ + } + + RLIB_IMPL_GEN_AS_ALIAS(unsigned int, unsigned long) + RLIB_IMPL_GEN_AS_ALIAS(unsigned short, unsigned long) + RLIB_IMPL_GEN_AS_ALIAS(uint8_t, unsigned long) + + RLIB_IMPL_GEN_AS_ALIAS(short, int) + RLIB_IMPL_GEN_AS_ALIAS(int8_t, int) + + public: + template <typename T> + T as() const { + return std::forward<T>(as(as_helper<T>())); + } + + template <typename T> + std::vector<T> split_as(const char ÷r = ' ') const { + const string &toSplit = *this; + std::vector<T> buf; + size_t curr = 0, prev = 0; + while((curr = toSplit.find(divider, curr)) != std::string::npos) { + buf.push_back(string(toSplit.substr(prev, curr - prev)).as<T>()); + ++curr; // skip divider + prev = curr; + } + buf.push_back(string(toSplit.substr(prev)).as<T>()); + return std::move(buf); + } + template <typename T> + std::vector<T> split_as(const std::string ÷r) const { + const string &toSplit = *this; + std::vector<T> buf; + size_t curr = 0, prev = 0; + while((curr = toSplit.find(divider, curr)) != std::string::npos) { + buf.push_back(string(toSplit.substr(prev, curr - prev)).as<T>()); + curr += divider.size(); // skip divider + prev = curr; + } + buf.push_back(string(toSplit.substr(prev)).as<T>()); + return std::move(buf); + } + + template <class ForwardIterable> + string &join(const ForwardIterable &buffer) { + join(buffer.cbegin(), buffer.cend()); + return *this; + } + template <class ForwardIterator> + string &join(ForwardIterator begin, ForwardIterator end) { + const string &toJoin = *this; + std::string result; + for(ForwardIterator iter = begin; iter != end; ++iter) { + if(iter != begin) + result += toJoin; + result += *iter; + } + return operator=(std::move(result)); + } + + string &strip() { + strip(" \t\r\n"); + return *this; + } + template <typename CharOrStringOrView> + string &strip(const CharOrStringOrView &stripped) { + size_t len = size(); + size_t begin = find_first_not_of(stripped); + + if(begin == std::string::npos) { + clear(); + return *this; + } + size_t end = find_last_not_of(stripped); + + erase(end + 1, len - end - 1); + erase(0, begin); + return *this; + } + + string &replace(const std::string &from, const std::string &to) { + size_t _; + replace(from, to, _); + return *this; + } + string &replace(const std::string &from, const std::string &to, size_t &out_times) { + if(from.empty()) + return *this; + size_t start_pos = 0; + size_t times = 0; + while((start_pos = find(from, start_pos)) != std::string::npos) + { + ++times; + this->std::string::replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + out_times = times; + return *this; + } + string &replace_once(const std::string &from, const std::string &to) { + bool _; + replace_once(from, to, _); + return *this; + } + string &replace_once(const std::string &from, const std::string &to, bool &out_replaced) { + size_t start_pos = find(from); + if(start_pos == std::string::npos) { + out_replaced = false; + } + else { + this->std::string::replace(start_pos, from.length(), to); + out_replaced = true; + } + return *this; + } + + + }; +} + +#endif + +#include <iostream> +#include <string> + +namespace rlib { + // This is my own hand-written library. I'm making it easy to use it directly. + + inline rlib::string scanln(std::istream &is = std::cin, char delimiter = '\n') noexcept { + std::string line; + std::getline(is, line, delimiter); + return (line); // RVO + } + + template <typename PrintFinalT> + void print(PrintFinalT reqArg) + { + std::cout << reqArg; + } + template <typename Required, typename... Optional> + void print(Required reqArgs, Optional... optiArgs) + { + std::cout << reqArgs << ' '; + print(optiArgs ...); + } + template <typename... Optional> + void println(Optional... optiArgs) + { + print(optiArgs ...); + println(); + } + template <> + inline void println() + { + //std::cout << rlib::endl; + std::cout << std::endl; + } +} + -- GitLab