diff --git a/include/etl/buffer_descriptors.h b/include/etl/buffer_descriptors.h index 9a972557..d9c03e11 100644 --- a/include/etl/buffer_descriptors.h +++ b/include/etl/buffer_descriptors.h @@ -37,33 +37,34 @@ SOFTWARE. #include "type_traits.h" #include "static_assert.h" #include "cyclic_value.h" +#include "algorithm.h" #include -#undef ETL_FILE -#define ETL_FILE "57" - namespace etl { //*************************************************************************** /// buffer_descriptors //*************************************************************************** - template + template class buffer_descriptors { + private: + + struct descriptor_item; + public: - typedef TBuffer value_type; - typedef value_type* pointer; - typedef TSize size_type; - typedef TFlag flag_type; + typedef TBuffer value_type; + typedef value_type* pointer; + typedef size_t size_type; + typedef TFlag flag_type; - ETL_STATIC_ASSERT(etl::is_unsigned::value, "TSize must be unsigned"); - ETL_STATIC_ASSERT(etl::is_integral::value, "TSize must be integral"); - - static ETL_CONSTANT size_t N_BUFFERS = N_BUFFERS_; + static ETL_CONSTANT size_type N_BUFFERS = N_BUFFERS_; static ETL_CONSTANT size_type BUFFER_SIZE = BUFFER_SIZE_; + //********************************* + /// Describes a buffer. //********************************* class descriptor { @@ -75,78 +76,131 @@ namespace etl //********************************* descriptor() - : pbuffer(ETL_NULLPTR) - , in_use(false) + : pdesc_item(ETL_NULLPTR) { } //********************************* - ETL_CONSTEXPR pointer data() const + descriptor(const descriptor& other) + : pdesc_item(other.pdesc_item) { - return pbuffer; } //********************************* - ETL_CONSTEXPR size_type max_size() const + descriptor& operator =(const descriptor& other) + { + pdesc_item = other.pdesc_item; + return *this; + } + + //********************************* + pointer data() const + { + return pdesc_item->pbuffer; + } + + //********************************* + ETL_NODISCARD + constexpr size_type max_size() const { return BUFFER_SIZE; } //********************************* - bool is_valid() const - { - return pbuffer != ETL_NULLPTR; - } - - //********************************* + ETL_NODISCARD bool is_allocated() const { - return bool(in_use); + return bool(pdesc_item->in_use); } //********************************* + ETL_NODISCARD bool is_released() const { - return !bool(in_use); + return bool(!pdesc_item->in_use); + } + + //********************************* + ETL_NODISCARD + bool is_valid() const + { + return pdesc_item != ETL_NULLPTR; } //********************************* void release() { - in_use = false; + pdesc_item->in_use = false; } private: //********************************* - ETL_CONSTEXPR descriptor(TBuffer* pbuffer_) - : pbuffer(pbuffer_) - , in_use(false) + descriptor(descriptor_item* pdesc_item_) + : pdesc_item(pdesc_item_) { } //********************************* void allocate() { - in_use = true; + pdesc_item->in_use = true;; + } + + /// The pointer to the buffer descriptor. + descriptor_item* pdesc_item; + }; + + //********************************* + /// Describes a notification. + //********************************* + class notification + { + public: + + //********************************* + notification() + : desc() + , count(0U) + { } //********************************* - descriptor(const descriptor&) ETL_DELETE; - descriptor& operator =(const descriptor&) ETL_DELETE; + notification(descriptor desc_, size_t count_) + : desc(desc_) + , count(count_) + { + } - pointer pbuffer; - volatile flag_type in_use; + //********************************* + ETL_NODISCARD + descriptor get_descriptor() const + { + return desc; + } + + //********************************* + ETL_NODISCARD + size_t get_count() const + { + return count; + } + + private: + + descriptor desc; + size_t count; }; - typedef etl::delegate callback_type; + // The type of the callback function. + typedef etl::delegate callback_type; //********************************* buffer_descriptors(TBuffer* pbuffers_) { for (size_t i = 0U; i < N_BUFFERS; ++i) { - descriptors[i].pbuffer = pbuffers_ + (i * BUFFER_SIZE); + descriptor_items[i].pbuffer = pbuffers_ + (i * BUFFER_SIZE); } } @@ -156,7 +210,7 @@ namespace etl { for (size_t i = 0U; i < N_BUFFERS; ++i) { - descriptors[i].pbuffer = pbuffers_ + (i * BUFFER_SIZE); + descriptor_items[i].pbuffer = pbuffers_ + (i * BUFFER_SIZE); } } @@ -167,26 +221,27 @@ namespace etl } //********************************* + ETL_NODISCARD bool is_valid() const { return callback.is_valid(); } //********************************* - void notify(descriptor& desc_, size_type count_) + void notify(notification n) { - // We have a valid callback? + // Do we have a valid callback? if (callback.is_valid()) { - // Set the relevant data. - callback(desc_, count_); - } + callback(n); + } } //********************************* - descriptor& allocate() + ETL_NODISCARD + descriptor allocate() { - descriptor& desc = descriptors[next]; + descriptor desc(&descriptor_items[next]); if (desc.is_released()) { @@ -198,19 +253,37 @@ namespace etl } else { - static descriptor null_descriptor; - return null_descriptor; + return descriptor(); } } + //********************************* + ETL_NODISCARD + descriptor allocate(value_type fill_) + { + descriptor desc = allocate(); + + if (desc.is_valid()) + { + etl::fill_n(desc.data(), BUFFER_SIZE, fill_); + } + + return desc; + } + private: + //********************************* + struct descriptor_item + { + pointer pbuffer; + volatile flag_type in_use; + }; + callback_type callback; - etl::array descriptors; + etl::array descriptor_items; etl::cyclic_value next; }; } -#undef ETL_FILE - #endif diff --git a/include/etl/version.h b/include/etl/version.h index b592f725..64d6a44a 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,7 +38,7 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 19 -#define ETL_VERSION_MINOR 0 +#define ETL_VERSION_MINOR 1 #define ETL_VERSION_PATCH 0 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) "." ETL_STRINGIFY(ETL_VERSION_MINOR) "." ETL_STRINGIFY(ETL_VERSION_PATCH) #define ETL_VERSION_W ETL_STRINGIFY(ETL_VERSION_MAJOR) L"." ETL_STRINGIFY(ETL_VERSION_MINOR) L"." ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/library.json b/library.json index d9ff2990..32bead34 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Embedded Template Library", - "version": "19.0.0", + "version": "19.1.0", "author s": { "name": "John Wellbelove", "email": "john.wellbelove@etlcpp.com" diff --git a/library.properties b/library.properties index abc54973..d91061e6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=19.0.0 +version=19.1.0 author= John Wellbelove maintainer=John Wellbelove license=MIT diff --git a/support/Release notes.txt b/support/Release notes.txt index 400f0494..c0f99551 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +19.1.0 +Refactor of etl::buffer_descriptors interface. + =============================================================================== 19.0.0 Containers with external buffers or pools are now separate classes instead of specialisations. diff --git a/test/test_buffer_descriptors.cpp b/test/test_buffer_descriptors.cpp index e0075c98..a99c6560 100644 --- a/test/test_buffer_descriptors.cpp +++ b/test/test_buffer_descriptors.cpp @@ -52,17 +52,15 @@ namespace constexpr size_t N_BUFFERS = 4U; constexpr size_t DATA_COUNT = BUFFER_SIZE / 2; - using BD = etl::buffer_descriptors; - using Descriptor = BD::descriptor; - using NotificationCallback = BD::callback_type; + using BD = etl::buffer_descriptors; //*********************************** struct Receiver { - void receive(Descriptor& desc_, BD::size_type count_) + void receive(BD::notification n) { - pbuffer = desc_.data(); - count = count_; + pbuffer = n.get_descriptor().data(); + count = n.get_count(); } BD::pointer pbuffer; @@ -89,7 +87,7 @@ namespace Receiver receiver; char buffers[N_BUFFERS][BUFFER_SIZE]; - NotificationCallback callback = NotificationCallback::create(receiver); + BD::callback_type callback = BD::callback_type::create(receiver); BD bd(&buffers[0][0], callback); @@ -104,7 +102,7 @@ namespace Receiver receiver; char buffers[N_BUFFERS][BUFFER_SIZE]; - NotificationCallback callback = NotificationCallback::create(receiver); + BD::callback_type callback = BD::callback_type::create(receiver); BD bd(&buffers[0][0]); bd.set_callback(callback); @@ -120,19 +118,45 @@ namespace Receiver receiver; char buffers[N_BUFFERS][BUFFER_SIZE]; - NotificationCallback callback = NotificationCallback::create(receiver); + BD::callback_type callback = BD::callback_type::create(receiver); BD bd(&buffers[0][0], callback); for (size_t i = 0U; i < N_BUFFERS; ++i) { - Descriptor& desc = bd.allocate(); + BD::descriptor desc = bd.allocate(); CHECK_EQUAL(BUFFER_SIZE, desc.max_size()); CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data())); } } + //************************************************************************* + TEST(test_buffers_with_allocate_fill) + { + Receiver receiver; + + std::array test = + { + char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), + char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF) + }; + + char buffers[N_BUFFERS][BUFFER_SIZE]; + BD::callback_type callback = BD::callback_type::create(receiver); + + BD bd(&buffers[0][0], callback); + + for (size_t i = 0U; i < N_BUFFERS; ++i) + { + BD::descriptor desc = bd.allocate(char(0xFF)); + + CHECK_EQUAL(BUFFER_SIZE, desc.max_size()); + CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data())); + CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE); + } + } + //************************************************************************* TEST(test_notifications) { @@ -143,18 +167,18 @@ namespace char buffers[N_BUFFERS][BUFFER_SIZE]; std::fill(&buffers[0][0], &buffers[N_BUFFERS - 1][0] + BUFFER_SIZE , 0U); - NotificationCallback callback = NotificationCallback::create(receiver); + BD::callback_type callback = BD::callback_type::create(receiver); BD bd(&buffers[0][0], callback); for (size_t i = 0U; i < N_BUFFERS; ++i) { - Descriptor& desc = bd.allocate(); + BD::descriptor desc = bd.allocate(); CHECK(desc.is_valid()); std::copy(test.begin(), test.begin() + DATA_COUNT, desc.data()); - bd.notify(desc, DATA_COUNT); + bd.notify(BD::notification(desc, DATA_COUNT)); desc.release(); CHECK_EQUAL(DATA_COUNT, receiver.count); @@ -170,18 +194,18 @@ namespace char buffers[N_BUFFERS][BUFFER_SIZE]; - NotificationCallback callback = NotificationCallback::create(receiver); + BD::callback_type callback = BD::callback_type::create(receiver); BD bd(&buffers[0][0], callback); // Use up all of the descriptors. for (size_t i = 0U; i < N_BUFFERS; ++i) { - Descriptor& desc = bd.allocate(); + BD::descriptor desc = bd.allocate(); CHECK(desc.is_valid()); } - Descriptor& desc = bd.allocate(); + BD::descriptor desc = bd.allocate(); CHECK(!desc.is_valid()); } @@ -189,25 +213,25 @@ namespace TEST(test_allocate_release_rollover) { Receiver receiver; - std::queue desc_queue; + std::queue desc_queue; char buffers[N_BUFFERS][BUFFER_SIZE]; - NotificationCallback callback = NotificationCallback::create(receiver); + BD::callback_type callback = BD::callback_type::create(receiver); BD bd(&buffers[0][0], callback); // Use up all of the descriptors, then release/allocate for the rest. for (size_t i = 0U; i < (N_BUFFERS * 2); ++i) { - Descriptor& desc = bd.allocate(); - desc_queue.push(&desc); + BD::descriptor desc = bd.allocate(); + desc_queue.push(desc); CHECK(desc.is_valid()); if (i >= (N_BUFFERS - 1)) { - desc_queue.front()->release(); + desc_queue.front().release(); desc_queue.pop(); } } @@ -220,10 +244,10 @@ namespace BD bd(&buffers[0][0]); - Descriptor& desc1 = bd.allocate(); - Descriptor& desc2 = bd.allocate(); - Descriptor& desc3 = bd.allocate(); - Descriptor& desc4 = bd.allocate(); + BD::descriptor desc1 = bd.allocate(); + BD::descriptor desc2 = bd.allocate(); + BD::descriptor desc3 = bd.allocate(); + BD::descriptor desc4 = bd.allocate(); CHECK(desc1.is_allocated()); CHECK(desc2.is_allocated()); @@ -279,18 +303,18 @@ namespace //********************************* struct Notification { - Descriptor* pdesc; + BD::descriptor desc; BD::size_type count; }; constexpr int N_ITERATIONS = 1000000; - etl::queue_spsc_atomic desc_queue; + etl::queue_spsc_atomic desc_queue; //********************************* - void Callback(Descriptor& desc_, BD::size_type count_) + void Callback(BD::notification n) { - desc_queue.push(Notification{ &desc_, count_ }); + desc_queue.push(n); } //********************************* @@ -298,7 +322,7 @@ namespace { static char buffers[N_BUFFERS][BUFFER_SIZE]; - BD bd(&buffers[0][0], NotificationCallback::create()); + BD bd(&buffers[0][0], BD::callback_type::create()); RAISE_THREAD_PRIORITY; FIX_PROCESSOR_AFFINITY1; @@ -310,21 +334,21 @@ namespace for (int i = 0; i < N_ITERATIONS; ++i) { - Descriptor* pdesc; + BD::descriptor desc; // Wait until we can allocate a descriptor. do { - pdesc = &bd.allocate(); - } while (pdesc->is_valid() == false); + desc = bd.allocate(); + } while (desc.is_valid() == false); - if (!pdesc->is_allocated()) + if (!desc.is_allocated()) { ++errors; } // Send a notification to the callback function. - bd.notify(*pdesc, BUFFER_SIZE); + bd.notify(BD::notification(desc, BUFFER_SIZE)); } CHECK_EQUAL(0, errors); @@ -343,20 +367,20 @@ namespace for (int i = 0; i < N_ITERATIONS;) { - Notification n; + BD::notification notification; // Try to get a notification from the queue. - if (desc_queue.pop(n)) + if (desc_queue.pop(notification)) { - CHECK_EQUAL(BUFFER_SIZE, n.count); - CHECK(n.pdesc->is_allocated()); + CHECK_EQUAL(BUFFER_SIZE, notification.get_count()); + CHECK(notification.get_descriptor().is_allocated()); - if (!n.pdesc->is_allocated()) + if (!notification.get_descriptor().is_allocated()) { ++errors; } - n.pdesc->release(); + notification.get_descriptor().release(); ++i; }