Removed redundant 'Bloom' namespace from entire codebase
This commit is contained in:
@@ -5,109 +5,106 @@
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
namespace Bloom
|
||||
/**
|
||||
* Simple bidirectional map
|
||||
*
|
||||
* This should only be used for small maps, with small elements (enums, string literals, etc).
|
||||
*
|
||||
* TODO: This needs some work - was written as a quick implementation with minimal requirements.
|
||||
* TODO: Add support for inserting/deleting elements (outside of construction).
|
||||
*
|
||||
* @tparam TypeA
|
||||
* @tparam TypeB
|
||||
*/
|
||||
template<typename TypeA, typename TypeB>
|
||||
class BiMap
|
||||
{
|
||||
/**
|
||||
* Simple bidirectional map
|
||||
*
|
||||
* This should only be used for small maps, with small elements (enums, string literals, etc).
|
||||
*
|
||||
* TODO: This needs some work - was written as a quick implementation with minimal requirements.
|
||||
* TODO: Add support for inserting/deleting elements (outside of construction).
|
||||
*
|
||||
* @tparam TypeA
|
||||
* @tparam TypeB
|
||||
*/
|
||||
template<typename TypeA, typename TypeB>
|
||||
class BiMap
|
||||
{
|
||||
public:
|
||||
BiMap(std::initializer_list<std::pair<TypeA, TypeB>> elements) {
|
||||
for (auto it = elements.begin(); it != elements.end(); ++it) {
|
||||
this->map.insert(std::pair<TypeA, TypeB>{it->first, it->second});
|
||||
this->flippedMap.insert(std::pair<TypeB, TypeA>(it->second, it->first));
|
||||
}
|
||||
public:
|
||||
BiMap(std::initializer_list<std::pair<TypeA, TypeB>> elements) {
|
||||
for (auto it = elements.begin(); it != elements.end(); ++it) {
|
||||
this->map.insert(std::pair<TypeA, TypeB>{it->first, it->second});
|
||||
this->flippedMap.insert(std::pair<TypeB, TypeA>(it->second, it->first));
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(const TypeA& key) const {
|
||||
return this->map.find(key) != this->map.end();
|
||||
}
|
||||
|
||||
bool contains(const TypeB& key) const {
|
||||
return this->flippedMap.find(key) != this->flippedMap.end();
|
||||
}
|
||||
|
||||
auto find(const TypeA& key) const {
|
||||
const auto valueIt = this->map.find(key);
|
||||
return valueIt != this->map.end() ? std::optional(valueIt) : std::nullopt;
|
||||
}
|
||||
|
||||
auto find(const TypeB& key) const {
|
||||
const auto valueIt = this->flippedMap.find(key);
|
||||
return valueIt != this->flippedMap.end() ? std::optional(valueIt) : std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeB> valueAt(const TypeA& key) const {
|
||||
std::optional<TypeB> output;
|
||||
|
||||
const auto valueIt = this->map.find(key);
|
||||
if (valueIt != this->map.end()) {
|
||||
output = valueIt->second;
|
||||
}
|
||||
|
||||
bool contains(const TypeA& key) const {
|
||||
return this->map.find(key) != this->map.end();
|
||||
return output;
|
||||
}
|
||||
|
||||
std::optional<TypeA> valueAt(const TypeB& key) const {
|
||||
std::optional<TypeA> output;
|
||||
|
||||
const auto valueIt = this->flippedMap.find(key);
|
||||
if (valueIt != this->flippedMap.end()) {
|
||||
output = valueIt->second;
|
||||
}
|
||||
|
||||
bool contains(const TypeB& key) const {
|
||||
return this->flippedMap.find(key) != this->flippedMap.end();
|
||||
return output;
|
||||
}
|
||||
|
||||
const TypeB& at(const TypeA& key) const {
|
||||
return this->map.at(key);
|
||||
}
|
||||
|
||||
const TypeA& at(const TypeB& key) const {
|
||||
return this->flippedMap.at(key);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unordered_map<TypeA, TypeB> getMap() const {
|
||||
return this->map;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<TypeB> getKeys() const {
|
||||
auto keys = std::set<TypeB>();
|
||||
|
||||
for (const auto& [key, value] : this->map) {
|
||||
keys.insert(key);
|
||||
}
|
||||
|
||||
auto find(const TypeA& key) const {
|
||||
const auto valueIt = this->map.find(key);
|
||||
return valueIt != this->map.end() ? std::optional(valueIt) : std::nullopt;
|
||||
return keys;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<TypeB> getValues() const {
|
||||
auto values = std::set<TypeB>();
|
||||
|
||||
for (const auto& [key, value] : this->map) {
|
||||
values.insert(value);
|
||||
}
|
||||
|
||||
auto find(const TypeB& key) const {
|
||||
const auto valueIt = this->flippedMap.find(key);
|
||||
return valueIt != this->flippedMap.end() ? std::optional(valueIt) : std::nullopt;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
std::optional<TypeB> valueAt(const TypeA& key) const {
|
||||
std::optional<TypeB> output;
|
||||
void insert(const std::pair<TypeA, TypeB>& pair) {
|
||||
auto insertResultPair = this->map.insert(pair);
|
||||
this->flippedMap.insert(std::pair<TypeB, TypeA>(pair.second, pair.first));
|
||||
}
|
||||
|
||||
const auto valueIt = this->map.find(key);
|
||||
if (valueIt != this->map.end()) {
|
||||
output = valueIt->second;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::optional<TypeA> valueAt(const TypeB& key) const {
|
||||
std::optional<TypeA> output;
|
||||
|
||||
const auto valueIt = this->flippedMap.find(key);
|
||||
if (valueIt != this->flippedMap.end()) {
|
||||
output = valueIt->second;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const TypeB& at(const TypeA& key) const {
|
||||
return this->map.at(key);
|
||||
}
|
||||
|
||||
const TypeA& at(const TypeB& key) const {
|
||||
return this->flippedMap.at(key);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unordered_map<TypeA, TypeB> getMap() const {
|
||||
return this->map;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<TypeB> getKeys() const {
|
||||
auto keys = std::set<TypeB>();
|
||||
|
||||
for (const auto& [key, value] : this->map) {
|
||||
keys.insert(key);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::set<TypeB> getValues() const {
|
||||
auto values = std::set<TypeB>();
|
||||
|
||||
for (const auto& [key, value] : this->map) {
|
||||
values.insert(value);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
void insert(const std::pair<TypeA, TypeB>& pair) {
|
||||
auto insertResultPair = this->map.insert(pair);
|
||||
this->flippedMap.insert(std::pair<TypeB, TypeA>(pair.second, pair.first));
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<TypeA, TypeB> map = {};
|
||||
std::unordered_map<TypeB, TypeA> flippedMap = {};
|
||||
};
|
||||
}
|
||||
private:
|
||||
std::unordered_map<TypeA, TypeB> map = {};
|
||||
std::unordered_map<TypeB, TypeA> flippedMap = {};
|
||||
};
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
#include "ConditionVariableNotifier.hpp"
|
||||
|
||||
namespace Bloom
|
||||
{
|
||||
void ConditionVariableNotifier::notify() {
|
||||
const auto lock = std::unique_lock(this->mutex);
|
||||
this->notified = true;
|
||||
this->conditionalVariable.notify_all();
|
||||
}
|
||||
|
||||
void ConditionVariableNotifier::waitForNotification(std::optional<std::chrono::milliseconds> timeout) {
|
||||
const auto predicate = [this] {
|
||||
return this->notified;
|
||||
};
|
||||
auto lock = std::unique_lock(this->mutex);
|
||||
|
||||
if (timeout.has_value()) {
|
||||
this->conditionalVariable.wait_for(lock, timeout.value(), predicate);
|
||||
|
||||
} else {
|
||||
this->conditionalVariable.wait(lock, predicate);
|
||||
}
|
||||
|
||||
this->notified = false;
|
||||
}
|
||||
void ConditionVariableNotifier::notify() {
|
||||
const auto lock = std::unique_lock(this->mutex);
|
||||
this->notified = true;
|
||||
this->conditionalVariable.notify_all();
|
||||
}
|
||||
|
||||
void ConditionVariableNotifier::waitForNotification(std::optional<std::chrono::milliseconds> timeout) {
|
||||
const auto predicate = [this] {
|
||||
return this->notified;
|
||||
};
|
||||
auto lock = std::unique_lock(this->mutex);
|
||||
|
||||
if (timeout.has_value()) {
|
||||
this->conditionalVariable.wait_for(lock, timeout.value(), predicate);
|
||||
|
||||
} else {
|
||||
this->conditionalVariable.wait(lock, predicate);
|
||||
}
|
||||
|
||||
this->notified = false;
|
||||
}
|
||||
|
||||
@@ -7,40 +7,37 @@
|
||||
|
||||
#include "NotifierInterface.hpp"
|
||||
|
||||
namespace Bloom
|
||||
/**
|
||||
* The ConditionVariableNotifier class is an implementation of the NotifierInterface, using an
|
||||
* std::condition_variable.
|
||||
*/
|
||||
class ConditionVariableNotifier: public NotifierInterface
|
||||
{
|
||||
/**
|
||||
* The ConditionVariableNotifier class is an implementation of the NotifierInterface, using an
|
||||
* std::condition_variable.
|
||||
public:
|
||||
ConditionVariableNotifier() = default;
|
||||
~ConditionVariableNotifier() override = default;
|
||||
|
||||
/*
|
||||
* ConditionVariableNotifier objects should not be copied.
|
||||
*/
|
||||
class ConditionVariableNotifier: public NotifierInterface
|
||||
{
|
||||
public:
|
||||
ConditionVariableNotifier() = default;
|
||||
~ConditionVariableNotifier() override = default;
|
||||
ConditionVariableNotifier(ConditionVariableNotifier& other) = delete;
|
||||
ConditionVariableNotifier& operator = (ConditionVariableNotifier& other) = delete;
|
||||
|
||||
/*
|
||||
* ConditionVariableNotifier objects should not be copied.
|
||||
*/
|
||||
ConditionVariableNotifier(ConditionVariableNotifier& other) = delete;
|
||||
ConditionVariableNotifier& operator = (ConditionVariableNotifier& other) = delete;
|
||||
/*
|
||||
* TODO: Implement this.
|
||||
*/
|
||||
ConditionVariableNotifier(ConditionVariableNotifier&& other) noexcept = delete;
|
||||
ConditionVariableNotifier& operator = (ConditionVariableNotifier&& other) = delete;
|
||||
|
||||
/*
|
||||
* TODO: Implement this.
|
||||
*/
|
||||
ConditionVariableNotifier(ConditionVariableNotifier&& other) noexcept = delete;
|
||||
ConditionVariableNotifier& operator = (ConditionVariableNotifier&& other) = delete;
|
||||
void notify() override;
|
||||
|
||||
void notify() override;
|
||||
/**
|
||||
* Blocks until the contained std::conditional_variable is notified.
|
||||
*/
|
||||
void waitForNotification(std::optional<std::chrono::milliseconds> timeout = std::nullopt);
|
||||
|
||||
/**
|
||||
* Blocks until the contained std::conditional_variable is notified.
|
||||
*/
|
||||
void waitForNotification(std::optional<std::chrono::milliseconds> timeout = std::nullopt);
|
||||
|
||||
private:
|
||||
std::mutex mutex;
|
||||
std::condition_variable conditionalVariable;
|
||||
bool notified = false;
|
||||
};
|
||||
}
|
||||
private:
|
||||
std::mutex mutex;
|
||||
std::condition_variable conditionalVariable;
|
||||
bool notified = false;
|
||||
};
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Bloom {
|
||||
template<typename Type>
|
||||
requires std::is_pointer<Type>::value
|
||||
struct DereferenceLessComparator
|
||||
{
|
||||
constexpr bool operator () (const Type& lhs, const Type& rhs) const {
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
};
|
||||
}
|
||||
template<typename Type>
|
||||
requires std::is_pointer<Type>::value
|
||||
struct DereferenceLessComparator
|
||||
{
|
||||
constexpr bool operator () (const Type& lhs, const Type& rhs) const {
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,21 +6,18 @@
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
namespace Bloom
|
||||
class EnumToStringMappings
|
||||
{
|
||||
class EnumToStringMappings
|
||||
{
|
||||
public:
|
||||
static const inline BiMap<Targets::TargetMemoryType, QString> targetMemoryTypes = {
|
||||
{Targets::TargetMemoryType::RAM, "ram"},
|
||||
{Targets::TargetMemoryType::EEPROM, "eeprom"},
|
||||
{Targets::TargetMemoryType::FLASH, "flash"},
|
||||
{Targets::TargetMemoryType::OTHER, "other"},
|
||||
};
|
||||
|
||||
static const inline BiMap<Targets::TargetMemoryEndianness, QString> targetMemoryEndianness = {
|
||||
{Targets::TargetMemoryEndianness::LITTLE, "little"},
|
||||
{Targets::TargetMemoryEndianness::BIG, "big"},
|
||||
};
|
||||
public:
|
||||
static const inline BiMap<Targets::TargetMemoryType, QString> targetMemoryTypes = {
|
||||
{Targets::TargetMemoryType::RAM, "ram"},
|
||||
{Targets::TargetMemoryType::EEPROM, "eeprom"},
|
||||
{Targets::TargetMemoryType::FLASH, "flash"},
|
||||
{Targets::TargetMemoryType::OTHER, "other"},
|
||||
};
|
||||
}
|
||||
|
||||
static const inline BiMap<Targets::TargetMemoryEndianness, QString> targetMemoryEndianness = {
|
||||
{Targets::TargetMemoryEndianness::LITTLE, "little"},
|
||||
{Targets::TargetMemoryEndianness::BIG, "big"},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -7,71 +7,68 @@
|
||||
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom
|
||||
{
|
||||
using Exceptions::Exception;
|
||||
using Exceptions::Exception;
|
||||
|
||||
EpollInstance::EpollInstance() {
|
||||
this->fileDescriptor = ::epoll_create(1);
|
||||
EpollInstance::EpollInstance() {
|
||||
this->fileDescriptor = ::epoll_create(1);
|
||||
|
||||
if (this->fileDescriptor < 0) {
|
||||
throw Exception(
|
||||
"Failed to create epoll instance - error number " + std::to_string(errno)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void EpollInstance::addEntry(int fileDescriptor, std::uint16_t eventMask) {
|
||||
struct ::epoll_event event = {
|
||||
.events = eventMask,
|
||||
.data = {
|
||||
.fd = fileDescriptor
|
||||
}
|
||||
};
|
||||
|
||||
if (::epoll_ctl(this->fileDescriptor.value(), EPOLL_CTL_ADD, fileDescriptor, &event) != 0) {
|
||||
throw Exception(
|
||||
"Failed to add entry to epoll instance - error number " + std::to_string(errno) + " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void EpollInstance::removeEntry(int fileDescriptor) {
|
||||
if (::epoll_ctl(this->fileDescriptor.value(), EPOLL_CTL_DEL, fileDescriptor, NULL) != 0) {
|
||||
throw Exception(
|
||||
"Failed to remove entry from epoll instance - error number " + std::to_string(errno)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> EpollInstance::waitForEvent(std::optional<std::chrono::milliseconds> timeout) const {
|
||||
std::array<struct epoll_event, 1> events = {};
|
||||
|
||||
const auto eventCount = ::epoll_wait(
|
||||
this->fileDescriptor.value(),
|
||||
events.data(),
|
||||
1,
|
||||
timeout.has_value() ? static_cast<int>(timeout->count()) : -1
|
||||
if (this->fileDescriptor < 0) {
|
||||
throw Exception(
|
||||
"Failed to create epoll instance - error number " + std::to_string(errno)
|
||||
+ " returned."
|
||||
);
|
||||
|
||||
if (eventCount < 1) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return static_cast<int>(events.at(0).data.fd);
|
||||
}
|
||||
|
||||
EpollInstance::EpollInstance(EpollInstance&& other) noexcept
|
||||
: fileDescriptor(other.fileDescriptor)
|
||||
{
|
||||
other.fileDescriptor = std::nullopt;
|
||||
}
|
||||
|
||||
EpollInstance::~EpollInstance() noexcept {
|
||||
if (this->fileDescriptor.value_or(-1) >= 0) {
|
||||
::close(this->fileDescriptor.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EpollInstance::addEntry(int fileDescriptor, std::uint16_t eventMask) {
|
||||
struct ::epoll_event event = {
|
||||
.events = eventMask,
|
||||
.data = {
|
||||
.fd = fileDescriptor
|
||||
}
|
||||
};
|
||||
|
||||
if (::epoll_ctl(this->fileDescriptor.value(), EPOLL_CTL_ADD, fileDescriptor, &event) != 0) {
|
||||
throw Exception(
|
||||
"Failed to add entry to epoll instance - error number " + std::to_string(errno) + " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void EpollInstance::removeEntry(int fileDescriptor) {
|
||||
if (::epoll_ctl(this->fileDescriptor.value(), EPOLL_CTL_DEL, fileDescriptor, NULL) != 0) {
|
||||
throw Exception(
|
||||
"Failed to remove entry from epoll instance - error number " + std::to_string(errno)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<int> EpollInstance::waitForEvent(std::optional<std::chrono::milliseconds> timeout) const {
|
||||
std::array<struct epoll_event, 1> events = {};
|
||||
|
||||
const auto eventCount = ::epoll_wait(
|
||||
this->fileDescriptor.value(),
|
||||
events.data(),
|
||||
1,
|
||||
timeout.has_value() ? static_cast<int>(timeout->count()) : -1
|
||||
);
|
||||
|
||||
if (eventCount < 1) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return static_cast<int>(events.at(0).data.fd);
|
||||
}
|
||||
|
||||
EpollInstance::EpollInstance(EpollInstance&& other) noexcept
|
||||
: fileDescriptor(other.fileDescriptor)
|
||||
{
|
||||
other.fileDescriptor = std::nullopt;
|
||||
}
|
||||
|
||||
EpollInstance::~EpollInstance() noexcept {
|
||||
if (this->fileDescriptor.value_or(-1) >= 0) {
|
||||
::close(this->fileDescriptor.value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,62 +5,59 @@
|
||||
#include <optional>
|
||||
#include <chrono>
|
||||
|
||||
namespace Bloom
|
||||
/**
|
||||
* RAII wrapper for an epoll instance.
|
||||
*
|
||||
* See https://man7.org/linux/man-pages/man7/epoll.7.html for more on the Linux epoll API.
|
||||
*/
|
||||
class EpollInstance
|
||||
{
|
||||
public:
|
||||
EpollInstance();
|
||||
|
||||
/**
|
||||
* RAII wrapper for an epoll instance.
|
||||
* Adds an entry to the epoll instance.
|
||||
*
|
||||
* See https://man7.org/linux/man-pages/man7/epoll.7.html for more on the Linux epoll API.
|
||||
* @param fileDescriptor
|
||||
* @param eventMask
|
||||
*/
|
||||
class EpollInstance
|
||||
{
|
||||
public:
|
||||
EpollInstance();
|
||||
void addEntry(int fileDescriptor, std::uint16_t eventMask);
|
||||
|
||||
/**
|
||||
* Adds an entry to the epoll instance.
|
||||
*
|
||||
* @param fileDescriptor
|
||||
* @param eventMask
|
||||
*/
|
||||
void addEntry(int fileDescriptor, std::uint16_t eventMask);
|
||||
/**
|
||||
* Removes an entry from the epoll instance.
|
||||
*
|
||||
* @param fileDescriptor
|
||||
*/
|
||||
void removeEntry(int fileDescriptor);
|
||||
|
||||
/**
|
||||
* Removes an entry from the epoll instance.
|
||||
*
|
||||
* @param fileDescriptor
|
||||
*/
|
||||
void removeEntry(int fileDescriptor);
|
||||
/**
|
||||
* Waits on the epoll instance until an event occurs for any of the registered files.
|
||||
*
|
||||
* @param timeout
|
||||
* Millisecond timeout. If not provided, no timeout will be applied and this function will block until an
|
||||
* event occurs.
|
||||
*
|
||||
* @return
|
||||
* The file descriptor of the file for which the event occurred, or std::nullopt if a timeout was reached.
|
||||
*/
|
||||
[[nodiscard]] std::optional<int> waitForEvent(
|
||||
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
||||
) const;
|
||||
|
||||
/**
|
||||
* Waits on the epoll instance until an event occurs for any of the registered files.
|
||||
*
|
||||
* @param timeout
|
||||
* Millisecond timeout. If not provided, no timeout will be applied and this function will block until an
|
||||
* event occurs.
|
||||
*
|
||||
* @return
|
||||
* The file descriptor of the file for which the event occurred, or std::nullopt if a timeout was reached.
|
||||
*/
|
||||
[[nodiscard]] std::optional<int> waitForEvent(
|
||||
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
||||
) const;
|
||||
/*
|
||||
* EpollInstance objects should not be copied.
|
||||
*/
|
||||
EpollInstance(EpollInstance& other) = delete;
|
||||
EpollInstance& operator = (EpollInstance& other) = delete;
|
||||
|
||||
/*
|
||||
* EpollInstance objects should not be copied.
|
||||
*/
|
||||
EpollInstance(EpollInstance& other) = delete;
|
||||
EpollInstance& operator = (EpollInstance& other) = delete;
|
||||
/*
|
||||
* TODO: Implement this. For now, use the move constructor.
|
||||
*/
|
||||
EpollInstance& operator = (EpollInstance&& other) = delete;
|
||||
|
||||
/*
|
||||
* TODO: Implement this. For now, use the move constructor.
|
||||
*/
|
||||
EpollInstance& operator = (EpollInstance&& other) = delete;
|
||||
EpollInstance(EpollInstance&& other) noexcept;
|
||||
~EpollInstance() noexcept;
|
||||
|
||||
EpollInstance(EpollInstance&& other) noexcept;
|
||||
~EpollInstance() noexcept;
|
||||
|
||||
private:
|
||||
std::optional<int> fileDescriptor;
|
||||
};
|
||||
}
|
||||
private:
|
||||
std::optional<int> fileDescriptor;
|
||||
};
|
||||
|
||||
@@ -7,49 +7,46 @@
|
||||
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom
|
||||
{
|
||||
using Exceptions::Exception;
|
||||
using Exceptions::Exception;
|
||||
|
||||
EventFdNotifier::EventFdNotifier() {
|
||||
this->fileDescriptor = ::eventfd(0, ::EFD_NONBLOCK);
|
||||
EventFdNotifier::EventFdNotifier() {
|
||||
this->fileDescriptor = ::eventfd(0, ::EFD_NONBLOCK);
|
||||
|
||||
if (this->fileDescriptor < 0) {
|
||||
throw Exception(
|
||||
"Failed to create eventfd object - error number " + std::to_string(errno)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EventFdNotifier::EventFdNotifier(EventFdNotifier&& other) noexcept
|
||||
: fileDescriptor(other.fileDescriptor)
|
||||
{
|
||||
other.fileDescriptor = std::nullopt;
|
||||
}
|
||||
|
||||
EventFdNotifier::~EventFdNotifier() noexcept {
|
||||
this->close();
|
||||
}
|
||||
|
||||
void EventFdNotifier::notify() {
|
||||
if (::eventfd_write(this->fileDescriptor.value(), 1) < 0) {
|
||||
throw Exceptions::Exception("Failed to increment eventfd counter - error number: "
|
||||
+ std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void EventFdNotifier::clear() {
|
||||
::eventfd_t counter = {};
|
||||
if (::eventfd_read(this->fileDescriptor.value(), &counter) < 0 && errno != EAGAIN) {
|
||||
throw Exceptions::Exception("Failed to clear EventFdNotifier object - eventfd_read failed - "
|
||||
"error number: " + std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void EventFdNotifier::close() {
|
||||
if (this->fileDescriptor.value_or(-1) >= 0) {
|
||||
::close(this->fileDescriptor.value());
|
||||
}
|
||||
if (this->fileDescriptor < 0) {
|
||||
throw Exception(
|
||||
"Failed to create eventfd object - error number " + std::to_string(errno)
|
||||
+ " returned."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EventFdNotifier::EventFdNotifier(EventFdNotifier&& other) noexcept
|
||||
: fileDescriptor(other.fileDescriptor)
|
||||
{
|
||||
other.fileDescriptor = std::nullopt;
|
||||
}
|
||||
|
||||
EventFdNotifier::~EventFdNotifier() noexcept {
|
||||
this->close();
|
||||
}
|
||||
|
||||
void EventFdNotifier::notify() {
|
||||
if (::eventfd_write(this->fileDescriptor.value(), 1) < 0) {
|
||||
throw Exceptions::Exception("Failed to increment eventfd counter - error number: "
|
||||
+ std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void EventFdNotifier::clear() {
|
||||
::eventfd_t counter = {};
|
||||
if (::eventfd_read(this->fileDescriptor.value(), &counter) < 0 && errno != EAGAIN) {
|
||||
throw Exceptions::Exception("Failed to clear EventFdNotifier object - eventfd_read failed - "
|
||||
"error number: " + std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void EventFdNotifier::close() {
|
||||
if (this->fileDescriptor.value_or(-1) >= 0) {
|
||||
::close(this->fileDescriptor.value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,41 +4,38 @@
|
||||
|
||||
#include "NotifierInterface.hpp"
|
||||
|
||||
namespace Bloom
|
||||
/**
|
||||
* RAII wrapper for a Linux eventfd object, used to implement the NotifierInterface.
|
||||
*/
|
||||
class EventFdNotifier: public NotifierInterface
|
||||
{
|
||||
/**
|
||||
* RAII wrapper for a Linux eventfd object, used to implement the NotifierInterface.
|
||||
public:
|
||||
EventFdNotifier();
|
||||
|
||||
/*
|
||||
* EventNotifier objects should not be copied.
|
||||
*/
|
||||
class EventFdNotifier: public NotifierInterface
|
||||
{
|
||||
public:
|
||||
EventFdNotifier();
|
||||
EventFdNotifier(EventFdNotifier& other) = delete;
|
||||
EventFdNotifier& operator = (EventFdNotifier& other) = delete;
|
||||
|
||||
/*
|
||||
* EventNotifier objects should not be copied.
|
||||
*/
|
||||
EventFdNotifier(EventFdNotifier& other) = delete;
|
||||
EventFdNotifier& operator = (EventFdNotifier& other) = delete;
|
||||
/*
|
||||
* TODO: Implement this. For now, use the move constructor.
|
||||
*/
|
||||
EventFdNotifier& operator = (EventFdNotifier&& other) = delete;
|
||||
|
||||
/*
|
||||
* TODO: Implement this. For now, use the move constructor.
|
||||
*/
|
||||
EventFdNotifier& operator = (EventFdNotifier&& other) = delete;
|
||||
EventFdNotifier(EventFdNotifier&& other) noexcept;
|
||||
~EventFdNotifier() noexcept override;
|
||||
|
||||
EventFdNotifier(EventFdNotifier&& other) noexcept;
|
||||
~EventFdNotifier() noexcept override;
|
||||
[[nodiscard]] int getFileDescriptor() const {
|
||||
return this->fileDescriptor.value();
|
||||
}
|
||||
|
||||
[[nodiscard]] int getFileDescriptor() const {
|
||||
return this->fileDescriptor.value();
|
||||
}
|
||||
void notify() override;
|
||||
|
||||
void notify() override;
|
||||
void clear();
|
||||
|
||||
void clear();
|
||||
private:
|
||||
std::optional<int> fileDescriptor;
|
||||
|
||||
private:
|
||||
std::optional<int> fileDescriptor;
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
void close();
|
||||
};
|
||||
|
||||
@@ -1,37 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
namespace Bloom
|
||||
/**
|
||||
* The NotifierInterface class describes an interface for notifying different components, within Bloom, of something
|
||||
* important that has just happened.
|
||||
*
|
||||
* It's important to note that this interface only describes the issuing of notifications. It *does not* describe
|
||||
* the listening for notifications. The listening can be defined by the implementation.
|
||||
*
|
||||
* For example, consider the EventFdNotifier implementation. That class is just an RAII wrapper for a Linux eventfd
|
||||
* object. Notifications are recorded by incrementing the eventfd counter. And they can be listened for, using
|
||||
* Linux system functions like poll(), select(), and similar.
|
||||
*
|
||||
* The EventListener class can hold a pointer to a NotifierInterface, where it will invoke
|
||||
* NotifierInterface::notify() everytime a new event is registered on the listener.
|
||||
*/
|
||||
class NotifierInterface
|
||||
{
|
||||
public:
|
||||
NotifierInterface() = default;
|
||||
virtual ~NotifierInterface() noexcept = default;
|
||||
|
||||
NotifierInterface(NotifierInterface& other) = delete;
|
||||
|
||||
NotifierInterface& operator = (NotifierInterface& other) = delete;
|
||||
NotifierInterface& operator = (NotifierInterface&& other) = delete;
|
||||
|
||||
NotifierInterface(NotifierInterface&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* The NotifierInterface class describes an interface for notifying different components, within Bloom, of something
|
||||
* important that has just happened.
|
||||
*
|
||||
* It's important to note that this interface only describes the issuing of notifications. It *does not* describe
|
||||
* the listening for notifications. The listening can be defined by the implementation.
|
||||
*
|
||||
* For example, consider the EventFdNotifier implementation. That class is just an RAII wrapper for a Linux eventfd
|
||||
* object. Notifications are recorded by incrementing the eventfd counter. And they can be listened for, using
|
||||
* Linux system functions like poll(), select(), and similar.
|
||||
*
|
||||
* The EventListener class can hold a pointer to a NotifierInterface, where it will invoke
|
||||
* NotifierInterface::notify() everytime a new event is registered on the listener.
|
||||
* Should record a notification.
|
||||
*/
|
||||
class NotifierInterface
|
||||
{
|
||||
public:
|
||||
NotifierInterface() = default;
|
||||
virtual ~NotifierInterface() noexcept = default;
|
||||
|
||||
NotifierInterface(NotifierInterface& other) = delete;
|
||||
|
||||
NotifierInterface& operator = (NotifierInterface& other) = delete;
|
||||
NotifierInterface& operator = (NotifierInterface&& other) = delete;
|
||||
|
||||
NotifierInterface(NotifierInterface&& other) noexcept = default;
|
||||
|
||||
/**
|
||||
* Should record a notification.
|
||||
*/
|
||||
virtual void notify() = 0;
|
||||
};
|
||||
}
|
||||
virtual void notify() = 0;
|
||||
};
|
||||
|
||||
@@ -3,76 +3,73 @@
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace Bloom
|
||||
/**
|
||||
* Wrapper for synchronised access to a resource.
|
||||
*
|
||||
* @tparam Type
|
||||
*/
|
||||
template<typename Type>
|
||||
class Synchronised
|
||||
{
|
||||
/**
|
||||
* Wrapper for synchronised access to a resource.
|
||||
*
|
||||
* @tparam Type
|
||||
*/
|
||||
template<typename Type>
|
||||
class Synchronised
|
||||
public:
|
||||
class Accessor
|
||||
{
|
||||
public:
|
||||
class Accessor
|
||||
{
|
||||
public:
|
||||
constexpr Accessor(std::mutex& mutex, Type& value)
|
||||
: lock(std::unique_lock(mutex))
|
||||
, value(value)
|
||||
{}
|
||||
|
||||
constexpr Type* operator -> () noexcept {
|
||||
return &(this->value);
|
||||
}
|
||||
|
||||
constexpr const Type* operator -> () const noexcept {
|
||||
return &(this->value);
|
||||
}
|
||||
|
||||
constexpr Type& operator * () noexcept {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
constexpr const Type& operator * () const noexcept {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_lock<std::mutex> lock;
|
||||
Type& value;
|
||||
};
|
||||
|
||||
Synchronised() = default;
|
||||
|
||||
explicit Synchronised(Type value)
|
||||
: value(std::move(value))
|
||||
constexpr Accessor(std::mutex& mutex, Type& value)
|
||||
: lock(std::unique_lock(mutex))
|
||||
, value(value)
|
||||
{}
|
||||
|
||||
Accessor accessor() {
|
||||
return Accessor(this->mutex, this->value);
|
||||
constexpr Type* operator -> () noexcept {
|
||||
return &(this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use this unless you already hold a raw (not managed by an Accessor) lock to the contained value.
|
||||
*
|
||||
* This should only be used in instances where you need to hold a raw lock, like in the `stop_waiting`
|
||||
* predicate function for a call to std::condition_variable::wait().
|
||||
*
|
||||
* In all other instances, you should use Synchronised::accessor().
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Type& unsafeReference() {
|
||||
constexpr const Type* operator -> () const noexcept {
|
||||
return &(this->value);
|
||||
}
|
||||
|
||||
constexpr Type& operator * () noexcept {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock() {
|
||||
return std::unique_lock(this->mutex);
|
||||
constexpr const Type& operator * () const noexcept {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
std::mutex mutex;
|
||||
std::unique_lock<std::mutex> lock;
|
||||
Type& value;
|
||||
};
|
||||
}
|
||||
|
||||
Synchronised() = default;
|
||||
|
||||
explicit Synchronised(Type value)
|
||||
: value(std::move(value))
|
||||
{}
|
||||
|
||||
Accessor accessor() {
|
||||
return Accessor(this->mutex, this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use this unless you already hold a raw (not managed by an Accessor) lock to the contained value.
|
||||
*
|
||||
* This should only be used in instances where you need to hold a raw lock, like in the `stop_waiting`
|
||||
* predicate function for a call to std::condition_variable::wait().
|
||||
*
|
||||
* In all other instances, you should use Synchronised::accessor().
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Type& unsafeReference() {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock() {
|
||||
return std::unique_lock(this->mutex);
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
@@ -5,50 +5,47 @@
|
||||
#include <cassert>
|
||||
#include <atomic>
|
||||
|
||||
namespace Bloom
|
||||
enum class ThreadState: std::uint8_t
|
||||
{
|
||||
enum class ThreadState: std::uint8_t
|
||||
{
|
||||
UNINITIALISED,
|
||||
READY,
|
||||
STOPPED,
|
||||
STARTING,
|
||||
SHUTDOWN_INITIATED,
|
||||
};
|
||||
UNINITIALISED,
|
||||
READY,
|
||||
STOPPED,
|
||||
STARTING,
|
||||
SHUTDOWN_INITIATED,
|
||||
};
|
||||
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
Thread() = default;
|
||||
virtual ~Thread() = default;
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
Thread() = default;
|
||||
virtual ~Thread() = default;
|
||||
|
||||
Thread(const Thread& other) = delete;
|
||||
Thread(Thread&& other) = delete;
|
||||
Thread(const Thread& other) = delete;
|
||||
Thread(Thread&& other) = delete;
|
||||
|
||||
Thread& operator = (const Thread& other) = delete;
|
||||
Thread& operator = (Thread&& other) = delete;
|
||||
Thread& operator = (const Thread& other) = delete;
|
||||
Thread& operator = (Thread&& other) = delete;
|
||||
|
||||
ThreadState getThreadState() {
|
||||
return this->threadState;
|
||||
}
|
||||
ThreadState getThreadState() {
|
||||
return this->threadState;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::atomic<ThreadState> threadState = ThreadState::UNINITIALISED;
|
||||
protected:
|
||||
std::atomic<ThreadState> threadState = ThreadState::UNINITIALISED;
|
||||
|
||||
/**
|
||||
* Disables signal interrupts on current thread.
|
||||
*/
|
||||
static void blockAllSignals() {
|
||||
sigset_t set = {};
|
||||
sigfillset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
}
|
||||
/**
|
||||
* Disables signal interrupts on current thread.
|
||||
*/
|
||||
static void blockAllSignals() {
|
||||
sigset_t set = {};
|
||||
sigfillset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
}
|
||||
|
||||
void setName(const std::string& name) {
|
||||
// POSIX thread names cannot exceed 16 characters, including the terminating null byte.
|
||||
assert(name.size() <= 15);
|
||||
void setName(const std::string& name) {
|
||||
// POSIX thread names cannot exceed 16 characters, including the terminating null byte.
|
||||
assert(name.size() <= 15);
|
||||
|
||||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
}
|
||||
};
|
||||
}
|
||||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
namespace Bloom
|
||||
class YamlUtilities
|
||||
{
|
||||
class YamlUtilities
|
||||
{
|
||||
public:
|
||||
template <typename Type>
|
||||
static bool isCastable(const YAML::Node& node) {
|
||||
try {
|
||||
node.as<Type>();
|
||||
return true;
|
||||
public:
|
||||
template <typename Type>
|
||||
static bool isCastable(const YAML::Node& node) {
|
||||
try {
|
||||
node.as<Type>();
|
||||
return true;
|
||||
|
||||
} catch (YAML::BadConversion&) {
|
||||
return false;
|
||||
}
|
||||
} catch (YAML::BadConversion&) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user