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