summaryrefslogtreecommitdiffstats
path: root/include/raul
diff options
context:
space:
mode:
Diffstat (limited to 'include/raul')
-rw-r--r--include/raul/Array.hpp238
-rw-r--r--include/raul/Deletable.hpp12
-rw-r--r--include/raul/DoubleBuffer.hpp120
-rw-r--r--include/raul/Exception.hpp13
-rw-r--r--include/raul/Maid.hpp235
-rw-r--r--include/raul/Noncopyable.hpp15
-rw-r--r--include/raul/Path.hpp359
-rw-r--r--include/raul/Process.hpp89
-rw-r--r--include/raul/RingBuffer.hpp367
-rw-r--r--include/raul/Semaphore.hpp204
-rw-r--r--include/raul/Socket.hpp337
-rw-r--r--include/raul/Symbol.hpp186
-rw-r--r--include/raul/TimeSlice.hpp215
-rw-r--r--include/raul/TimeStamp.hpp360
14 files changed, 1420 insertions, 1330 deletions
diff --git a/include/raul/Array.hpp b/include/raul/Array.hpp
index a80038f..9e7e24c 100644
--- a/include/raul/Array.hpp
+++ b/include/raul/Array.hpp
@@ -29,129 +29,131 @@ namespace Raul {
*
* \ingroup raul
*/
-template <class T>
+template<class T>
class Array : public Maid::Disposable
{
public:
- explicit Array(size_t size = 0)
- : Maid::Disposable()
- , _size(size)
- , _elems(size ? new T[size] : nullptr)
- {
- }
-
- Array(size_t size, T initial_value)
- : Maid::Disposable()
- , _size(size)
- , _elems(size ? new T[size] : nullptr)
- {
- if (size > 0) {
- for (size_t i = 0; i < size; ++i) {
- _elems[i] = initial_value;
- }
- }
- }
-
- Array(const Array<T>& array)
- : Maid::Disposable()
- , _size(array._size)
- , _elems(_size ? new T[_size] : nullptr)
- {
- for (size_t i = 0; i < _size; ++i) {
- _elems[i] = array._elems[i];
- }
- }
-
- ~Array() override = default;
-
- Array<T>& operator=(const Array<T>& array)
- {
- if (&array == this) {
- return *this;
- }
-
- _size = array._size;
- _elems = _size ? new T[_size] : nullptr;
-
- for (size_t i = 0; i < _size; ++i) {
- _elems[i] = array._elems[i];
- }
- }
-
- Array(Array<T>&& array) noexcept
- : _size(array._size)
- , _elems(std::move(array._elems))
- {
- }
-
- Array<T>& operator=(Array<T>&& array) noexcept
- {
- _size = array._size;
- _elems = std::move(array._elems);
- return *this;
- }
-
- Array(size_t size, const Array<T>& contents)
- : _size(size)
- , _elems(size ? new T[size] : nullptr)
- {
- assert(contents.size() >= size);
- for (size_t i = 0; i < std::min(size, contents.size()); ++i) {
- _elems[i] = contents[i];
- }
- }
-
- Array(size_t size, const Array<T>& contents, T initial_value = T())
- : _size(size)
- , _elems(size ? new T[size] : nullptr)
- {
- const size_t end = std::min(size, contents.size());
- for (size_t i = 0; i < end; ++i) {
- _elems[i] = contents[i];
- }
- for (size_t i = end; i < size; ++i) {
- _elems[i] = initial_value;
- }
- }
-
- virtual void alloc(size_t num_elems) {
- _size = num_elems;
-
- if (num_elems > 0) {
- _elems = std::unique_ptr<T[]>(new T[num_elems]);
- } else {
- _elems.reset();
- }
- }
-
- virtual void alloc(size_t num_elems, T initial_value) {
- _size = num_elems;
-
- if (num_elems > 0) {
- _elems = std::unique_ptr<T[]>(new T[num_elems]);
- for (size_t i = 0; i < _size; ++i) {
- _elems[i] = initial_value;
- }
- } else {
- _elems.reset();
- }
- }
-
- inline size_t size() const { return _size; }
-
- inline T& operator[](size_t i) const {
- assert(i < _size);
- return _elems[i];
- }
-
- inline T& at(size_t i) const {
- assert(i < _size);
- return _elems[i];
- }
+ explicit Array(size_t size = 0)
+ : Maid::Disposable()
+ , _size(size)
+ , _elems(size ? new T[size] : nullptr)
+ {}
+
+ Array(size_t size, T initial_value)
+ : Maid::Disposable()
+ , _size(size)
+ , _elems(size ? new T[size] : nullptr)
+ {
+ if (size > 0) {
+ for (size_t i = 0; i < size; ++i) {
+ _elems[i] = initial_value;
+ }
+ }
+ }
+
+ Array(const Array<T>& array)
+ : Maid::Disposable()
+ , _size(array._size)
+ , _elems(_size ? new T[_size] : nullptr)
+ {
+ for (size_t i = 0; i < _size; ++i) {
+ _elems[i] = array._elems[i];
+ }
+ }
+
+ ~Array() override = default;
+
+ Array<T>& operator=(const Array<T>& array)
+ {
+ if (&array == this) {
+ return *this;
+ }
+
+ _size = array._size;
+ _elems = _size ? new T[_size] : nullptr;
+
+ for (size_t i = 0; i < _size; ++i) {
+ _elems[i] = array._elems[i];
+ }
+ }
+
+ Array(Array<T>&& array) noexcept
+ : _size(array._size)
+ , _elems(std::move(array._elems))
+ {}
+
+ Array<T>& operator=(Array<T>&& array) noexcept
+ {
+ _size = array._size;
+ _elems = std::move(array._elems);
+ return *this;
+ }
+
+ Array(size_t size, const Array<T>& contents)
+ : _size(size)
+ , _elems(size ? new T[size] : nullptr)
+ {
+ assert(contents.size() >= size);
+ for (size_t i = 0; i < std::min(size, contents.size()); ++i) {
+ _elems[i] = contents[i];
+ }
+ }
+
+ Array(size_t size, const Array<T>& contents, T initial_value = T())
+ : _size(size)
+ , _elems(size ? new T[size] : nullptr)
+ {
+ const size_t end = std::min(size, contents.size());
+ for (size_t i = 0; i < end; ++i) {
+ _elems[i] = contents[i];
+ }
+ for (size_t i = end; i < size; ++i) {
+ _elems[i] = initial_value;
+ }
+ }
+
+ virtual void alloc(size_t num_elems)
+ {
+ _size = num_elems;
+
+ if (num_elems > 0) {
+ _elems = std::unique_ptr<T[]>(new T[num_elems]);
+ } else {
+ _elems.reset();
+ }
+ }
+
+ virtual void alloc(size_t num_elems, T initial_value)
+ {
+ _size = num_elems;
+
+ if (num_elems > 0) {
+ _elems = std::unique_ptr<T[]>(new T[num_elems]);
+ for (size_t i = 0; i < _size; ++i) {
+ _elems[i] = initial_value;
+ }
+ } else {
+ _elems.reset();
+ }
+ }
+
+ inline size_t size() const { return _size; }
+
+ inline T& operator[](size_t i) const
+ {
+ assert(i < _size);
+ return _elems[i];
+ }
+
+ inline T& at(size_t i) const
+ {
+ assert(i < _size);
+ return _elems[i];
+ }
private:
- size_t _size;
- std::unique_ptr<T[]> _elems;
+ size_t _size;
+ std::unique_ptr<T[]> _elems;
};
} // namespace Raul
diff --git a/include/raul/Deletable.hpp b/include/raul/Deletable.hpp
index 63a7a88..39262c8 100644
--- a/include/raul/Deletable.hpp
+++ b/include/raul/Deletable.hpp
@@ -25,15 +25,15 @@ namespace Raul {
class Deletable
{
public:
- Deletable() = default;
+ Deletable() = default;
- Deletable(const Deletable&) = default;
- Deletable& operator=(const Deletable&) = default;
+ Deletable(const Deletable&) = default;
+ Deletable& operator=(const Deletable&) = default;
- Deletable(Deletable&&) = default;
- Deletable& operator=(Deletable&&) = default;
+ Deletable(Deletable&&) = default;
+ Deletable& operator=(Deletable&&) = default;
- virtual ~Deletable() = default;
+ virtual ~Deletable() = default;
};
} // namespace Raul
diff --git a/include/raul/DoubleBuffer.hpp b/include/raul/DoubleBuffer.hpp
index 95ece0f..1c1ee69 100644
--- a/include/raul/DoubleBuffer.hpp
+++ b/include/raul/DoubleBuffer.hpp
@@ -32,67 +32,71 @@ namespace Raul {
* \ingroup raul
*/
template<typename T>
-class DoubleBuffer {
+class DoubleBuffer
+{
public:
- explicit DoubleBuffer(T val)
- : _state(State::READ_WRITE)
- {
- _vals[0] = std::move(val);
- }
-
- DoubleBuffer(const DoubleBuffer&) = delete;
- DoubleBuffer& operator=(const DoubleBuffer&) = delete;
-
- DoubleBuffer(DoubleBuffer&&) = delete;
- DoubleBuffer& operator=(DoubleBuffer&&) = delete;
-
- ~DoubleBuffer() = default;
-
- inline const T& get() const {
- switch (_state.load(std::memory_order_acquire)) {
- case State::READ_WRITE:
- case State::READ_LOCK:
- return _vals[0];
- case State::WRITE_READ:
- case State::LOCK_READ:
- break;
- }
- return _vals[1];
- }
-
- inline bool set(T new_val) {
- if (transition(State::READ_WRITE, State::READ_LOCK)) {
- // Locked _vals[1] for writing
- _vals[1] = std::move(new_val);
- _state.store(State::WRITE_READ, std::memory_order_release);
- return true;
- }
-
- if (transition(State::WRITE_READ, State::LOCK_READ)) {
- // Locked _vals[0] for writing
- _vals[0] = std::move(new_val);
- _state.store(State::READ_WRITE, std::memory_order_release);
- return true;
- }
-
- return false;
- }
+ explicit DoubleBuffer(T val)
+ : _state(State::READ_WRITE)
+ {
+ _vals[0] = std::move(val);
+ }
+
+ DoubleBuffer(const DoubleBuffer&) = delete;
+ DoubleBuffer& operator=(const DoubleBuffer&) = delete;
+
+ DoubleBuffer(DoubleBuffer&&) = delete;
+ DoubleBuffer& operator=(DoubleBuffer&&) = delete;
+
+ ~DoubleBuffer() = default;
+
+ inline const T& get() const
+ {
+ switch (_state.load(std::memory_order_acquire)) {
+ case State::READ_WRITE:
+ case State::READ_LOCK:
+ return _vals[0];
+ case State::WRITE_READ:
+ case State::LOCK_READ:
+ break;
+ }
+ return _vals[1];
+ }
+
+ inline bool set(T new_val)
+ {
+ if (transition(State::READ_WRITE, State::READ_LOCK)) {
+ // Locked _vals[1] for writing
+ _vals[1] = std::move(new_val);
+ _state.store(State::WRITE_READ, std::memory_order_release);
+ return true;
+ }
+
+ if (transition(State::WRITE_READ, State::LOCK_READ)) {
+ // Locked _vals[0] for writing
+ _vals[0] = std::move(new_val);
+ _state.store(State::READ_WRITE, std::memory_order_release);
+ return true;
+ }
+
+ return false;
+ }
private:
- enum class State {
- READ_WRITE, ///< Read vals[0], Write vals[1]
- READ_LOCK, ///< Read vals[0], Lock vals[1]
- WRITE_READ, ///< Write vals[0], Read vals[1]
- LOCK_READ ///< Lock vals[0], Read vals[1]
- };
-
- bool transition(State from, const State to) {
- return _state.compare_exchange_strong(
- from, to, std::memory_order_release, std::memory_order_relaxed);
- }
-
- std::atomic<State> _state;
- T _vals[2];
+ enum class State {
+ READ_WRITE, ///< Read vals[0], Write vals[1]
+ READ_LOCK, ///< Read vals[0], Lock vals[1]
+ WRITE_READ, ///< Write vals[0], Read vals[1]
+ LOCK_READ ///< Lock vals[0], Read vals[1]
+ };
+
+ bool transition(State from, const State to)
+ {
+ return _state.compare_exchange_strong(
+ from, to, std::memory_order_release, std::memory_order_relaxed);
+ }
+
+ std::atomic<State> _state;
+ T _vals[2];
};
} // namespace Raul
diff --git a/include/raul/Exception.hpp b/include/raul/Exception.hpp
index 40a4382..919ece2 100644
--- a/include/raul/Exception.hpp
+++ b/include/raul/Exception.hpp
@@ -23,16 +23,19 @@
namespace Raul {
/** An exception (unexpected error). */
-class Exception : public std::exception {
+class Exception : public std::exception
+{
public:
- // NOLINTNEXTLINE(modernize-use-override, hicpp-use-override)
- const char* what() const noexcept final override { return _what.c_str(); }
+ // NOLINTNEXTLINE(modernize-use-override, hicpp-use-override)
+ const char* what() const noexcept final override { return _what.c_str(); }
protected:
- explicit Exception(std::string what) : _what(std::move(what)) {}
+ explicit Exception(std::string what)
+ : _what(std::move(what))
+ {}
private:
- const std::string _what;
+ const std::string _what;
};
} // namespace Raul
diff --git a/include/raul/Maid.hpp b/include/raul/Maid.hpp
index 1c1977f..9176d8b 100644
--- a/include/raul/Maid.hpp
+++ b/include/raul/Maid.hpp
@@ -38,118 +38,133 @@ namespace Raul {
class Maid : public Noncopyable
{
public:
- /** An object that can be disposed via Maid::dispose(). */
- class Disposable : public Deletable {
- public:
- Disposable() = default;
-
- Disposable(const Disposable&) = delete;
- Disposable& operator=(const Disposable&) = delete;
-
- Disposable(Disposable&&) = delete;
- Disposable& operator=(Disposable&&) = delete;
-
- ~Disposable() override = default;
-
- private:
- friend class Maid;
- Disposable* _maid_next{};
- };
-
- /** Disposable wrapper for any type. */
- template<typename T>
- class Managed : public Raul::Maid::Disposable, public T
- {
- public:
- template<typename... Args>
- explicit Managed(Args&&... args)
- : T(std::forward<Args>(args)...)
- {}
- };
-
- /** Deleter for Disposable objects. */
- template<typename T>
- class Disposer {
- public:
- explicit Disposer(Maid* maid) : _maid(maid) {}
-
- Disposer() = default;
-
- void operator()(T* obj) {
- if (_maid) { _maid->dispose(obj); }
- }
-
- private:
- Maid* _maid{nullptr};
- };
-
- /** A managed pointer that automatically disposes of its contents.
- *
- * This is a unique_ptr so that it is possible to statically verify that
- * code is real-time safe.
- */
- template<typename T> using managed_ptr = std::unique_ptr<T, Disposer<T>>;
-
- Maid() : _disposed(nullptr) {}
-
- Maid(const Maid&) = delete;
- Maid& operator=(const Maid&) = delete;
-
- Maid(Maid&&) = delete;
- Maid& operator=(Maid&&) = delete;
-
- inline ~Maid() { cleanup(); }
-
- /** Return false iff there is currently no garbage. */
- inline bool empty() const {
- return !_disposed.load(std::memory_order_relaxed);
- }
-
- /** Enqueue an object for deletion when cleanup() is called next.
- *
- * This is thread-safe, and real-time safe assuming reasonably low
- * contention.
- */
- inline void dispose(Disposable* obj) {
- if (obj) {
- // Atomically add obj to the head of the disposed list
- do {
- obj->_maid_next = _disposed.load(std::memory_order_relaxed);
- } while (!_disposed.compare_exchange_weak(
- obj->_maid_next, obj,
- std::memory_order_release,
- std::memory_order_relaxed));
- }
- }
-
- /** Delete all disposed objects immediately.
- *
- * Obviously not real-time safe, but may be called while other threads are
- * calling dispose().
- */
- inline void cleanup() {
- // Atomically get the head of the disposed list
- Disposable* const disposed = _disposed.exchange(
- nullptr, std::memory_order_acquire);
-
- // Free the disposed list
- for (Disposable* obj = disposed; obj;) {
- Disposable* const next = obj->_maid_next;
- delete obj;
- obj = next;
- }
- }
-
- /** Make a unique_ptr that will dispose its object when dropped. */
- template<class T, class... Args>
- managed_ptr<T> make_managed(Args&&... args) {
- return std::unique_ptr<T, Disposer<T> >(
- new T(std::forward<Args>(args)...),
- Disposer<T>(this));
- }
+ /** An object that can be disposed via Maid::dispose(). */
+ class Disposable : public Deletable
+ {
+ public:
+ Disposable() = default;
+
+ Disposable(const Disposable&) = delete;
+ Disposable& operator=(const Disposable&) = delete;
+
+ Disposable(Disposable&&) = delete;
+ Disposable& operator=(Disposable&&) = delete;
+
+ ~Disposable() override = default;
+
+ private:
+ friend class Maid;
+ Disposable* _maid_next{};
+ };
+
+ /** Disposable wrapper for any type. */
+ template<typename T>
+ class Managed
+ : public Raul::Maid::Disposable
+ , public T
+ {
+ public:
+ template<typename... Args>
+ explicit Managed(Args&&... args)
+ : T(std::forward<Args>(args)...)
+ {}
+ };
+
+ /** Deleter for Disposable objects. */
+ template<typename T>
+ class Disposer
+ {
+ public:
+ explicit Disposer(Maid* maid)
+ : _maid(maid)
+ {}
+
+ Disposer() = default;
+
+ void operator()(T* obj)
+ {
+ if (_maid) {
+ _maid->dispose(obj);
+ }
+ }
+
+ private:
+ Maid* _maid{nullptr};
+ };
+
+ /** A managed pointer that automatically disposes of its contents.
+ *
+ * This is a unique_ptr so that it is possible to statically verify that
+ * code is real-time safe.
+ */
+ template<typename T>
+ using managed_ptr = std::unique_ptr<T, Disposer<T>>;
+
+ Maid()
+ : _disposed(nullptr)
+ {}
+
+ Maid(const Maid&) = delete;
+ Maid& operator=(const Maid&) = delete;
+
+ Maid(Maid&&) = delete;
+ Maid& operator=(Maid&&) = delete;
+
+ inline ~Maid() { cleanup(); }
+
+ /** Return false iff there is currently no garbage. */
+ inline bool empty() const
+ {
+ return !_disposed.load(std::memory_order_relaxed);
+ }
+
+ /** Enqueue an object for deletion when cleanup() is called next.
+ *
+ * This is thread-safe, and real-time safe assuming reasonably low
+ * contention.
+ */
+ inline void dispose(Disposable* obj)
+ {
+ if (obj) {
+ // Atomically add obj to the head of the disposed list
+ do {
+ obj->_maid_next = _disposed.load(std::memory_order_relaxed);
+ } while (!_disposed.compare_exchange_weak(obj->_maid_next,
+ obj,
+ std::memory_order_release,
+ std::memory_order_relaxed));
+ }
+ }
+
+ /** Delete all disposed objects immediately.
+ *
+ * Obviously not real-time safe, but may be called while other threads are
+ * calling dispose().
+ */
+ inline void cleanup()
+ {
+ // Atomically get the head of the disposed list
+ Disposable* const disposed =
+ _disposed.exchange(nullptr, std::memory_order_acquire);
+
+ // Free the disposed list
+ for (Disposable* obj = disposed; obj;) {
+ Disposable* const next = obj->_maid_next;
+ delete obj;
+ obj = next;
+ }
+ }
+
+ /** Make a unique_ptr that will dispose its object when dropped. */
+ template<class T, class... Args>
+ managed_ptr<T> make_managed(Args&&... args)
+ {
+ return std::unique_ptr<T, Disposer<T>>(new T(std::forward<Args>(args)...),
+ Disposer<T>(this));
+ }
private:
- std::atomic<Disposable*> _disposed;
+ std::atomic<Disposable*> _disposed;
};
template<typename T>
diff --git a/include/raul/Noncopyable.hpp b/include/raul/Noncopyable.hpp
index 5ab4d82..6cfd0ed 100644
--- a/include/raul/Noncopyable.hpp
+++ b/include/raul/Noncopyable.hpp
@@ -18,17 +18,18 @@
namespace Raul {
-class Noncopyable {
+class Noncopyable
+{
public:
- Noncopyable(const Noncopyable&) = delete;
- const Noncopyable& operator=(const Noncopyable&) = delete;
+ Noncopyable(const Noncopyable&) = delete;
+ const Noncopyable& operator=(const Noncopyable&) = delete;
- Noncopyable(Noncopyable&&) = delete;
- Noncopyable& operator=(Noncopyable&&) = delete;
+ Noncopyable(Noncopyable&&) = delete;
+ Noncopyable& operator=(Noncopyable&&) = delete;
protected:
- Noncopyable() = default;
- ~Noncopyable() = default;
+ Noncopyable() = default;
+ ~Noncopyable() = default;
};
} // namespace Raul
diff --git a/include/raul/Path.hpp b/include/raul/Path.hpp
index f455049..8da985a 100644
--- a/include/raul/Path.hpp
+++ b/include/raul/Path.hpp
@@ -32,178 +32,195 @@ namespace Raul {
*
* @ingroup raul
*/
-class Path : public std::basic_string<char> {
+class Path : public std::basic_string<char>
+{
public:
- /** Attempt to construct an invalid Path. */
- class BadPath : public Exception {
- public:
- explicit BadPath(const std::string& path) : Exception(path) {}
- };
-
- /** Construct an uninitialzed path, because the STL is annoying. */
- Path() : std::basic_string<char>("/") {}
-
- /** Construct a Path from a C++ string.
- *
- * This will throw an exception if `path` is invalid. To avoid this, use
- * is_valid() first to check.
- */
- explicit Path(const std::basic_string<char>& path)
- : std::basic_string<char>(path)
- {
- if (!is_valid(path)) {
- throw BadPath(path);
- }
- }
-
- /** Construct a Path from a C string.
- *
- * This will throw an exception if `path` is invalid. To avoid this, use
- * is_valid() first to check.
- */
- explicit Path(const char* path)
- : std::basic_string<char>(path)
- {
- if (!is_valid(path)) {
- throw BadPath(path);
- }
- }
-
- Path(const Path& path) = default;
- Path& operator=(const Path& path) = default;
-
- Path(Path&& path) = default;
- Path& operator=(Path&& path) = default;
-
- ~Path() = default;
-
- /** Return true iff `c` is a valid Path character. */
- static inline bool is_valid_char(char c) {
- return c == '/' || Symbol::is_valid_char(c);
- }
-
- /** Return true iff `str` is a valid Path. */
- static inline bool is_valid(const std::basic_string<char>& str) {
- if (str.empty() || (str[0] != '/')) {
- return false; // Must start with '/'
- }
-
- if (str != "/" && *str.rbegin() == '/') {
- return false; // Must not end with '/' except for the root
- }
-
- for (size_t i = 1; i < str.length(); ++i) {
- if (!is_valid_char(str[i])) {
- return false; // All characters must be /, _, a-z, A-Z, 0-9
- }
-
- if (str[i - 1] == '/') {
- if (str[i] == '/') {
- return false; // Must not contain "//"
- }
-
- if (!Symbol::is_valid_start_char(str[i])) {
- return false; // Invalid symbol start character (digit)
- }
- }
- }
-
- return true;
- }
-
- /** Return true iff this path is the root path ("/"). */
- inline bool is_root() const { return *this == "/"; }
-
- /** Return true iff this path is a child of `parent` at any depth. */
- inline bool is_child_of(const Path& parent) const {
- const std::string parent_base = parent.base();
- return substr(0, parent_base.length()) == parent_base;
- }
-
- /** Return true iff this path is a parent of `child` at any depth. */
- inline bool is_parent_of(const Path& child) const {
- return child.is_child_of(*this);
- }
-
- /** Return the symbol of this path (everything after the last '/').
- *
- * This is what is called the "basename" for file paths, the "method name"
- * for OSC paths, and so on. Since the root path does not have a symbol,
- * this does not return a Raul::Symbol but may return the empty string.
- */
- inline const char* symbol() const {
- if (!is_root()) {
- const size_t last_sep = rfind('/');
- if (last_sep != std::string::npos) {
- return c_str() + last_sep + 1;
- }
- }
- return "";
- }
-
- /** Return the parent's path.
- *
- * Calling this on the path "/" will return "/".
- * This is the (deepest) "container path" for OSC paths.
- */
- inline Path parent() const {
- if (is_root()) {
- return *this;
- }
-
- const size_t first_sep = find('/');
- const size_t last_sep = find_last_of('/');
- return (first_sep == last_sep) ? Path("/") : Path(substr(0, last_sep));
- }
-
- /** Return a child Path of this path. */
- inline Path child(const Path& p) const {
- return p.is_root() ? *this : Path(base() + p.substr(1));
- }
-
- /** Return a direct child Path of this Path with the given Symbol. */
- inline Path child(const Raul::Symbol& symbol) const {
- return Path(base() + symbol.c_str());
- }
-
- /** Return path with a trailing "/".
- *
- * The returned string is such that appending a valid Symbol to it is
- * guaranteed to form a valid path.
- */
- inline std::string base() const {
- if (is_root()) {
- return *this;
- }
-
- return *this + '/';
- }
-
- /** Return the lowest common ancestor of a and b. */
- static inline Path lca(const Path& a, const Path& b) {
- const size_t len = std::min(a.length(), b.length());
- size_t last_sep = 0;
- for (size_t i = 0; i < len; ++i) {
- if (a[i] == '/' && b[i] == '/') {
- last_sep = i;
- }
- if (a[i] != b[i]) {
- break;
- }
- }
-
- if (last_sep <= 1) {
- return Path("/");
- }
-
- return Path(a.substr(0, last_sep));
- }
-
- /** Return true iff `child` is equal to, or a descendant of `parent`. */
- static inline bool descendant_comparator(const Path& parent,
- const Path& child) {
- return (child == parent || child.is_child_of(parent));
- }
+ /** Attempt to construct an invalid Path. */
+ class BadPath : public Exception
+ {
+ public:
+ explicit BadPath(const std::string& path)
+ : Exception(path)
+ {}
+ };
+
+ /** Construct an uninitialzed path, because the STL is annoying. */
+ Path()
+ : std::basic_string<char>("/")
+ {}
+
+ /** Construct a Path from a C++ string.
+ *
+ * This will throw an exception if `path` is invalid. To avoid this, use
+ * is_valid() first to check.
+ */
+ explicit Path(const std::basic_string<char>& path)
+ : std::basic_string<char>(path)
+ {
+ if (!is_valid(path)) {
+ throw BadPath(path);
+ }
+ }
+
+ /** Construct a Path from a C string.
+ *
+ * This will throw an exception if `path` is invalid. To avoid this, use
+ * is_valid() first to check.
+ */
+ explicit Path(const char* path)
+ : std::basic_string<char>(path)
+ {
+ if (!is_valid(path)) {
+ throw BadPath(path);
+ }
+ }
+
+ Path(const Path& path) = default;
+ Path& operator=(const Path& path) = default;
+
+ Path(Path&& path) = default;
+ Path& operator=(Path&& path) = default;
+
+ ~Path() = default;
+
+ /** Return true iff `c` is a valid Path character. */
+ static inline bool is_valid_char(char c)
+ {
+ return c == '/' || Symbol::is_valid_char(c);
+ }
+
+ /** Return true iff `str` is a valid Path. */
+ static inline bool is_valid(const std::basic_string<char>& str)
+ {
+ if (str.empty() || (str[0] != '/')) {
+ return false; // Must start with '/'
+ }
+
+ if (str != "/" && *str.rbegin() == '/') {
+ return false; // Must not end with '/' except for the root
+ }
+
+ for (size_t i = 1; i < str.length(); ++i) {
+ if (!is_valid_char(str[i])) {
+ return false; // All characters must be /, _, a-z, A-Z, 0-9
+ }
+
+ if (str[i - 1] == '/') {
+ if (str[i] == '/') {
+ return false; // Must not contain "//"
+ }
+
+ if (!Symbol::is_valid_start_char(str[i])) {
+ return false; // Invalid symbol start character (digit)
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /** Return true iff this path is the root path ("/"). */
+ inline bool is_root() const { return *this == "/"; }
+
+ /** Return true iff this path is a child of `parent` at any depth. */
+ inline bool is_child_of(const Path& parent) const
+ {
+ const std::string parent_base = parent.base();
+ return substr(0, parent_base.length()) == parent_base;
+ }
+
+ /** Return true iff this path is a parent of `child` at any depth. */
+ inline bool is_parent_of(const Path& child) const
+ {
+ return child.is_child_of(*this);
+ }
+
+ /** Return the symbol of this path (everything after the last '/').
+ *
+ * This is what is called the "basename" for file paths, the "method name"
+ * for OSC paths, and so on. Since the root path does not have a symbol,
+ * this does not return a Raul::Symbol but may return the empty string.
+ */
+ inline const char* symbol() const
+ {
+ if (!is_root()) {
+ const size_t last_sep = rfind('/');
+ if (last_sep != std::string::npos) {
+ return c_str() + last_sep + 1;
+ }
+ }
+ return "";
+ }
+
+ /** Return the parent's path.
+ *
+ * Calling this on the path "/" will return "/".
+ * This is the (deepest) "container path" for OSC paths.
+ */
+ inline Path parent() const
+ {
+ if (is_root()) {
+ return *this;
+ }
+
+ const size_t first_sep = find('/');
+ const size_t last_sep = find_last_of('/');
+ return (first_sep == last_sep) ? Path("/") : Path(substr(0, last_sep));
+ }
+
+ /** Return a child Path of this path. */
+ inline Path child(const Path& p) const
+ {
+ return p.is_root() ? *this : Path(base() + p.substr(1));
+ }
+
+ /** Return a direct child Path of this Path with the given Symbol. */
+ inline Path child(const Raul::Symbol& symbol) const
+ {
+ return Path(base() + symbol.c_str());
+ }
+
+ /** Return path with a trailing "/".
+ *
+ * The returned string is such that appending a valid Symbol to it is
+ * guaranteed to form a valid path.
+ */
+ inline std::string base() const
+ {
+ if (is_root()) {
+ return *this;
+ }
+
+ return *this + '/';
+ }
+
+ /** Return the lowest common ancestor of a and b. */
+ static inline Path lca(const Path& a, const Path& b)
+ {
+ const size_t len = std::min(a.length(), b.length());
+ size_t last_sep = 0;
+ for (size_t i = 0; i < len; ++i) {
+ if (a[i] == '/' && b[i] == '/') {
+ last_sep = i;
+ }
+ if (a[i] != b[i]) {
+ break;
+ }
+ }
+
+ if (last_sep <= 1) {
+ return Path("/");
+ }
+
+ return Path(a.substr(0, last_sep));
+ }
+
+ /** Return true iff `child` is equal to, or a descendant of `parent`. */
+ static inline bool descendant_comparator(const Path& parent,
+ const Path& child)
+ {
+ return (child == parent || child.is_child_of(parent));
+ }
};
} // namespace Raul
diff --git a/include/raul/Process.hpp b/include/raul/Process.hpp
index d77c3f3..1c5deed 100644
--- a/include/raul/Process.hpp
+++ b/include/raul/Process.hpp
@@ -30,52 +30,53 @@ namespace Raul {
class Process : Noncopyable
{
public:
- /** Launch a sub process.
- *
- * @param argv List of arguments, where argv[0] is the command name.
- * @return True on success.
- */
- static bool launch(const char* const argv[]) {
- // Use the same double fork() trick as JACK to prevent zombie children
- const int child = fork();
-
- if (child == 0) {
- // (in child)
-
- // Close all nonstandard file descriptors
- struct rlimit max_fds{};
- getrlimit(RLIMIT_NOFILE, &max_fds);
- for (rlim_t fd = 3; fd < max_fds.rlim_cur; ++fd) {
- close(static_cast<int>(fd));
- }
-
- // Fork child
- const int grandchild = fork();
- switch (grandchild) {
- case 0:
- // (in grandchild)
- setsid();
- execvp(argv[0], const_cast<char*const*>(argv));
- _exit(-1);
-
- case -1:
- // Fork failed, there is no grandchild
- _exit(-1);
-
- default:
- // Fork succeeded, return grandchild PID
- _exit(grandchild);
- }
- } else if (child < 0) {
- // Fork failed, there is no child
- return false;
- }
-
- return true;
- }
+ /** Launch a sub process.
+ *
+ * @param argv List of arguments, where argv[0] is the command name.
+ * @return True on success.
+ */
+ static bool launch(const char* const argv[])
+ {
+ // Use the same double fork() trick as JACK to prevent zombie children
+ const int child = fork();
+
+ if (child == 0) {
+ // (in child)
+
+ // Close all nonstandard file descriptors
+ struct rlimit max_fds {};
+ getrlimit(RLIMIT_NOFILE, &max_fds);
+ for (rlim_t fd = 3; fd < max_fds.rlim_cur; ++fd) {
+ close(static_cast<int>(fd));
+ }
+
+ // Fork child
+ const int grandchild = fork();
+ switch (grandchild) {
+ case 0:
+ // (in grandchild)
+ setsid();
+ execvp(argv[0], const_cast<char* const*>(argv));
+ _exit(-1);
+
+ case -1:
+ // Fork failed, there is no grandchild
+ _exit(-1);
+
+ default:
+ // Fork succeeded, return grandchild PID
+ _exit(grandchild);
+ }
+ } else if (child < 0) {
+ // Fork failed, there is no child
+ return false;
+ }
+
+ return true;
+ }
private:
- Process() = default;
+ Process() = default;
};
} // namespace Raul
diff --git a/include/raul/RingBuffer.hpp b/include/raul/RingBuffer.hpp
index 6c61d38..5460de2 100644
--- a/include/raul/RingBuffer.hpp
+++ b/include/raul/RingBuffer.hpp
@@ -34,187 +34,198 @@ namespace Raul {
@ingroup raul
*/
-class RingBuffer : public Noncopyable {
+class RingBuffer : public Noncopyable
+{
public:
- /**
- Create a new RingBuffer.
- @param size Size in bytes (note this may be rounded up).
- */
- explicit RingBuffer(uint32_t size)
- : _write_head(0)
- , _read_head(0)
- , _size(next_power_of_two(size))
- , _size_mask(_size - 1)
- , _buf(new char[_size])
- {
- assert(read_space() == 0);
- assert(write_space() == _size - 1);
- }
-
- RingBuffer(const RingBuffer&) = delete;
- RingBuffer& operator=(const RingBuffer&) = delete;
-
- RingBuffer(RingBuffer&&) = delete;
- RingBuffer& operator=(RingBuffer&&) = delete;
-
- ~RingBuffer() = default;
-
- /**
- Reset (empty) the RingBuffer.
-
- This method is NOT thread-safe, it may only be called when there are no
- readers or writers.
- */
- inline void reset() {
- _write_head = 0;
- _read_head = 0;
- }
-
- /**
- Return the number of bytes of space available for reading.
- */
- inline uint32_t read_space() const {
- return read_space_internal(_read_head, _write_head);
- }
-
- /**
- Return the number of bytes of space available for writing.
- */
- inline uint32_t write_space() const {
- return write_space_internal(_read_head, _write_head);
- }
-
- /**
- Return the capacity (i.e. total write space when empty).
- */
- inline uint32_t capacity() const { return _size - 1; }
-
- /**
- Read from the RingBuffer without advancing the read head.
- */
- inline uint32_t peek(uint32_t size, void* dst) {
- return peek_internal(_read_head, _write_head, size, dst);
- }
-
- /**
- Read from the RingBuffer and advance the read head.
- */
- inline uint32_t read(uint32_t size, void* dst) {
- const uint32_t r = _read_head;
- const uint32_t w = _write_head;
-
- if (peek_internal(r, w, size, dst)) {
- std::atomic_thread_fence(std::memory_order_acquire);
- _read_head = (r + size) & _size_mask;
- return size;
- }
-
- return 0;
- }
-
- /**
- Skip data in the RingBuffer (advance read head without reading).
- */
- inline uint32_t skip(uint32_t size) {
- const uint32_t r = _read_head;
- const uint32_t w = _write_head;
- if (read_space_internal(r, w) < size) {
- return 0;
- }
-
- std::atomic_thread_fence(std::memory_order_acquire);
- _read_head = (r + size) & _size_mask;
- return size;
- }
-
- /**
- Write data to the RingBuffer.
- */
- inline uint32_t write(uint32_t size, const void* src) {
- const uint32_t r = _read_head;
- const uint32_t w = _write_head;
- if (write_space_internal(r, w) < size) {
- return 0;
- }
-
- if (w + size <= _size) {
- memcpy(&_buf[w], src, size);
- std::atomic_thread_fence(std::memory_order_release);
- _write_head = (w + size) & _size_mask;
- } else {
- const uint32_t this_size = _size - w;
- assert(this_size < size);
- assert(w + this_size <= _size);
- memcpy(&_buf[w], src, this_size);
- memcpy(&_buf[0],
- static_cast<const char*>(src) + this_size,
- size - this_size);
- std::atomic_thread_fence(std::memory_order_release);
- _write_head = size - this_size;
- }
-
- return size;
- }
+ /**
+ Create a new RingBuffer.
+ @param size Size in bytes (note this may be rounded up).
+ */
+ explicit RingBuffer(uint32_t size)
+ : _write_head(0)
+ , _read_head(0)
+ , _size(next_power_of_two(size))
+ , _size_mask(_size - 1)
+ , _buf(new char[_size])
+ {
+ assert(read_space() == 0);
+ assert(write_space() == _size - 1);
+ }
+
+ RingBuffer(const RingBuffer&) = delete;
+ RingBuffer& operator=(const RingBuffer&) = delete;
+
+ RingBuffer(RingBuffer&&) = delete;
+ RingBuffer& operator=(RingBuffer&&) = delete;
+
+ ~RingBuffer() = default;
+
+ /**
+ Reset (empty) the RingBuffer.
+
+ This method is NOT thread-safe, it may only be called when there are no
+ readers or writers.
+ */
+ inline void reset()
+ {
+ _write_head = 0;
+ _read_head = 0;
+ }
+
+ /**
+ Return the number of bytes of space available for reading.
+ */
+ inline uint32_t read_space() const
+ {
+ return read_space_internal(_read_head, _write_head);
+ }
+
+ /**
+ Return the number of bytes of space available for writing.
+ */
+ inline uint32_t write_space() const
+ {
+ return write_space_internal(_read_head, _write_head);
+ }
+
+ /**
+ Return the capacity (i.e. total write space when empty).
+ */
+ inline uint32_t capacity() const { return _size - 1; }
+
+ /**
+ Read from the RingBuffer without advancing the read head.
+ */
+ inline uint32_t peek(uint32_t size, void* dst)
+ {
+ return peek_internal(_read_head, _write_head, size, dst);
+ }
+
+ /**
+ Read from the RingBuffer and advance the read head.
+ */
+ inline uint32_t read(uint32_t size, void* dst)
+ {
+ const uint32_t r = _read_head;
+ const uint32_t w = _write_head;
+
+ if (peek_internal(r, w, size, dst)) {
+ std::atomic_thread_fence(std::memory_order_acquire);
+ _read_head = (r + size) & _size_mask;
+ return size;
+ }
+
+ return 0;
+ }
+
+ /**
+ Skip data in the RingBuffer (advance read head without reading).
+ */
+ inline uint32_t skip(uint32_t size)
+ {
+ const uint32_t r = _read_head;
+ const uint32_t w = _write_head;
+ if (read_space_internal(r, w) < size) {
+ return 0;
+ }
+
+ std::atomic_thread_fence(std::memory_order_acquire);
+ _read_head = (r + size) & _size_mask;
+ return size;
+ }
+
+ /**
+ Write data to the RingBuffer.
+ */
+ inline uint32_t write(uint32_t size, const void* src)
+ {
+ const uint32_t r = _read_head;
+ const uint32_t w = _write_head;
+ if (write_space_internal(r, w) < size) {
+ return 0;
+ }
+
+ if (w + size <= _size) {
+ memcpy(&_buf[w], src, size);
+ std::atomic_thread_fence(std::memory_order_release);
+ _write_head = (w + size) & _size_mask;
+ } else {
+ const uint32_t this_size = _size - w;
+ assert(this_size < size);
+ assert(w + this_size <= _size);
+ memcpy(&_buf[w], src, this_size);
+ memcpy(
+ &_buf[0], static_cast<const char*>(src) + this_size, size - this_size);
+ std::atomic_thread_fence(std::memory_order_release);
+ _write_head = size - this_size;
+ }
+
+ return size;
+ }
private:
- static inline uint32_t next_power_of_two(uint32_t size) {
- // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
- size--;
- size |= size >> 1U;
- size |= size >> 2U;
- size |= size >> 4U;
- size |= size >> 8U;
- size |= size >> 16U;
- size++;
- return size;
- }
-
- inline uint32_t write_space_internal(uint32_t r, uint32_t w) const {
- if (r == w) {
- return _size - 1;
- }
-
- if (r < w) {
- return ((r - w + _size) & _size_mask) - 1;
- }
-
- return (r - w) - 1;
- }
-
- inline uint32_t read_space_internal(uint32_t r, uint32_t w) const {
- if (r < w) {
- return w - r;
- }
-
- return (w - r + _size) & _size_mask;
- }
-
- inline uint32_t peek_internal(uint32_t r, uint32_t w,
- uint32_t size, void* dst) const {
- if (read_space_internal(r, w) < size) {
- return 0;
- }
-
- if (r + size < _size) {
- memcpy(dst, &_buf[r], size);
- } else {
- const uint32_t first_size = _size - r;
- memcpy(dst, &_buf[r], first_size);
- memcpy(static_cast<char*>(dst) + first_size,
- &_buf[0],
- size - first_size);
- }
-
- return size;
- }
-
- mutable uint32_t _write_head; ///< Read index into _buf
- mutable uint32_t _read_head; ///< Write index into _buf
-
- const uint32_t _size; ///< Size (capacity) in bytes
- const uint32_t _size_mask; ///< Mask for fast modulo
-
- const std::unique_ptr<char[]> _buf; ///< Contents
+ static inline uint32_t next_power_of_two(uint32_t size)
+ {
+ // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ size--;
+ size |= size >> 1U;
+ size |= size >> 2U;
+ size |= size >> 4U;
+ size |= size >> 8U;
+ size |= size >> 16U;
+ size++;
+ return size;
+ }
+
+ inline uint32_t write_space_internal(uint32_t r, uint32_t w) const
+ {
+ if (r == w) {
+ return _size - 1;
+ }
+
+ if (r < w) {
+ return ((r - w + _size) & _size_mask) - 1;
+ }
+
+ return (r - w) - 1;
+ }
+
+ inline uint32_t read_space_internal(uint32_t r, uint32_t w) const
+ {
+ if (r < w) {
+ return w - r;
+ }
+
+ return (w - r + _size) & _size_mask;
+ }
+
+ inline uint32_t peek_internal(uint32_t r,
+ uint32_t w,
+ uint32_t size,
+ void* dst) const
+ {
+ if (read_space_internal(r, w) < size) {
+ return 0;
+ }
+
+ if (r + size < _size) {
+ memcpy(dst, &_buf[r], size);
+ } else {
+ const uint32_t first_size = _size - r;
+ memcpy(dst, &_buf[r], first_size);
+ memcpy(static_cast<char*>(dst) + first_size, &_buf[0], size - first_size);
+ }
+
+ return size;
+ }
+
+ mutable uint32_t _write_head; ///< Read index into _buf
+ mutable uint32_t _read_head; ///< Write index into _buf
+
+ const uint32_t _size; ///< Size (capacity) in bytes
+ const uint32_t _size_mask; ///< Mask for fast modulo
+
+ const std::unique_ptr<char[]> _buf; ///< Contents
};
} // namespace Raul
diff --git a/include/raul/Semaphore.hpp b/include/raul/Semaphore.hpp
index f87dac3..5e9303b 100644
--- a/include/raul/Semaphore.hpp
+++ b/include/raul/Semaphore.hpp
@@ -17,14 +17,14 @@
#define RAUL_SEMAPHORE_HPP
#ifdef __APPLE__
-# include <mach/mach.h>
+# include <mach/mach.h>
#elif defined(_WIN32)
-# define NOMINMAX
-# include <windows.h>
+# define NOMINMAX
+# include <windows.h>
#else
-# include <cerrno>
-# include <ctime>
-# include <semaphore.h>
+# include <cerrno>
+# include <ctime>
+# include <semaphore.h>
#endif
#include <chrono>
@@ -47,58 +47,57 @@ namespace Raul {
class Semaphore
{
public:
- /**
- Create a new semaphore.
+ /**
+ Create a new semaphore.
- Chances are you want 1 wait() per 1 post(), an initial value of 0.
- */
- explicit Semaphore(unsigned initial)
- : _sem()
- {
- if (!init(initial)) {
- throw std::runtime_error("Failed to create semaphore");
- }
- }
+ Chances are you want 1 wait() per 1 post(), an initial value of 0.
+ */
+ explicit Semaphore(unsigned initial)
+ : _sem()
+ {
+ if (!init(initial)) {
+ throw std::runtime_error("Failed to create semaphore");
+ }
+ }
- inline Semaphore(const Semaphore&) = delete;
- inline Semaphore& operator=(const Semaphore&) = delete;
+ inline Semaphore(const Semaphore&) = delete;
+ inline Semaphore& operator=(const Semaphore&) = delete;
- inline Semaphore(Semaphore&&) = delete;
- inline Semaphore& operator=(Semaphore&&) = delete;
+ inline Semaphore(Semaphore&&) = delete;
+ inline Semaphore& operator=(Semaphore&&) = delete;
- inline ~Semaphore() {
- destroy();
- }
+ inline ~Semaphore() { destroy(); }
- /** Destroy and reset to a new initial value. */
- inline void reset(unsigned initial) {
- destroy();
- init(initial);
- }
+ /** Destroy and reset to a new initial value. */
+ inline void reset(unsigned initial)
+ {
+ destroy();
+ init(initial);
+ }
- /** Post/Increment/Signal */
- inline void post();
+ /** Post/Increment/Signal */
+ inline void post();
- /** Wait/Decrement. Return false on error. */
- inline bool wait();
+ /** Wait/Decrement. Return false on error. */
+ inline bool wait();
- /** Attempt Wait/Decrement. Return true iff decremented. */
- inline bool try_wait();
+ /** Attempt Wait/Decrement. Return true iff decremented. */
+ inline bool try_wait();
- /** Wait for at most `ms` milliseconds. Return true iff decremented. */
- template<class Rep, class Period>
- inline bool timed_wait(const std::chrono::duration<Rep, Period>& wait);
+ /** Wait for at most `ms` milliseconds. Return true iff decremented. */
+ template<class Rep, class Period>
+ inline bool timed_wait(const std::chrono::duration<Rep, Period>& wait);
private:
- inline bool init(unsigned initial);
- inline void destroy();
+ inline bool init(unsigned initial);
+ inline void destroy();
#if defined(__APPLE__)
- semaphore_t _sem; // sem_t is a worthless broken mess on OSX
+ semaphore_t _sem; // sem_t is a worthless broken mess on OSX
#elif defined(_WIN32)
- HANDLE _sem; // types are overrated anyway
+ HANDLE _sem; // types are overrated anyway
#else
- sem_t _sem;
+ sem_t _sem;
#endif
};
@@ -107,52 +106,55 @@ private:
inline bool
Semaphore::init(unsigned initial)
{
- if (semaphore_create(mach_task_self(), &_sem, SYNC_POLICY_FIFO, int(initial))) {
- return false;
- }
- return true;
+ if (semaphore_create(
+ mach_task_self(), &_sem, SYNC_POLICY_FIFO, int(initial))) {
+ return false;
+ }
+ return true;
}
inline void
Semaphore::destroy()
{
- semaphore_destroy(mach_task_self(), _sem);
+ semaphore_destroy(mach_task_self(), _sem);
}
inline void
Semaphore::post()
{
- semaphore_signal(_sem);
+ semaphore_signal(_sem);
}
inline bool
Semaphore::wait()
{
- if (semaphore_wait(_sem) != KERN_SUCCESS) {
- return false;
- }
- return true;
+ if (semaphore_wait(_sem) != KERN_SUCCESS) {
+ return false;
+ }
+
+ return true;
}
inline bool
Semaphore::try_wait()
{
- const mach_timespec_t zero = { 0, 0 };
- return semaphore_timedwait(_sem, zero) == KERN_SUCCESS;
+ const mach_timespec_t zero = {0, 0};
+ return semaphore_timedwait(_sem, zero) == KERN_SUCCESS;
}
template<class Rep, class Period>
inline bool
Semaphore::timed_wait(const std::chrono::duration<Rep, Period>& wait)
{
- namespace chr = std::chrono;
+ namespace chr = std::chrono;
+
+ const chr::seconds sec(chr::duration_cast<chr::seconds>(wait));
+ const chr::nanoseconds nsec(wait - sec);
- const chr::seconds sec(chr::duration_cast<chr::seconds>(wait));
- const chr::nanoseconds nsec(wait - sec);
+ const mach_timespec_t t = {static_cast<unsigned>(sec.count()),
+ static_cast<int>(nsec.count())};
- const mach_timespec_t t = { static_cast<unsigned>(sec.count()),
- static_cast<int>(nsec.count()) };
- return semaphore_timedwait(_sem, t) == KERN_SUCCESS;
+ return semaphore_timedwait(_sem, t) == KERN_SUCCESS;
}
#elif defined(_WIN32)
@@ -160,109 +162,111 @@ Semaphore::timed_wait(const std::chrono::duration<Rep, Period>& wait)
inline bool
Semaphore::init(unsigned initial)
{
- if (!(_sem = CreateSemaphore(NULL, (LONG)initial, LONG_MAX, NULL))) {
- return false;
- }
- return true;
+ if (!(_sem = CreateSemaphore(NULL, (LONG)initial, LONG_MAX, NULL))) {
+ return false;
+ }
+
+ return true;
}
inline void
Semaphore::destroy()
{
- CloseHandle(_sem);
+ CloseHandle(_sem);
}
inline void
Semaphore::post()
{
- ReleaseSemaphore(_sem, 1, NULL);
+ ReleaseSemaphore(_sem, 1, NULL);
}
inline bool
Semaphore::wait()
{
- if (WaitForSingleObject(_sem, INFINITE) != WAIT_OBJECT_0) {
- return false;
- }
- return true;
+ if (WaitForSingleObject(_sem, INFINITE) != WAIT_OBJECT_0) {
+ return false;
+ }
+
+ return true;
}
inline bool
Semaphore::try_wait()
{
- return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0;
+ return WaitForSingleObject(_sem, 0) == WAIT_OBJECT_0;
}
template<class Rep, class Period>
inline bool
Semaphore::timed_wait(const std::chrono::duration<Rep, Period>& wait)
{
- namespace chr = std::chrono;
+ namespace chr = std::chrono;
- const chr::milliseconds ms(chr::duration_cast<chr::milliseconds>(wait));
- return WaitForSingleObject(
- _sem, static_cast<DWORD>(ms.count())) == WAIT_OBJECT_0;
+ const chr::milliseconds ms(chr::duration_cast<chr::milliseconds>(wait));
+ return WaitForSingleObject(_sem, static_cast<DWORD>(ms.count())) ==
+ WAIT_OBJECT_0;
}
-#else /* !defined(__APPLE__) && !defined(_WIN32) */
+#else /* !defined(__APPLE__) && !defined(_WIN32) */
inline bool
Semaphore::init(unsigned initial)
{
- return !sem_init(&_sem, 0, initial);
+ return !sem_init(&_sem, 0, initial);
}
inline void
Semaphore::destroy()
{
- sem_destroy(&_sem);
+ sem_destroy(&_sem);
}
inline void
Semaphore::post()
{
- sem_post(&_sem);
+ sem_post(&_sem);
}
inline bool
Semaphore::wait()
{
- while (sem_wait(&_sem)) {
- if (errno != EINTR) {
- return false; // We are all doomed
- }
- /* Otherwise, interrupted (rare/weird), so try again. */
- }
-
- return true;
+ while (sem_wait(&_sem)) {
+ if (errno != EINTR) {
+ return false; // We are all doomed
+ }
+ /* Otherwise, interrupted (rare/weird), so try again. */
+ }
+
+ return true;
}
inline bool
Semaphore::try_wait()
{
- return (sem_trywait(&_sem) == 0);
+ return (sem_trywait(&_sem) == 0);
}
template<class Rep, class Period>
inline bool
Semaphore::timed_wait(const std::chrono::duration<Rep, Period>& wait)
{
- namespace chr = std::chrono;
+ namespace chr = std::chrono;
- // Use clock_gettime to ensure sem_timedwait uses the same clock
- struct timespec time{};
- clock_gettime(CLOCK_REALTIME, &time);
+ // Use clock_gettime to ensure sem_timedwait uses the same clock
+ struct timespec time {};
+ clock_gettime(CLOCK_REALTIME, &time);
- const auto now(chr::seconds(time.tv_sec) + chr::nanoseconds(time.tv_nsec));
- const auto end(now + wait);
+ const auto now(chr::seconds(time.tv_sec) + chr::nanoseconds(time.tv_nsec));
+ const auto end(now + wait);
- const chr::seconds end_sec(chr::duration_cast<chr::seconds>(end));
- const chr::nanoseconds end_nsec(end - end_sec);
+ const chr::seconds end_sec(chr::duration_cast<chr::seconds>(end));
+ const chr::nanoseconds end_nsec(end - end_sec);
- const struct timespec ts_end = { static_cast<time_t>(end_sec.count()),
- static_cast<long>(end_nsec.count()) };
+ const struct timespec ts_end = {static_cast<time_t>(end_sec.count()),
+ static_cast<long>(end_nsec.count())};
- return (sem_timedwait(&_sem, &ts_end) == 0);
+ return (sem_timedwait(&_sem, &ts_end) == 0);
}
#endif
diff --git a/include/raul/Socket.hpp b/include/raul/Socket.hpp
index 2a67fd3..7da3555 100644
--- a/include/raul/Socket.hpp
+++ b/include/raul/Socket.hpp
@@ -32,229 +32,228 @@
namespace Raul {
/** A safe and simple interface for UNIX or TCP sockets. */
-class Socket : public Raul::Noncopyable {
+class Socket : public Raul::Noncopyable
+{
public:
- enum class Type {
- UNIX,
- TCP
- };
-
- /** Create a new unbound/unconnected socket of a given type. */
- explicit Socket(Type t);
-
- /** Wrap an existing open socket. */
- Socket(Type t,
- std::string uri,
- struct sockaddr* addr,
- socklen_t addr_len,
- int fd);
-
- Socket(const Socket&) = delete;
- Socket& operator=(const Socket&) = delete;
-
- Socket(Socket&&) = delete;
- Socket& operator=(Socket&&) = delete;
-
- ~Socket();
-
- /** Bind a server socket to an address.
- * @param uri Address URI, e.g. unix:///tmp/foo, or tcp://hostname:1234.
- * Use "*" as hostname to listen on all interfaces.
- * @return True on success.
- */
- bool bind(const std::string& uri);
-
- /** Connect a client socket to a server address.
- * @param uri Address URI, e.g. unix:///tmp/foo or tcp://somehost:1234
- * @return True on success.
- */
- bool connect(const std::string& uri);
-
- /** Mark server socket as passive to listen for incoming connections.
- * @return True on success.
- */
- bool listen();
-
- /** Accept a connection.
- * @return An new open socket for the connection.
- */
- std::shared_ptr<Socket> accept();
-
- /** Return the file descriptor for the socket. */
- int fd() const { return _sock; }
-
- const std::string& uri() const { return _uri; }
-
- /** Close the socket. */
- void close();
-
- /** Shut down the socket.
- * This terminates any connections associated with the sockets, and will
- * (unlike close()) cause a poll on the socket to return.
- */
- void shutdown();
+ enum class Type { UNIX, TCP };
+
+ /** Create a new unbound/unconnected socket of a given type. */
+ explicit Socket(Type t);
+
+ /** Wrap an existing open socket. */
+ Socket(Type t,
+ std::string uri,
+ struct sockaddr* addr,
+ socklen_t addr_len,
+ int fd);
+
+ Socket(const Socket&) = delete;
+ Socket& operator=(const Socket&) = delete;
+
+ Socket(Socket&&) = delete;
+ Socket& operator=(Socket&&) = delete;
+
+ ~Socket();
+
+ /** Bind a server socket to an address.
+ * @param uri Address URI, e.g. unix:///tmp/foo, or tcp://hostname:1234.
+ * Use "*" as hostname to listen on all interfaces.
+ * @return True on success.
+ */
+ bool bind(const std::string& uri);
+
+ /** Connect a client socket to a server address.
+ * @param uri Address URI, e.g. unix:///tmp/foo or tcp://somehost:1234
+ * @return True on success.
+ */
+ bool connect(const std::string& uri);
+
+ /** Mark server socket as passive to listen for incoming connections.
+ * @return True on success.
+ */
+ bool listen();
+
+ /** Accept a connection.
+ * @return An new open socket for the connection.
+ */
+ std::shared_ptr<Socket> accept();
+
+ /** Return the file descriptor for the socket. */
+ int fd() const { return _sock; }
+
+ const std::string& uri() const { return _uri; }
+
+ /** Close the socket. */
+ void close();
+
+ /** Shut down the socket.
+ * This terminates any connections associated with the sockets, and will
+ * (unlike close()) cause a poll on the socket to return.
+ */
+ void shutdown();
private:
- bool set_addr(const std::string& uri);
+ bool set_addr(const std::string& uri);
- std::string _uri;
- struct sockaddr* _addr;
- socklen_t _addr_len;
- Type _type;
- int _sock;
+ std::string _uri;
+ struct sockaddr* _addr;
+ socklen_t _addr_len;
+ Type _type;
+ int _sock;
};
#ifndef NI_MAXHOST
-# define NI_MAXHOST 1025
+# define NI_MAXHOST 1025
#endif
-inline
-Socket::Socket(Type t)
- : _uri(t == Type::UNIX ? "unix:" : "tcp:")
- , _addr(nullptr)
- , _addr_len(0)
- , _type(t)
- , _sock(-1)
+inline Socket::Socket(Type t)
+ : _uri(t == Type::UNIX ? "unix:" : "tcp:")
+ , _addr(nullptr)
+ , _addr_len(0)
+ , _type(t)
+ , _sock(-1)
{
- switch (t) {
- case Type::UNIX:
- _sock = socket(AF_UNIX, SOCK_STREAM, 0);
- break;
- case Type::TCP:
- _sock = socket(AF_INET, SOCK_STREAM, 0);
- break;
- }
+ switch (t) {
+ case Type::UNIX:
+ _sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ break;
+ case Type::TCP:
+ _sock = socket(AF_INET, SOCK_STREAM, 0);
+ break;
+ }
}
-inline
-Socket::Socket(Type t,
- std::string uri,
- struct sockaddr* addr,
- socklen_t addr_len,
- int fd)
+inline Socket::Socket(Type t,
+ std::string uri,
+ struct sockaddr* addr,
+ socklen_t addr_len,
+ int fd)
: _uri(std::move(uri))
, _addr(addr)
, _addr_len(addr_len)
, _type(t)
, _sock(fd)
-{
-}
+{}
-inline
-Socket::~Socket()
+inline Socket::~Socket()
{
- free(_addr);
- close();
+ free(_addr);
+ close();
}
inline bool
Socket::set_addr(const std::string& uri)
{
- free(_addr);
- if (_type == Type::UNIX && uri.substr(0, strlen("unix://")) == "unix://") {
- const std::string path = uri.substr(strlen("unix://"));
- auto* uaddr = static_cast<struct sockaddr_un*>(
- calloc(1, sizeof(struct sockaddr_un)));
- uaddr->sun_family = AF_UNIX;
- strncpy(uaddr->sun_path, path.c_str(), sizeof(uaddr->sun_path) - 1);
- _uri = uri;
- _addr = reinterpret_cast<sockaddr*>(uaddr);
- _addr_len = sizeof(struct sockaddr_un);
- return true;
- }
-
- if (_type == Type::TCP && uri.find("://") != std::string::npos) {
- const std::string authority = uri.substr(uri.find("://") + 3);
- const size_t port_sep = authority.find(':');
- if (port_sep == std::string::npos) {
- return false;
- }
-
- std::string host = authority.substr(0, port_sep);
- const std::string port = authority.substr(port_sep + 1);
- if (host.empty() || host == "*") {
- host = "0.0.0.0"; // INADDR_ANY
- }
-
- struct addrinfo* ainfo = nullptr;
- if (getaddrinfo(host.c_str(), port.c_str(), nullptr, &ainfo)) {
- return false;
- }
-
- _uri = uri;
- _addr = static_cast<struct sockaddr*>(malloc(ainfo->ai_addrlen));
- _addr_len = ainfo->ai_addrlen;
- memcpy(_addr, ainfo->ai_addr, ainfo->ai_addrlen);
- freeaddrinfo(ainfo);
- return true;
- }
-
- return false;
+ free(_addr);
+ if (_type == Type::UNIX && uri.substr(0, strlen("unix://")) == "unix://") {
+ const std::string path = uri.substr(strlen("unix://"));
+ auto* uaddr =
+ static_cast<struct sockaddr_un*>(calloc(1, sizeof(struct sockaddr_un)));
+ uaddr->sun_family = AF_UNIX;
+ strncpy(uaddr->sun_path, path.c_str(), sizeof(uaddr->sun_path) - 1);
+ _uri = uri;
+ _addr = reinterpret_cast<sockaddr*>(uaddr);
+ _addr_len = sizeof(struct sockaddr_un);
+ return true;
+ }
+
+ if (_type == Type::TCP && uri.find("://") != std::string::npos) {
+ const std::string authority = uri.substr(uri.find("://") + 3);
+ const size_t port_sep = authority.find(':');
+ if (port_sep == std::string::npos) {
+ return false;
+ }
+
+ std::string host = authority.substr(0, port_sep);
+ const std::string port = authority.substr(port_sep + 1);
+ if (host.empty() || host == "*") {
+ host = "0.0.0.0"; // INADDR_ANY
+ }
+
+ struct addrinfo* ainfo = nullptr;
+ if (getaddrinfo(host.c_str(), port.c_str(), nullptr, &ainfo)) {
+ return false;
+ }
+
+ _uri = uri;
+ _addr = static_cast<struct sockaddr*>(malloc(ainfo->ai_addrlen));
+ _addr_len = ainfo->ai_addrlen;
+ memcpy(_addr, ainfo->ai_addr, ainfo->ai_addrlen);
+ freeaddrinfo(ainfo);
+ return true;
+ }
+
+ return false;
}
inline bool
Socket::bind(const std::string& uri)
{
- return set_addr(uri) && ::bind(_sock, _addr, _addr_len) != -1;
+ return set_addr(uri) && ::bind(_sock, _addr, _addr_len) != -1;
}
inline bool
Socket::connect(const std::string& uri)
{
- return set_addr(uri) && ::connect(_sock, _addr, _addr_len) != -1;
+ return set_addr(uri) && ::connect(_sock, _addr, _addr_len) != -1;
}
inline bool
Socket::listen() // NOLINT(readability-make-member-function-const)
{
- return ::listen(_sock, 64) != -1;
+ return ::listen(_sock, 64) != -1;
}
inline std::shared_ptr<Socket>
Socket::accept()
{
- socklen_t client_addr_len = _addr_len;
- auto* const client_addr =
- static_cast<struct sockaddr*>(calloc(1, client_addr_len));
-
- const int conn = ::accept(_sock, client_addr, &client_addr_len);
- if (conn == -1) {
- free(client_addr);
- return std::shared_ptr<Socket>();
- }
-
- std::string client_uri = _uri;
- if (_type != Type::UNIX) {
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
- if (!getnameinfo(client_addr, client_addr_len,
- host, sizeof(host), serv, sizeof(serv), 0)) {
- const std::string scheme = _uri.substr(0, _uri.find(':'));
- client_uri = scheme + "://" + host + ":" + serv;
- }
- }
-
- return std::make_shared<Socket>(
- _type, client_uri, client_addr, client_addr_len, conn);
+ socklen_t client_addr_len = _addr_len;
+ auto* const client_addr =
+ static_cast<struct sockaddr*>(calloc(1, client_addr_len));
+
+ const int conn = ::accept(_sock, client_addr, &client_addr_len);
+ if (conn == -1) {
+ free(client_addr);
+ return std::shared_ptr<Socket>();
+ }
+
+ std::string client_uri = _uri;
+ if (_type != Type::UNIX) {
+ char host[NI_MAXHOST];
+ char serv[NI_MAXSERV];
+ if (!getnameinfo(client_addr,
+ client_addr_len,
+ host,
+ sizeof(host),
+ serv,
+ sizeof(serv),
+ 0)) {
+ const std::string scheme = _uri.substr(0, _uri.find(':'));
+ client_uri = scheme + "://" + host + ":" + serv;
+ }
+ }
+
+ return std::make_shared<Socket>(
+ _type, client_uri, client_addr, client_addr_len, conn);
}
inline void
Socket::close()
{
- if (_sock != -1) {
- ::close(_sock);
- _sock = -1;
- }
+ if (_sock != -1) {
+ ::close(_sock);
+ _sock = -1;
+ }
}
inline void
Socket::shutdown() // NOLINT(readability-make-member-function-const)
{
- if (_sock != -1) {
- ::shutdown(_sock, SHUT_RDWR);
- }
+ if (_sock != -1) {
+ ::shutdown(_sock, SHUT_RDWR);
+ }
}
-} // namespace Raul
+} // namespace Raul
-#endif // RAUL_SOCKET_HPP
+#endif // RAUL_SOCKET_HPP
diff --git a/include/raul/Symbol.hpp b/include/raul/Symbol.hpp
index ff593ff..30917b5 100644
--- a/include/raul/Symbol.hpp
+++ b/include/raul/Symbol.hpp
@@ -34,96 +34,104 @@ namespace Raul {
*
* @ingroup raul
*/
-class Symbol : public std::basic_string<char> {
+class Symbol : public std::basic_string<char>
+{
public:
- /** Attempt to construct an invalid Symbol. */
- class BadSymbol : public Exception {
- public:
- explicit BadSymbol(const std::string& symbol) : Exception(symbol) {}
- };
-
- /** Construct a Symbol from a C++ string.
- *
- * This will throw an exception if `symbol` is invalid. To avoid this,
- * use is_valid() first to check.
- */
- explicit Symbol(const std::basic_string<char>& symbol)
- : std::basic_string<char>(symbol)
- {
- if (!is_valid(symbol)) {
- throw BadSymbol(symbol);
- }
- }
-
- /** Construct a Symbol from a C string.
- *
- * This will throw an exception if `symbol` is invalid. To avoid this,
- * use is_valid() first to check.
- */
- explicit Symbol(const char* symbol)
- : std::basic_string<char>(symbol)
- {
- if (!is_valid(symbol)) {
- throw BadSymbol(symbol);
- }
- }
-
- Symbol(const Symbol& symbol) = default;
- Symbol& operator=(const Symbol& symbol) = default;
-
- Symbol(Symbol&& symbol) = default;
- Symbol& operator=(Symbol&& symbol) = default;
-
- ~Symbol() = default;
-
- /** Return true iff `c` is a valid Symbol start character. */
- static inline bool is_valid_start_char(char c) {
- return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
- }
-
- /** Return true iff `c` is a valid Symbol character. */
- static inline bool is_valid_char(char c) {
- return is_valid_start_char(c) || (c >= '0' && c <= '9');
- }
-
- /** Return true iff `str` is a valid Symbol. */
- static inline bool is_valid(const std::basic_string<char>& str) {
- if (str.empty() || (str[0] >= '0' && str[0] <= '9')) {
- return false; // Must start with a letter or underscore
- }
-
- for (auto c : str) {
- if (!is_valid_char(c)) {
- return false; // All characters must be _, a-z, A-Z, 0-9
- }
- }
-
- return true;
- }
-
- /** Convert a string to a valid symbol.
- *
- * This will make a best effort at turning `str` into a complete, valid
- * Symbol, and will always return one.
- */
- static inline Symbol symbolify(const std::basic_string<char>& in) {
- if (in.empty()) {
- return Symbol("_");
- }
-
- std::basic_string<char> out(in);
- for (size_t i = 0; i < in.length(); ++i) {
- if (!is_valid_char(out[i])) {
- out[i] = '_';
- }
- }
-
- if (is_valid_start_char(out[0])) {
- return Symbol(out);
- }
-
- return Symbol(std::string("_") + out);
- }
+ /** Attempt to construct an invalid Symbol. */
+ class BadSymbol : public Exception
+ {
+ public:
+ explicit BadSymbol(const std::string& symbol)
+ : Exception(symbol)
+ {}
+ };
+
+ /** Construct a Symbol from a C++ string.
+ *
+ * This will throw an exception if `symbol` is invalid. To avoid this,
+ * use is_valid() first to check.
+ */
+ explicit Symbol(const std::basic_string<char>& symbol)
+ : std::basic_string<char>(symbol)
+ {
+ if (!is_valid(symbol)) {
+ throw BadSymbol(symbol);
+ }
+ }
+
+ /** Construct a Symbol from a C string.
+ *
+ * This will throw an exception if `symbol` is invalid. To avoid this,
+ * use is_valid() first to check.
+ */
+ explicit Symbol(const char* symbol)
+ : std::basic_string<char>(symbol)
+ {
+ if (!is_valid(symbol)) {
+ throw BadSymbol(symbol);
+ }
+ }
+
+ Symbol(const Symbol& symbol) = default;
+ Symbol& operator=(const Symbol& symbol) = default;
+
+ Symbol(Symbol&& symbol) = default;
+ Symbol& operator=(Symbol&& symbol) = default;
+
+ ~Symbol() = default;
+
+ /** Return true iff `c` is a valid Symbol start character. */
+ static inline bool is_valid_start_char(char c)
+ {
+ return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+ }
+
+ /** Return true iff `c` is a valid Symbol character. */
+ static inline bool is_valid_char(char c)
+ {
+ return is_valid_start_char(c) || (c >= '0' && c <= '9');
+ }
+
+ /** Return true iff `str` is a valid Symbol. */
+ static inline bool is_valid(const std::basic_string<char>& str)
+ {
+ if (str.empty() || (str[0] >= '0' && str[0] <= '9')) {
+ return false; // Must start with a letter or underscore
+ }
+
+ for (auto c : str) {
+ if (!is_valid_char(c)) {
+ return false; // All characters must be _, a-z, A-Z, 0-9
+ }
+ }
+
+ return true;
+ }
+
+ /** Convert a string to a valid symbol.
+ *
+ * This will make a best effort at turning `str` into a complete, valid
+ * Symbol, and will always return one.
+ */
+ static inline Symbol symbolify(const std::basic_string<char>& in)
+ {
+ if (in.empty()) {
+ return Symbol("_");
+ }
+
+ std::basic_string<char> out(in);
+ for (size_t i = 0; i < in.length(); ++i) {
+ if (!is_valid_char(out[i])) {
+ out[i] = '_';
+ }
+ }
+
+ if (is_valid_start_char(out[0])) {
+ return Symbol(out);
+ }
+
+ return Symbol(std::string("_") + out);
+ }
};
} // namespace Raul
diff --git a/include/raul/TimeSlice.hpp b/include/raul/TimeSlice.hpp
index 90eb7d4..3efa180 100644
--- a/include/raul/TimeSlice.hpp
+++ b/include/raul/TimeSlice.hpp
@@ -44,111 +44,122 @@ namespace Raul {
*
* \ingroup raul
*/
-class TimeSlice : public Noncopyable {
+class TimeSlice : public Noncopyable
+{
public:
- TimeSlice(uint32_t rate, uint32_t ppqn, double bpm)
- : _tick_rate(rate)
- , _beat_rate(60.0/bpm)
- , _start_ticks(Raul::TimeUnit(Raul::TimeUnit::FRAMES, rate), 0, 0)
- , _length_ticks(TimeUnit(TimeUnit::FRAMES, rate), 0, 0)
- , _start_beats(TimeUnit(TimeUnit::BEATS, ppqn), 0, 0)
- , _length_beats(TimeUnit(TimeUnit::BEATS, ppqn), 0, 0)
- , _offset_ticks(TimeUnit(TimeUnit::FRAMES, rate), 0, 0)
- {}
-
- /** Set the start and length of the slice.
- *
- * Note that external offset is not affected by this, don't forget to reset
- * the offset each cycle!
- */
- void set_slice(TimeStamp start, TimeDuration length) {
- assert(start.unit() == ticks_unit());
- assert(length.unit() == ticks_unit());
- _start_ticks = start;
- _length_ticks = length;
- update_beat_time();
- }
-
- void set_length(TimeDuration length) {
- assert(length.unit() == ticks_unit());
- _length_ticks = length;
- _length_beats = ticks_to_beats(_length_ticks);
- }
-
- bool contains(TimeStamp time) const {
- return (time >= start_ticks() && time < start_ticks() + length_ticks());
- }
-
- double tick_rate() const { return _tick_rate; }
- double beat_rate() const { return _beat_rate; }
- double bpm() const { return 60/_beat_rate; }
-
- void set_tick_rate(double tick_rate) {
- _tick_rate = tick_rate;
- update_beat_time();
- }
-
- void set_bpm(double bpm) {
- _beat_rate = 60.0/bpm;
- update_beat_time();
- }
-
- inline TimeStamp beats_to_seconds(TimeStamp beats) const {
- return {real_unit(), beats.to_double() * 1/_beat_rate};
- }
-
- inline TimeStamp beats_to_ticks(TimeStamp beats) const {
- return {ticks_unit(), beats.to_double() * _beat_rate * _tick_rate};
- }
-
- inline TimeStamp ticks_to_seconds(TimeStamp ticks) const {
- return {real_unit(), ticks.ticks() * 1/_tick_rate};
- }
-
- inline TimeStamp ticks_to_beats(TimeStamp ticks) const {
- return {beats_unit(), ticks.ticks() * 1/_tick_rate * _beat_rate};
- }
-
- /** Start of current sub-cycle in ticks */
- inline TimeStamp start_ticks() const { return _start_ticks; }
-
- /** Length of current sub-cycle in ticks */
- inline TimeDuration length_ticks() const { return _length_ticks; }
-
- /** Start of current sub-cycle in beats */
- inline TimeStamp start_beats() const { return _start_beats; }
-
- /** Length of current sub-cycle in beats */
- inline TimeDuration length_beats() const { return _length_beats; }
-
- /** Set the offset between real-time and timeslice-time. */
- inline void set_offset(TimeDuration offset) { _offset_ticks = offset; }
-
- /** Offset relative to external (e.g Jack) time */
- inline TimeDuration offset_ticks() const { return _offset_ticks; }
-
- inline TimeUnit beats_unit() const { return _start_beats.unit(); }
- inline TimeUnit ticks_unit() const { return _start_ticks.unit(); }
-
- static inline TimeUnit real_unit() { return {TimeUnit::SECONDS, 0}; }
+ TimeSlice(uint32_t rate, uint32_t ppqn, double bpm)
+ : _tick_rate(rate)
+ , _beat_rate(60.0 / bpm)
+ , _start_ticks(Raul::TimeUnit(Raul::TimeUnit::FRAMES, rate), 0, 0)
+ , _length_ticks(TimeUnit(TimeUnit::FRAMES, rate), 0, 0)
+ , _start_beats(TimeUnit(TimeUnit::BEATS, ppqn), 0, 0)
+ , _length_beats(TimeUnit(TimeUnit::BEATS, ppqn), 0, 0)
+ , _offset_ticks(TimeUnit(TimeUnit::FRAMES, rate), 0, 0)
+ {}
+
+ /** Set the start and length of the slice.
+ *
+ * Note that external offset is not affected by this, don't forget to reset
+ * the offset each cycle!
+ */
+ void set_slice(TimeStamp start, TimeDuration length)
+ {
+ assert(start.unit() == ticks_unit());
+ assert(length.unit() == ticks_unit());
+ _start_ticks = start;
+ _length_ticks = length;
+ update_beat_time();
+ }
+
+ void set_length(TimeDuration length)
+ {
+ assert(length.unit() == ticks_unit());
+ _length_ticks = length;
+ _length_beats = ticks_to_beats(_length_ticks);
+ }
+
+ bool contains(TimeStamp time) const
+ {
+ return (time >= start_ticks() && time < start_ticks() + length_ticks());
+ }
+
+ double tick_rate() const { return _tick_rate; }
+ double beat_rate() const { return _beat_rate; }
+ double bpm() const { return 60 / _beat_rate; }
+
+ void set_tick_rate(double tick_rate)
+ {
+ _tick_rate = tick_rate;
+ update_beat_time();
+ }
+
+ void set_bpm(double bpm)
+ {
+ _beat_rate = 60.0 / bpm;
+ update_beat_time();
+ }
+
+ inline TimeStamp beats_to_seconds(TimeStamp beats) const
+ {
+ return {real_unit(), beats.to_double() * 1 / _beat_rate};
+ }
+
+ inline TimeStamp beats_to_ticks(TimeStamp beats) const
+ {
+ return {ticks_unit(), beats.to_double() * _beat_rate * _tick_rate};
+ }
+
+ inline TimeStamp ticks_to_seconds(TimeStamp ticks) const
+ {
+ return {real_unit(), ticks.ticks() * 1 / _tick_rate};
+ }
+
+ inline TimeStamp ticks_to_beats(TimeStamp ticks) const
+ {
+ return {beats_unit(), ticks.ticks() * 1 / _tick_rate * _beat_rate};
+ }
+
+ /** Start of current sub-cycle in ticks */
+ inline TimeStamp start_ticks() const { return _start_ticks; }
+
+ /** Length of current sub-cycle in ticks */
+ inline TimeDuration length_ticks() const { return _length_ticks; }
+
+ /** Start of current sub-cycle in beats */
+ inline TimeStamp start_beats() const { return _start_beats; }
+
+ /** Length of current sub-cycle in beats */
+ inline TimeDuration length_beats() const { return _length_beats; }
+
+ /** Set the offset between real-time and timeslice-time. */
+ inline void set_offset(TimeDuration offset) { _offset_ticks = offset; }
+
+ /** Offset relative to external (e.g Jack) time */
+ inline TimeDuration offset_ticks() const { return _offset_ticks; }
+
+ inline TimeUnit beats_unit() const { return _start_beats.unit(); }
+ inline TimeUnit ticks_unit() const { return _start_ticks.unit(); }
+
+ static inline TimeUnit real_unit() { return {TimeUnit::SECONDS, 0}; }
private:
- inline void update_beat_time() {
- _start_beats = ticks_to_beats(_start_ticks);
- _length_beats = ticks_to_beats(_length_ticks);
- }
-
- // Rate/Tempo
- double _tick_rate; ///< Tick rate in Hz (e.g. sample rate)
- double _beat_rate; ///< Beat rate in Hz
-
- // Current time
- TimeStamp _start_ticks; ///< Current window start in ticks
- TimeDuration _length_ticks; ///< Current window length in ticks
- TimeStamp _start_beats; ///< Current window start in beats
- TimeDuration _length_beats; ///< Current window length in beats
-
- TimeDuration _offset_ticks; ///< Offset to global time
+ inline void update_beat_time()
+ {
+ _start_beats = ticks_to_beats(_start_ticks);
+ _length_beats = ticks_to_beats(_length_ticks);
+ }
+
+ // Rate/Tempo
+ double _tick_rate; ///< Tick rate in Hz (e.g. sample rate)
+ double _beat_rate; ///< Beat rate in Hz
+
+ // Current time
+ TimeStamp _start_ticks; ///< Current window start in ticks
+ TimeDuration _length_ticks; ///< Current window length in ticks
+ TimeStamp _start_beats; ///< Current window start in beats
+ TimeDuration _length_beats; ///< Current window length in beats
+
+ TimeDuration _offset_ticks; ///< Offset to global time
};
} // namespace Raul
diff --git a/include/raul/TimeStamp.hpp b/include/raul/TimeStamp.hpp
index 01cc294..0385ef3 100644
--- a/include/raul/TimeStamp.hpp
+++ b/include/raul/TimeStamp.hpp
@@ -28,44 +28,46 @@ namespace Raul {
/** A type of time stamp
* \ingroup raul
*/
-class TimeUnit {
+class TimeUnit
+{
public:
- enum Type {
- FRAMES,
- BEATS,
- SECONDS
- };
-
- /** `ppt` (parts per tick) is the sample rate for FRAMES, PPQN for BEATS,
- * and ignored for SECONDS.
- */
- inline TimeUnit(Type type, uint32_t ppt)
- : _type(type)
- , _ppt(ppt)
- {
- assert(type == SECONDS || ppt != 0);
- _type = type;
- _ppt = ppt;
- }
-
- static inline TimeUnit frames(uint32_t srate) { return {FRAMES, srate}; }
- static inline TimeUnit beats(uint32_t ppqn) { return {BEATS, ppqn}; }
- static inline TimeUnit seconds() { return {BEATS, std::numeric_limits<uint32_t>::max()}; }
-
- inline Type type() const { return _type; }
- inline uint32_t ppt() const { return _ppt; }
-
- inline bool operator==(const TimeUnit& rhs) const {
- return (_type == rhs._type && _ppt == rhs._ppt);
- }
-
- inline bool operator!=(const TimeUnit& rhs) const {
- return (_type != rhs._type || _ppt != rhs._ppt);
- }
+ enum Type { FRAMES, BEATS, SECONDS };
+
+ /** `ppt` (parts per tick) is the sample rate for FRAMES, PPQN for BEATS,
+ * and ignored for SECONDS.
+ */
+ inline TimeUnit(Type type, uint32_t ppt)
+ : _type(type)
+ , _ppt(ppt)
+ {
+ assert(type == SECONDS || ppt != 0);
+ _type = type;
+ _ppt = ppt;
+ }
+
+ static inline TimeUnit frames(uint32_t srate) { return {FRAMES, srate}; }
+ static inline TimeUnit beats(uint32_t ppqn) { return {BEATS, ppqn}; }
+ static inline TimeUnit seconds()
+ {
+ return {BEATS, std::numeric_limits<uint32_t>::max()};
+ }
+
+ inline Type type() const { return _type; }
+ inline uint32_t ppt() const { return _ppt; }
+
+ inline bool operator==(const TimeUnit& rhs) const
+ {
+ return (_type == rhs._type && _ppt == rhs._ppt);
+ }
+
+ inline bool operator!=(const TimeUnit& rhs) const
+ {
+ return (_type != rhs._type || _ppt != rhs._ppt);
+ }
private:
- Type _type;
- uint32_t _ppt;
+ Type _type;
+ uint32_t _ppt;
};
/** A real-time time stamp (possible units: frame, absolute (s), or beat).
@@ -77,158 +79,170 @@ private:
*
* \ingroup raul
*/
-class TimeStamp {
+class TimeStamp
+{
public:
- explicit TimeStamp(TimeUnit unit, uint32_t ticks = 0, uint32_t subticks = 0)
- : _ticks(ticks)
- , _subticks(subticks)
- , _unit(unit)
- {}
-
- inline TimeStamp(TimeUnit unit, double dec)
- : _ticks(0u)
- , _subticks(0u)
- , _unit(unit)
- {
- dec = std::max(0.0, dec);
- dec = std::min(double(std::numeric_limits<uint32_t>::max()), dec);
- double integral = 0.0;
- const double fractional = modf(dec, &integral);
- _ticks = static_cast<uint32_t>(integral);
- _subticks = static_cast<uint32_t>(fractional * unit.ppt());
- }
-
- TimeStamp(const TimeStamp&) = default;
- TimeStamp& operator=(const TimeStamp&) = default;
-
- TimeStamp(TimeStamp&&) = default;
- TimeStamp& operator=(TimeStamp&&) = default;
-
- ~TimeStamp() = default;
-
- inline TimeUnit unit() const { return _unit; }
- inline uint32_t ticks() const { return _ticks; }
- inline uint32_t subticks() const { return _subticks; }
-
- inline double to_double() const {
- return _ticks + (_subticks / static_cast<double>(_unit.ppt()));
- }
-
- inline bool is_zero() const {
- return _ticks == 0 && _subticks == 0;
- }
-
- inline TimeStamp& operator=(uint32_t ticks) {
- _ticks = ticks;
- _subticks = 0;
- return *this;
- }
-
- inline bool operator==(const TimeStamp& rhs) const {
- return _ticks == rhs._ticks
- && _subticks == rhs._subticks
- && _unit == rhs._unit;
- }
-
- inline bool operator!=(const TimeStamp& rhs) const {
- return !operator==(rhs);
- }
-
- inline bool operator<(const TimeStamp& rhs) const {
- assert(_unit == rhs._unit);
- return (_ticks < rhs._ticks
- || (_ticks == rhs._ticks && _subticks < rhs._subticks));
- }
-
- inline bool operator>(const TimeStamp& rhs) const {
- assert(_unit == rhs._unit);
- return (_ticks > rhs._ticks
- || (_ticks == rhs._ticks && _subticks > rhs._subticks));
- }
-
- inline bool operator<=(const TimeStamp& rhs) const {
- return (*this == rhs) || ((*this) < rhs);
- }
-
- inline bool operator>=(const TimeStamp& rhs) const {
- return (*this == rhs) || ((*this) > rhs);
- }
-
- inline TimeStamp& operator+=(const TimeStamp& rhs) {
- assert(_unit == rhs._unit);
- _ticks += rhs._ticks;
- if (_subticks + rhs._subticks <= _unit.ppt()) {
- _subticks += rhs._subticks;
- } else if (rhs._subticks > 0) {
- ++_ticks;
- _subticks = rhs._subticks + _subticks - _unit.ppt();
- }
- return *this;
- }
-
- inline TimeStamp& operator-=(const TimeStamp& rhs) {
- assert(_unit == rhs._unit);
- assert(rhs <= *this);
- _ticks -= rhs._ticks;
- if (_subticks >= rhs._subticks) {
- _subticks -= rhs._subticks;
- } else if (rhs._subticks > 0) {
- --_ticks;
- _subticks = _unit.ppt() - (rhs._subticks - _subticks);
- }
- return *this;
- }
-
- inline TimeStamp operator+(const TimeStamp& rhs) const {
- assert(_unit == rhs._unit);
- TimeStamp result = *this;
- result += rhs;
- return result;
- }
-
- inline TimeStamp operator-(const TimeStamp& rhs) const {
- assert(_unit == rhs._unit);
- TimeStamp result = *this;
- result -= rhs;
- return result;
- }
+ explicit TimeStamp(TimeUnit unit, uint32_t ticks = 0, uint32_t subticks = 0)
+ : _ticks(ticks)
+ , _subticks(subticks)
+ , _unit(unit)
+ {}
+
+ inline TimeStamp(TimeUnit unit, double dec)
+ : _ticks(0u)
+ , _subticks(0u)
+ , _unit(unit)
+ {
+ dec = std::max(0.0, dec);
+ dec = std::min(double(std::numeric_limits<uint32_t>::max()), dec);
+ double integral = 0.0;
+ const double fractional = modf(dec, &integral);
+ _ticks = static_cast<uint32_t>(integral);
+ _subticks = static_cast<uint32_t>(fractional * unit.ppt());
+ }
+
+ TimeStamp(const TimeStamp&) = default;
+ TimeStamp& operator=(const TimeStamp&) = default;
+
+ TimeStamp(TimeStamp&&) = default;
+ TimeStamp& operator=(TimeStamp&&) = default;
+
+ ~TimeStamp() = default;
+
+ inline TimeUnit unit() const { return _unit; }
+ inline uint32_t ticks() const { return _ticks; }
+ inline uint32_t subticks() const { return _subticks; }
+
+ inline double to_double() const
+ {
+ return _ticks + (_subticks / static_cast<double>(_unit.ppt()));
+ }
+
+ inline bool is_zero() const { return _ticks == 0 && _subticks == 0; }
+
+ inline TimeStamp& operator=(uint32_t ticks)
+ {
+ _ticks = ticks;
+ _subticks = 0;
+ return *this;
+ }
+
+ inline bool operator==(const TimeStamp& rhs) const
+ {
+ return _ticks == rhs._ticks && _subticks == rhs._subticks &&
+ _unit == rhs._unit;
+ }
+
+ inline bool operator!=(const TimeStamp& rhs) const
+ {
+ return !operator==(rhs);
+ }
+
+ inline bool operator<(const TimeStamp& rhs) const
+ {
+ assert(_unit == rhs._unit);
+ return (_ticks < rhs._ticks ||
+ (_ticks == rhs._ticks && _subticks < rhs._subticks));
+ }
+
+ inline bool operator>(const TimeStamp& rhs) const
+ {
+ assert(_unit == rhs._unit);
+ return (_ticks > rhs._ticks ||
+ (_ticks == rhs._ticks && _subticks > rhs._subticks));
+ }
+
+ inline bool operator<=(const TimeStamp& rhs) const
+ {
+ return (*this == rhs) || ((*this) < rhs);
+ }
+
+ inline bool operator>=(const TimeStamp& rhs) const
+ {
+ return (*this == rhs) || ((*this) > rhs);
+ }
+
+ inline TimeStamp& operator+=(const TimeStamp& rhs)
+ {
+ assert(_unit == rhs._unit);
+ _ticks += rhs._ticks;
+ if (_subticks + rhs._subticks <= _unit.ppt()) {
+ _subticks += rhs._subticks;
+ } else if (rhs._subticks > 0) {
+ ++_ticks;
+ _subticks = rhs._subticks + _subticks - _unit.ppt();
+ }
+ return *this;
+ }
+
+ inline TimeStamp& operator-=(const TimeStamp& rhs)
+ {
+ assert(_unit == rhs._unit);
+ assert(rhs <= *this);
+ _ticks -= rhs._ticks;
+ if (_subticks >= rhs._subticks) {
+ _subticks -= rhs._subticks;
+ } else if (rhs._subticks > 0) {
+ --_ticks;
+ _subticks = _unit.ppt() - (rhs._subticks - _subticks);
+ }
+ return *this;
+ }
+
+ inline TimeStamp operator+(const TimeStamp& rhs) const
+ {
+ assert(_unit == rhs._unit);
+ TimeStamp result = *this;
+ result += rhs;
+ return result;
+ }
+
+ inline TimeStamp operator-(const TimeStamp& rhs) const
+ {
+ assert(_unit == rhs._unit);
+ TimeStamp result = *this;
+ result -= rhs;
+ return result;
+ }
private:
- uint32_t _ticks;
- uint32_t _subticks;
- TimeUnit _unit;
+ uint32_t _ticks;
+ uint32_t _subticks;
+ TimeUnit _unit;
};
inline std::ostream&
operator<<(std::ostream& os, const TimeStamp& t)
{
- os << t.ticks() << ":" << t.subticks();
- switch (t.unit().type()) {
- case TimeUnit::FRAMES:
- os << " frames";
- break;
- case TimeUnit::BEATS:
- os << " beats";
- break;
- case TimeUnit::SECONDS:
- os << " seconds";
- break;
- }
- return os;
+ os << t.ticks() << ":" << t.subticks();
+ switch (t.unit().type()) {
+ case TimeUnit::FRAMES:
+ os << " frames";
+ break;
+ case TimeUnit::BEATS:
+ os << " beats";
+ break;
+ case TimeUnit::SECONDS:
+ os << " seconds";
+ break;
+ }
+ return os;
}
-class FrameStamp : public TimeStamp {
+class FrameStamp : public TimeStamp
+{
public:
- explicit FrameStamp(uint32_t rate, uint32_t ticks = 0, uint32_t subticks = 0)
- : TimeStamp(TimeUnit(TimeUnit::FRAMES, rate), ticks, subticks)
- {}
+ explicit FrameStamp(uint32_t rate, uint32_t ticks = 0, uint32_t subticks = 0)
+ : TimeStamp(TimeUnit(TimeUnit::FRAMES, rate), ticks, subticks)
+ {}
};
-class BeatStamp : public TimeStamp {
+class BeatStamp : public TimeStamp
+{
public:
- explicit BeatStamp(uint32_t ppqn, uint32_t ticks = 0, uint32_t subticks = 0)
- : TimeStamp(TimeUnit(TimeUnit::BEATS, ppqn), ticks, subticks)
- {}
+ explicit BeatStamp(uint32_t ppqn, uint32_t ticks = 0, uint32_t subticks = 0)
+ : TimeStamp(TimeUnit(TimeUnit::BEATS, ppqn), ticks, subticks)
+ {}
};
/** Same thing as TimeStamp really, but makes code clearer and enforces