From cf4020fa0885178e51316d508399dc4c2d08a80c Mon Sep 17 00:00:00 2001 From: Johnathon Slightham Date: Sat, 24 Jan 2026 16:10:02 -0500 Subject: [PATCH] Initial commit --- BlockingQueue.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ Errno.h | 34 ++++++++++++++++++++++++++++++ Event.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ Map.h | 19 +++++++++++++++++ Number.h | 19 +++++++++++++++++ PairHash.h | 14 +++++++++++++ README.md | 3 +++ String.h | 20 ++++++++++++++++++ Variant.h | 23 +++++++++++++++++++++ ip.h | 26 +++++++++++++++++++++++ 10 files changed, 267 insertions(+) create mode 100644 BlockingQueue.h create mode 100644 Errno.h create mode 100644 Event.h create mode 100644 Map.h create mode 100644 Number.h create mode 100644 PairHash.h create mode 100644 README.md create mode 100644 String.h create mode 100644 Variant.h create mode 100644 ip.h diff --git a/BlockingQueue.h b/BlockingQueue.h new file mode 100644 index 0000000..0cccca5 --- /dev/null +++ b/BlockingQueue.h @@ -0,0 +1,54 @@ +// +// A thread safe queue with a maximum capacity with blocking enqueue and dequeue calls. +// enqueue blocks if the queue is full, dequeue blocks if the queue is empty. +// + +#ifndef BLOCKINGQUEUE_H +#define BLOCKINGQUEUE_H + +#include +#include +#include +#include +#include + +template class BlockingQueue { + public: + explicit BlockingQueue(const size_t capacity) : m_capacity(capacity) { + } + + // Enqueue with timeout. Returns true on success, false on timeout. + bool enqueue(T &&item, std::chrono::milliseconds max_wait) { + std::unique_lock lock(m_mutex); + if (!m_cond_not_full.wait_for(lock, max_wait, + [this]() { return m_queue.size() < m_capacity; })) { + return false; + } + + m_queue.push(std::move(item)); + m_cond_not_empty.notify_one(); + return true; + } + + // Dequeue with timeout. Returns optional (empty on timeout). + std::optional dequeue(std::chrono::milliseconds max_wait) { + std::unique_lock lock(m_mutex); + if (!m_cond_not_empty.wait_for(lock, max_wait, [this]() { return !m_queue.empty(); })) { + return std::nullopt; + } + + T item = std::move(m_queue.front()); + m_queue.pop(); + m_cond_not_full.notify_one(); + return item; + } + + private: + std::queue m_queue; + size_t m_capacity; + std::mutex m_mutex; + std::condition_variable m_cond_not_empty; + std::condition_variable m_cond_not_full; +}; + +#endif // BLOCKINGQUEUE_H diff --git a/Errno.h b/Errno.h new file mode 100644 index 0000000..2a06a69 --- /dev/null +++ b/Errno.h @@ -0,0 +1,34 @@ +// +// Print a detailed errno +// + +#ifndef ERRNO_H +#define ERRNO_H + +#include + +#define ERRBUF_SIZE 300 + +#ifdef _WIN32 + +std::string get_errno() { + std::string errbuf; + errbuf.resize(ERRBUERRBUF_SIZE); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, WSAGetLastError(), 0, errbuf.data(), ERERRBUF_SIZE, + NULL); + return errbuf; +} + +#else + +#include +#include + +std::string get_errno() { + std::string err = std::strerror(errno); + return err; +} + +#endif + +#endif //ERRNO_H diff --git a/Event.h b/Event.h new file mode 100644 index 0000000..caf1c97 --- /dev/null +++ b/Event.h @@ -0,0 +1,55 @@ + +// +// An event/listener system. +// + +#ifndef EVENT_H +#define EVENT_H + +#include +#include + +class Event; + +class CallbackHandle { + public: + CallbackHandle(Event *evt, int id) : m_evt(evt), m_id(id) { + } + ~CallbackHandle(); + + private: + Event *m_evt; + int m_id; +}; + +class Event { + public: + using Callback = std::function; + + CallbackHandle addListener(Callback cb) { + int id = m_nextId++; + m_callbacks[id] = std::move(cb); + return CallbackHandle(this, id); + } + + void remove(int id) { + m_callbacks.erase(id); + } + + void fire() { + for (auto &kv : m_callbacks) + kv.second(); + } + + private: + friend class CallbackHandle; + std::unordered_map m_callbacks; + int m_nextId = 0; +}; + +CallbackHandle::~CallbackHandle() { + if (m_evt) + m_evt->remove(m_id); +} + +#endif // EVENT_H diff --git a/Map.h b/Map.h new file mode 100644 index 0000000..2f46f0c --- /dev/null +++ b/Map.h @@ -0,0 +1,19 @@ + +#ifndef MAP_UTIL_H +#define MAP_UTIL_H + +#include +#include + +// Get vector of values from an unordered_map +template +std::vector map_to_values(const std::unordered_map &map) { + std::vector out; + out.reserve(map.size()); + for (auto const &[key, value] : map) { + out.push_back(value); + } + return out; +} + +#endif // MAP_UTIL_H diff --git a/Number.h b/Number.h new file mode 100644 index 0000000..9e1b333 --- /dev/null +++ b/Number.h @@ -0,0 +1,19 @@ + +#ifndef NUMBER_UTILS_H +#define NUMBER_UTILS_H + +#include +#include + +// Map a value with range, to another range. +template +T mapRange(T value, T inMin, T inMax, T outMin, T outMax) { + static_assert(std::is_arithmetic::value, "Template parameter must be a numeric type"); + if (inMin == inMax) { + return value; + } + + return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; +} + +#endif //NUMBER_UTILS_H diff --git a/PairHash.h b/PairHash.h new file mode 100644 index 0000000..6faffb6 --- /dev/null +++ b/PairHash.h @@ -0,0 +1,14 @@ + +#ifndef PAIRHASH_H +#define PAIRHASH_H + +#include + +// Custom hash function for std::pair +template struct pair_hash { + std::size_t operator()(const std::pair &p) const { + return std::hash()(p.first) ^ (std::hash()(p.second) << 1); + } +}; + +#endif // PAIRHASH_H diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e1511b --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# cpp-utils + +This repository contains a collection of C++ helper/utility functions I like to use in a lot of my projects. diff --git a/String.h b/String.h new file mode 100644 index 0000000..4c2040d --- /dev/null +++ b/String.h @@ -0,0 +1,20 @@ +#ifndef STRING_H +#define STRING_H +#include +#include +#include + +// Split a string on a delimiter to a vector of strings +inline std::vector split(const std::string &str, const char delimiter) { + std::vector result; + std::stringstream ss(str); + std::string token; + + while (std::getline(ss, token, delimiter)) { + result.push_back(token); + } + + return result; +} + +#endif //STRING_H diff --git a/Variant.h b/Variant.h new file mode 100644 index 0000000..78cc3b3 --- /dev/null +++ b/Variant.h @@ -0,0 +1,23 @@ + +// Helper to make it easier to use std::visit with std::variant +// For example, +// std::visit( +// overloaded{ +// [](int i) { std::cout << "int: " << i << std::endl; }, +// [](double d) { std::cout << "double: " << d << std::endl; }, +// }, +// variant +// ); + +#ifndef VARIANT_H +#define VARIANT_H + +#include // NOLINT + +template struct overloaded : Ts... { + using Ts::operator()...; +}; + +template overloaded(Ts...) -> overloaded; + +#endif // VARIANT_H diff --git a/ip.h b/ip.h new file mode 100644 index 0000000..52c2d47 --- /dev/null +++ b/ip.h @@ -0,0 +1,26 @@ +#ifndef IP_UTIL_H +#define IP_UTIL_H + +#include + +#ifdef _WIN32 +#include +#include +#define CLOSE_SOCKET closesocket +#pragma comment(lib, "ws2_32.lib") +typedef SOCKET socket_t; +#else +#include +#include +#include +#include +#define CLOSE_SOCKET close +typedef int socket_t; +#endif + +bool is_valid_ipv4(const std::string &ip) { + struct in_addr addr; + return inet_pton(AF_INET, ip.c_str(), &addr) == 1; +} + +#endif // IP_UTIL_H