summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-09-14 20:13:35 +0200
committerSven Gothel <[email protected]>2020-09-14 20:13:35 +0200
commitc10af68a6d94fd901a938b60c843c6ee0ba8af84 (patch)
tree98bd3a4b5f0cfaeac4d2b9813e4dd06ebbc03c5e
parent410ed5c924b665beced35ab1d51b7277a5b0aff9 (diff)
C++ noexcept: Ringbuffer and its LFRingbuffer implementation
-rw-r--r--api/direct_bt/LFRingbuffer.hpp85
-rw-r--r--api/direct_bt/Ringbuffer.hpp42
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.