diff options
author | Sven Gothel <[email protected]> | 2020-09-14 20:13:35 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-09-14 20:13:35 +0200 |
commit | c10af68a6d94fd901a938b60c843c6ee0ba8af84 (patch) | |
tree | 98bd3a4b5f0cfaeac4d2b9813e4dd06ebbc03c5e | |
parent | 410ed5c924b665beced35ab1d51b7277a5b0aff9 (diff) |
C++ noexcept: Ringbuffer and its LFRingbuffer implementation
-rw-r--r-- | api/direct_bt/LFRingbuffer.hpp | 85 | ||||
-rw-r--r-- | api/direct_bt/Ringbuffer.hpp | 42 |
2 files changed, 70 insertions, 57 deletions
diff --git a/api/direct_bt/LFRingbuffer.hpp b/api/direct_bt/LFRingbuffer.hpp index ebaaa6a0..e2af5d4d 100644 --- a/api/direct_bt/LFRingbuffer.hpp +++ b/api/direct_bt/LFRingbuffer.hpp @@ -36,6 +36,8 @@ #include <chrono> #include <algorithm> +#include "dbt_debug.hpp" + #include "BasicTypes.hpp" #include "Ringbuffer.hpp" @@ -92,14 +94,14 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb std::atomic<int> writePos; std::atomic<int> size; - T * newArray(const int count) { + T * newArray(const int count) noexcept { return new T[count]; } - void freeArray(T * a) { + void freeArray(T * a) noexcept { delete[] a; } - void cloneFrom(const bool allocArrayAndCapacity, const LFRingbuffer & source) { + void cloneFrom(const bool allocArrayAndCapacity, const LFRingbuffer & source) noexcept { if( allocArrayAndCapacity ) { capacityPlusOne = source.capacityPlusOne; if( nullptr != array ) { @@ -123,7 +125,7 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb } } - void resetImpl(const T * copyFrom, const int copyFromCount) /* throws IllegalArgumentException */ { + void clearImpl() noexcept { // clear all elements, zero size if( 0 < size ) { int localReadPos = readPos; @@ -132,16 +134,27 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb array[localReadPos] = nullelem; } if( writePos != localReadPos ) { - throw InternalError("copy segment error: this "+toString()+", localReadPos "+std::to_string(localReadPos)+"; source count "+std::to_string(copyFromCount), E_FILE_LINE); + // Avoid exception, abort! + ERR_PRINT("Internal Error: copy segment error: this %s, readPos %d/%d; writePos %d", + toString().c_str(), readPos.load(), localReadPos, writePos.load()); + abort(); } readPos = localReadPos; size = 0; } + } + + void resetImpl(const T * copyFrom, const int copyFromCount) noexcept { + clearImpl(); // fill with copyFrom elements if( nullptr != copyFrom && 0 < copyFromCount ) { if( copyFromCount > capacityPlusOne-1 ) { - throw IllegalArgumentException("copyFrom array length "+std::to_string(copyFromCount)+" > capacity "+toString(), E_FILE_LINE); + // new blank resized array + capacityPlusOne = copyFromCount + 1; + array = newArray(capacityPlusOne); + readPos = 0; + writePos = 0; } int localWritePos = writePos; for(int i=0; i<copyFromCount; i++) { @@ -153,7 +166,7 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb } } - T getImpl(const bool blocking, const bool peek, const int timeoutMS) { + T getImpl(const bool blocking, const bool peek, const int timeoutMS) noexcept { std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor int localReadPos = readPos; @@ -189,7 +202,7 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb return r; } - int dropImpl (const int count) { + int dropImpl (const int count) noexcept { // locks ringbuffer completely (read/write), hence no need for local copy nor wait/sync etc std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto @@ -207,7 +220,7 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb return dropCount; } - bool putImpl(const T &e, const bool sameRef, const bool blocking, const int timeoutMS) /* throws InterruptedException */ { + bool putImpl(const T &e, const bool sameRef, const bool blocking, const int timeoutMS) noexcept { std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // RAII-style acquire and relinquish via destructor int localWritePos = writePos; @@ -243,14 +256,14 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb } public: - std::string toString() const override { + std::string toString() const noexcept override { const std::string es = isEmpty() ? ", empty" : ""; const std::string fs = isFull() ? ", full" : ""; return "LFRingbuffer<?>[size "+std::to_string(size)+" / "+std::to_string(capacityPlusOne-1)+ ", writePos "+std::to_string(writePos)+", readPos "+std::to_string(readPos)+es+fs+"]"; } - void dump(FILE *stream, std::string prefix) const override { + void dump(FILE *stream, std::string prefix) const noexcept override { fprintf(stream, "%s %s {\n", prefix.c_str(), toString().c_str()); for(int i=0; i<capacityPlusOne; i++) { // fprintf(stream, "\t[%d]: %p\n", i, array[i].get()); // FIXME @@ -278,14 +291,14 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb * @param copyFrom mandatory source array determining ring buffer's net {@link #capacity()} and initial content. * @throws IllegalArgumentException if <code>copyFrom</code> is <code>nullptr</code> */ - LFRingbuffer(const std::vector<T> & copyFrom) /* throws IllegalArgumentException */ + LFRingbuffer(const std::vector<T> & copyFrom) noexcept : capacityPlusOne(copyFrom.size() + 1), array(newArray(capacityPlusOne)), readPos(0), writePos(0), size(0) { resetImpl(copyFrom.data(), copyFrom.size()); } - LFRingbuffer(const T * copyFrom, const int copyFromSize) /* throws IllegalArgumentException */ + LFRingbuffer(const T * copyFrom, const int copyFromSize) noexcept : capacityPlusOne(copyFromSize + 1), array(newArray(capacityPlusOne)), readPos(0), writePos(0), size(0) { @@ -309,12 +322,12 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb * @param arrayType the array type of the created empty internal array. * @param capacity the initial net capacity of the ring buffer */ - LFRingbuffer(const int capacity) + LFRingbuffer(const int capacity) noexcept : capacityPlusOne(capacity + 1), array(newArray(capacityPlusOne)), readPos(0), writePos(0), size(0) { } - ~LFRingbuffer() { + ~LFRingbuffer() noexcept { freeArray(array); } @@ -329,7 +342,7 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb cloneFrom(false, _source); } - LFRingbuffer& operator=(const LFRingbuffer &_source) { + LFRingbuffer& operator=(const LFRingbuffer &_source) noexcept { std::unique_lock<std::mutex> lockMultiReadS(_source.syncMultiRead); std::unique_lock<std::mutex> lockMultiWriteS(_source.syncMultiWrite); std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); @@ -341,7 +354,7 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb if( capacityPlusOne != _source.capacityPlusOne ) { cloneFrom(true, _source); } else { - resetImpl(nullptr, 0 /* empty, nothing to copy */ ); // clear + clearImpl(); // clear cloneFrom(false, _source); } return *this; @@ -350,69 +363,69 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb LFRingbuffer(LFRingbuffer &&o) noexcept = default; LFRingbuffer& operator=(LFRingbuffer &&o) noexcept = default; - int capacity() const override { return capacityPlusOne-1; } + int capacity() const noexcept override { return capacityPlusOne-1; } - void clear() override { + void clear() noexcept override { std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto - resetImpl(nullptr, 0 /* empty, nothing to copy */ ); + clearImpl(); } - void reset(const T * copyFrom, const int copyFromCount) override { + void reset(const T * copyFrom, const int copyFromCount) noexcept override { std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto resetImpl(copyFrom, copyFromCount); } - void reset(const std::vector<T> & copyFrom) override { + void reset(const std::vector<T> & copyFrom) noexcept override { std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto resetImpl(copyFrom.data(), copyFrom.size()); } - int getSize() const override { return size; } + int getSize() const noexcept override { return size; } - int getFreeSlots() const override { return capacityPlusOne - 1 - size; } + int getFreeSlots() const noexcept override { return capacityPlusOne - 1 - size; } - bool isEmpty() const override { return writePos == readPos; /* 0 == size */ } + bool isEmpty() const noexcept override { return writePos == readPos; /* 0 == size */ } - bool isFull() const override { return ( writePos + 1 ) % capacityPlusOne == readPos ; /* capacityPlusOne - 1 == size */; } + bool isFull() const noexcept override { return ( writePos + 1 ) % capacityPlusOne == readPos ; /* capacityPlusOne - 1 == size */; } - T get() override { return getImpl(false, false, 0); } + T get() noexcept override { return getImpl(false, false, 0); } - T getBlocking(const int timeoutMS=0) override /* throws InterruptedException */ { + T getBlocking(const int timeoutMS=0) noexcept override { return getImpl(true, false, timeoutMS); } - T peek() override { + T peek() noexcept override { return getImpl(false, true, 0); } - T peekBlocking(const int timeoutMS=0) override /* throws InterruptedException */ { + T peekBlocking(const int timeoutMS=0) noexcept override { return getImpl(true, true, timeoutMS); } - int drop(const int count) override { + int drop(const int count) noexcept override { return dropImpl(count); } - bool put(const T & e) override { + bool put(const T & e) noexcept override { return putImpl(e, false, false, 0); } - bool putBlocking(const T & e, const int timeoutMS=0) override { + bool putBlocking(const T & e, const int timeoutMS=0) noexcept override { return !putImpl(e, false, true, timeoutMS); } - bool putSame() override { + bool putSame() noexcept override { return putImpl(nullelem, true, false, 0); } - bool putSameBlocking(const int timeoutMS=0) override { + bool putSameBlocking(const int timeoutMS=0) noexcept override { return putImpl(nullelem, true, true, timeoutMS); } - void waitForFreeSlots(const int count) override /* throws InterruptedException */ { + void waitForFreeSlots(const int count) noexcept override { std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // RAII-style acquire and relinquish via destructor std::unique_lock<std::mutex> lockRead(syncRead); // RAII-style acquire and relinquish via destructor diff --git a/api/direct_bt/Ringbuffer.hpp b/api/direct_bt/Ringbuffer.hpp index 4a4c525c..2ea326de 100644 --- a/api/direct_bt/Ringbuffer.hpp +++ b/api/direct_bt/Ringbuffer.hpp @@ -51,16 +51,16 @@ namespace direct_bt { */ template <class T> class Ringbuffer { public: - virtual ~Ringbuffer() {} + virtual ~Ringbuffer() noexcept {} /** Returns a short string representation incl. size/capacity and internal r/w index (impl. dependent). */ - virtual std::string toString() const = 0; + virtual std::string toString() const noexcept = 0; /** Debug functionality - Dumps the contents of the internal array. */ - virtual void dump(FILE *stream, std::string prefix) const = 0; + virtual void dump(FILE *stream, std::string prefix) const noexcept = 0; /** Returns the net capacity of this ring buffer. */ - virtual int capacity() const = 0; + virtual int capacity() const noexcept = 0; /** * Releasing all elements by assigning <code>null</code>. @@ -69,26 +69,26 @@ template <class T> class Ringbuffer { * {@link #getSize()} will return <code>0</code> after calling this method. * </p> */ - virtual void clear() = 0; + virtual void clear() noexcept = 0; /** * {@link #clear()} all elements and add all <code>copyFrom</code> elements thereafter. * @param copyFrom Mandatory array w/ length {@link #capacity()} to be copied into the internal array. */ - virtual void reset(const T * copyFrom, const int copyFromCount) = 0; - virtual void reset(const std::vector<T> & copyFrom) = 0; + virtual void reset(const T * copyFrom, const int copyFromCount) noexcept = 0; + virtual void reset(const std::vector<T> & copyFrom) noexcept = 0; /** Returns the number of elements in this ring buffer. */ - virtual int getSize() const = 0; + virtual int getSize() const noexcept = 0; /** Returns the number of free slots available to put. */ - virtual int getFreeSlots() const = 0; + virtual int getFreeSlots() const noexcept = 0; /** Returns true if this ring buffer is empty, otherwise false. */ - virtual bool isEmpty() const = 0; + virtual bool isEmpty() const noexcept = 0; /** Returns true if this ring buffer is full, otherwise false. */ - virtual bool isFull() const = 0; + virtual bool isFull() const noexcept = 0; /** * Dequeues the oldest enqueued element if available, otherwise null. @@ -101,7 +101,7 @@ template <class T> class Ringbuffer { * </p> * @return the oldest put element if available, otherwise null. */ - virtual T get() = 0; + virtual T get() noexcept = 0; /** * Dequeues the oldest enqueued element. @@ -117,13 +117,13 @@ template <class T> class Ringbuffer { * @return the oldest put element or <code>null</code> if timeout occurred. * @throws InterruptedException */ - virtual T getBlocking(const int timeoutMS=0) /* throws InterruptedException */ = 0; + virtual T getBlocking(const int timeoutMS=0) noexcept = 0; /** * Peeks the next element at the read position w/o modifying pointer, nor blocking. * @return <code>null</code> if empty, otherwise the element which would be read next. */ - virtual T peek() = 0; + virtual T peek() noexcept = 0; /** * Peeks the next element at the read position w/o modifying pointer, but with blocking. @@ -134,7 +134,7 @@ template <class T> class Ringbuffer { * </p> * @return <code>null</code> if empty or timeout occurred, otherwise the element which would be read next. */ - virtual T peekBlocking(const int timeoutMS=0) /* throws InterruptedException */ = 0; + virtual T peekBlocking(const int timeoutMS=0) noexcept = 0; /** * Drops up to {@code count} oldest enqueued elements. @@ -144,7 +144,7 @@ template <class T> class Ringbuffer { * @param count maximum number of elements to drop from ringbuffer. * @return actual number of dropped elements. */ - virtual int drop(const int count) = 0; + virtual int drop(const int count) noexcept = 0; /** * Enqueues the given element. @@ -155,7 +155,7 @@ template <class T> class Ringbuffer { * Method is non blocking and returns immediately;. * </p> */ - virtual bool put(const T & e) = 0; + virtual bool put(const T & e) noexcept = 0; /** * Enqueues the given element. @@ -168,7 +168,7 @@ template <class T> class Ringbuffer { * Returns true if successful, otherwise false in case timeout occurred. * </p> */ - virtual bool putBlocking(const T & e, const int timeoutMS=0) = 0; + virtual bool putBlocking(const T & e, const int timeoutMS=0) noexcept = 0; /** * Enqueues the same element at it's write position, if not full. @@ -180,7 +180,7 @@ template <class T> class Ringbuffer { * </p> * @throws InterruptedException */ - virtual bool putSame() = 0; + virtual bool putSame() noexcept = 0; /** * Enqueues the same element at it's write position, if not full. @@ -194,13 +194,13 @@ template <class T> class Ringbuffer { * </p> * @throws InterruptedException */ - virtual bool putSameBlocking(const int timeoutMS=0) = 0; + virtual bool putSameBlocking(const int timeoutMS=0) noexcept = 0; /** * Blocks until at least <code>count</code> free slots become available. * @throws InterruptedException */ - virtual void waitForFreeSlots(const int count) /* throws InterruptedException */ = 0; + virtual void waitForFreeSlots(const int count) noexcept = 0; /** * Resizes this ring buffer's capacity. |