From d13bf7d5df0255fbbd82ffea190332e6fd21c7e5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 6 Jul 2021 18:49:27 +0100 Subject: [PATCH] Changes before merging to development --- include/etl/bip_buffer_spsc_atomic.h | 714 ++++++++++-------- .../bip_buffer_spsc_atomic.h.t.cpp | 29 + test/sanity-check/c++03/CMakeLists.txt | 1 + test/sanity-check/c++11/CMakeLists.txt | 1 + test/sanity-check/c++14/CMakeLists.txt | 1 + test/sanity-check/c++17/CMakeLists.txt | 1 + test/vs2019/etl.vcxproj | 17 + test/vs2019/etl.vcxproj.filters | 3 + 8 files changed, 456 insertions(+), 311 deletions(-) create mode 100644 test/sanity-check/bip_buffer_spsc_atomic.h.t.cpp diff --git a/include/etl/bip_buffer_spsc_atomic.h b/include/etl/bip_buffer_spsc_atomic.h index 517436ac..100fc961 100644 --- a/include/etl/bip_buffer_spsc_atomic.h +++ b/include/etl/bip_buffer_spsc_atomic.h @@ -1,11 +1,40 @@ ///\file +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 Benedek Kupper, John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + /** * @note Based on the works of Andrea Lattuada and James Munns: * https://blog.systems.ethz.ch/blog/2019/the-design-and-implementation-of-a-lock-free-ring-buffer-with-contiguous-reservations.html * Whose design was inspired by Simon Cooke: * https://www.codeproject.com/Articles/3479/The-Bip-Buffer-The-Circular-Buffer-with-a-Twist */ + #ifndef ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED #define ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED @@ -22,379 +51,442 @@ #include "error_handler.h" #include "span.h" -#if ETL_HAS_ATOMIC +#if ETL_HAS_ATOMIC && ETL_CPP11_SUPPORTED namespace etl { - class bip_buffer_exception: public exception + //*************************************************************************** + /// Base exception for a bip buffer. + //*************************************************************************** + class bip_buffer_exception: public exception + { + public: + + bip_buffer_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) { - public: - bip_buffer_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - : exception(reason_, file_name_, line_number_) - { - } - }; + } + }; - class bip_buffer_reserve_invalid: public bip_buffer_exception + //*************************************************************************** + /// Exception for an invalid reserve. + //*************************************************************************** + class bip_buffer_reserve_invalid: public bip_buffer_exception + { + public: + + bip_buffer_reserve_invalid(string_type file_name_, numeric_type line_number_) + : bip_buffer_exception("bip_buffer:reserve", file_name_, line_number_) { - public: - bip_buffer_reserve_invalid(string_type file_name_, numeric_type line_number_) - : bip_buffer_exception("bip_buffer:reserve", file_name_, line_number_) - { - } - }; + } + }; - template - class bip_buffer_spsc_atomic_base + //*************************************************************************** + /// The common base for a bip_buffer_spsc_atomic_base. + //*************************************************************************** + template + class bip_buffer_spsc_atomic_base + { + public: + + /// The type used for determining the size of buffer. + typedef typename etl::size_type_lookup::type size_type; + + //************************************************************************* + /// Returns true if the buffer is empty. + //************************************************************************* + bool empty() const { - public: - /// The type used for determining the size of buffer. - typedef typename etl::size_type_lookup::type size_type; + return size() == 0; + } - bool empty() const + //************************************************************************* + /// Returns true if the buffer is full. + //************************************************************************* + bool full() const + { + return available() == 0; + } + + //************************************************************************* + /// Returns the total used size, which may be split in two blocks + /// so the size will always be smaller after a read commit. + //************************************************************************* + size_type size() const + { + size_type write_index = write.load(etl::memory_order_acquire); + size_type read_index = read.load(etl::memory_order_acquire); + + // no wraparound + if (write_index >= read_index) + { + // size is distance between read and write + return write_index - read_index; + } + else + { + size_type last_index = last.load(etl::memory_order_acquire); + + // size is distance between beginning and write, plus read and last + return (write_index - 0) + (last_index - read_index); + } + } + + //************************************************************************* + /// Returns the largest contiguous available block size. + //************************************************************************* + size_type available() const + { + size_type write_index = write.load(etl::memory_order_acquire); + size_type read_index = read.load(etl::memory_order_acquire); + + // no wraparound + if (write_index >= read_index) + { + size_type forward_size = capacity() - write_index; + + // check if there's more space if wrapping around + if (read_index > (forward_size + 1)) { - return size() == 0; + return read_index - 1; } - - bool full() const + else { - return available() == 0; + return forward_size; } + } + else // read_index > write_index + { + return read_index - write_index - 1; + } + } - // returns the total used size, which may be split in two blocks - // so the size will always be smaller after a read commit - size_type size() const + //************************************************************************* + /// Returns the maximum capacity of the buffer. + //************************************************************************* + size_type capacity() const + { + return RESERVED; + } + + //************************************************************************* + /// Returns the maximum size of the buffer. + //************************************************************************* + size_type max_size() const + { + return RESERVED; + } + + //************************************************************************* + /// Clears the buffer. + //************************************************************************* + void clear() + { + read.store(0, etl::memory_order_release); + write.store(0, etl::memory_order_release); + last.store(0, etl::memory_order_release); + } + + protected: + + //************************************************************************* + /// Construccts the buffer. + //************************************************************************* + bip_buffer_spsc_atomic_base(size_type reserved_) + : read(0) + , write(0) + , last(0) + , RESERVED(reserved_) + { + } + + //************************************************************************* + size_type get_write_reserve(size_type* psize) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type read_index = read.load(etl::memory_order_acquire); + + // No wraparound + if (write_index >= read_index) + { + size_type forward_size = capacity() - write_index; + + // We still fit in linearly + if (*psize <= forward_size) { - size_type write_index = write.load(etl::memory_order_acquire); - size_type read_index = read.load(etl::memory_order_acquire); - - // no wraparound - if (write_index >= read_index) + return write_index; + } + // There isn't more space even when wrapping around + else if (read_index <= (forward_size + 1)) + { + *psize = forward_size; + return write_index; + } + // Better wrap around now + else + { + // Check if size fits. + // When wrapping, the write index cannot reach read index, + // then we'd not be able to distinguish wrapped situation from linear. + if (*psize >= read_index) + { + if (read_index > 0) { - // size is distance between read and write - return write_index - read_index; + *psize = read_index - 1; } else { - size_type last_index = last.load(etl::memory_order_acquire); - - // size is distance between beginning and write, plus read and last - return (write_index - 0) + (last_index - read_index); + *psize = 0; } - } + } - // returns the largest contiguous(!) available block size - size_type available() const + return 0; + } + } + else // read_index > write_index + { + // Doesn't fit + if ((write_index + *psize) >= read_index) { - size_type write_index = write.load(etl::memory_order_acquire); - size_type read_index = read.load(etl::memory_order_acquire); - - // no wraparound - if (write_index >= read_index) - { - size_type forward_size = capacity() - write_index; - - // check if there's more space if wrapping around - if (read_index > (forward_size + 1)) - { - return read_index - 1; - } - else - { - return forward_size; - } - } - else // read_index > write_index - { - return read_index - write_index - 1; - } + *psize = read_index - write_index - 1; } - size_type capacity() const + return write_index; + } + } + + //************************************************************************* + void apply_write_reserve(size_type windex, size_type wsize) + { + if (wsize > 0) + { + size_type write_index = write.load(etl::memory_order_relaxed); + size_type read_index = read.load(etl::memory_order_acquire); + + // Wrapped around already + if (write_index < read_index) { - return RESERVED; + ETL_ASSERT_AND_RETURN((windex == write_index) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid)); } - - size_type max_size() const + // No wraparound so far, also not wrapping around with this block + else if (windex == write_index) { - return RESERVED; - } + ETL_ASSERT_AND_RETURN(wsize <= (capacity() - write_index), ETL_ERROR(bip_buffer_reserve_invalid)); - void clear() + // Move both indexes forward + last.store(windex + wsize, etl::memory_order_release); + } + // Wrapping around now + else { - read.store(0, etl::memory_order_release); - write.store(0, etl::memory_order_release); - last.store(0, etl::memory_order_release); + ETL_ASSERT_AND_RETURN((windex == 0) && ((wsize + 1) <= read_index), ETL_ERROR(bip_buffer_reserve_invalid)); } + + // Always update write index + write.store(windex + wsize, etl::memory_order_release); + } + } - protected: - bip_buffer_spsc_atomic_base(size_type reserved_) - : read(0), - write(0), - last(0), - RESERVED(reserved_) + //************************************************************************* + size_type get_read_reserve(size_type* psize) + { + size_type read_index = read.load(etl::memory_order_relaxed); + size_type write_index = write.load(etl::memory_order_acquire); + + if (read_index > write_index) + { + // Writer has wrapped around + size_type last_index = last.load(etl::memory_order_relaxed); + + if (read_index == last_index) { + // Reader reached the end, start read from 0 + read_index = 0; } - - size_type get_write_reserve(size_type* psize) + else // (read_index < last_index) { - size_type write_index = write.load(etl::memory_order_relaxed); - size_type read_index = read.load(etl::memory_order_acquire); - - // no wraparound - if (write_index >= read_index) - { - size_type forward_size = capacity() - write_index; - - // we still fit in linearly - if (*psize <= forward_size) - { - return write_index; - } - // there isn't more space even when wrapping around - else if (read_index <= (forward_size + 1)) - { - *psize = forward_size; - return write_index; - } - // better wrap around now - else - { - // check if size fits - // when wrapping, the write index cannot reach read index, - // then we'd not be able to distinguish wrapped situation from linear - if (*psize >= read_index) - { - if (read_index > 0) - { - *psize = read_index - 1; - } - else - { - *psize = 0; - } - } - return 0; - } - } - else // read_index > write_index - { - // doesn't fit - if ((write_index + *psize) >= read_index) - { - *psize = read_index - write_index - 1; - } - return write_index; - } + // Use the remaining buffer at the end + write_index = last_index; } + } + else + { + // No wraparound, nothing to adjust + } - void apply_write_reserve(size_type windex, size_type wsize) - { - if (wsize > 0) - { - size_type write_index = write.load(etl::memory_order_relaxed); - size_type read_index = read.load(etl::memory_order_acquire); + // Limit to max available size + if ((write_index - read_index) < *psize) + { + *psize = write_index - read_index; + } - // wrapped around already - if (write_index < read_index) - { - ETL_ASSERT_AND_RETURN((windex == write_index) && ((wsize + 1) <= read_index), - ETL_ERROR(bip_buffer_reserve_invalid)); - } - // no wraparound so far, also not wrapping around with this block - else if (windex == write_index) - { - ETL_ASSERT_AND_RETURN(wsize <= (capacity() - write_index), - ETL_ERROR(bip_buffer_reserve_invalid)); + return read_index; + } - // move both indexes forward - last.store(windex + wsize, etl::memory_order_release); - } - // wrapping around now - else - { - ETL_ASSERT_AND_RETURN((windex == 0) && ((wsize + 1) <= read_index), - ETL_ERROR(bip_buffer_reserve_invalid)); - } - // always update write index - write.store(windex + wsize, etl::memory_order_release); - } - } + //************************************************************************* + void apply_read_reserve(size_type rindex, size_type rsize) + { + if (rsize > 0) + { + size_type rsize_checker = rsize; + ETL_ASSERT_AND_RETURN((rindex == get_read_reserve(&rsize_checker)) && (rsize == rsize_checker), ETL_ERROR(bip_buffer_reserve_invalid)); - size_type get_read_reserve(size_type* psize) - { - size_type read_index = read.load(etl::memory_order_relaxed); - size_type write_index = write.load(etl::memory_order_acquire); + read.store(rindex + rsize, etl::memory_order_release); + } + } - if (read_index > write_index) - { - // writer has wrapped around + private: - size_type last_index = last.load(etl::memory_order_relaxed); - if (read_index == last_index) - { - // reader reached the end, start read from 0 - read_index = 0; - } - else // (read_index < last_index) - { - // use the remaining buffer at the end - write_index = last_index; - } - } - else - { - // no wraparound, nothing to adjust - } - - // limit to max available size - if ((write_index - read_index) < *psize) - { - *psize = write_index - read_index; - } - return read_index; - } - - void apply_read_reserve(size_type rindex, size_type rsize) - { - if (rsize > 0) - { - size_type rsize_checker = rsize; - ETL_ASSERT_AND_RETURN((rindex == get_read_reserve(&rsize_checker)) && (rsize == rsize_checker), - ETL_ERROR(bip_buffer_reserve_invalid)); - - read.store(rindex + rsize, etl::memory_order_release); - } - } - - private: - etl::atomic read; - etl::atomic write; - etl::atomic last; - const size_type RESERVED; + etl::atomic read; + etl::atomic write; + etl::atomic last; + const size_type RESERVED; #if defined(ETL_POLYMORPHIC_SPSC_BIP_BUFFER_ATOMIC) || defined(ETL_POLYMORPHIC_CONTAINERS) - public: - virtual ~bip_buffer_spsc_atomic_base() - { - } + public: + virtual ~bip_buffer_spsc_atomic_base() + { + } #else - protected: - ~bip_buffer_spsc_atomic_base() - { - } -#endif - }; + protected: - template - class ibip_buffer_spsc_atomic : public bip_buffer_spsc_atomic_base + ~bip_buffer_spsc_atomic_base() { - private: - typedef typename etl::bip_buffer_spsc_atomic_base base_t; - using base_t::get_read_reserve; - using base_t::apply_read_reserve; - using base_t::get_write_reserve; - using base_t::apply_write_reserve; - - public: - typedef T value_type; ///< The type stored in the buffer. - typedef T& reference; ///< A reference to the type used in the buffer. - typedef const T& const_reference; ///< A const reference to the type used in the buffer. -#if ETL_CPP11_SUPPORTED - typedef T&& rvalue_reference;///< An rvalue_reference to the type used in the buffer. + } #endif - typedef typename base_t::size_type size_type; ///< The type used for determining the size of the buffer. + }; - // reserves a memory area for reading up to the max_reserve_size - span read_reserve(size_type max_reserve_size) - { - size_type reserve_size = max_reserve_size; - auto rindex = get_read_reserve(&reserve_size); - return span(p_buffer + rindex, reserve_size); - } + //*************************************************************************** + /// A fixed capacity bipartite buffer. + //*************************************************************************** + template + class ibip_buffer_spsc_atomic : public bip_buffer_spsc_atomic_base + { + private: + + typedef typename etl::bip_buffer_spsc_atomic_base base_t; + using base_t::get_read_reserve; + using base_t::apply_read_reserve; + using base_t::get_write_reserve; + using base_t::apply_write_reserve; - // commits the previously reserved read memory area - // the reserve can be trimmed at the end before committing - // throws bip_buffer_reserve_invalid - void read_commit(const span &reserve) - { - size_type rindex = etl::distance(p_buffer, reserve.data()); - apply_read_reserve(rindex, reserve.size()); - } + public: + + typedef T value_type; ///< The type stored in the buffer. + typedef T& reference; ///< A reference to the type used in the buffer. + typedef const T& const_reference; ///< A const reference to the type used in the buffer. +#if ETL_CPP11_SUPPORTED + typedef T&& rvalue_reference;///< An rvalue_reference to the type used in the buffer. +#endif + typedef typename base_t::size_type size_type; ///< The type used for determining the size of the buffer. - // reserves a memory area for writing up to the max_reserve_size - span write_reserve(size_type max_reserve_size) - { - size_type reserve_size = max_reserve_size; - auto windex = get_write_reserve(&reserve_size); - return span(p_buffer + windex, reserve_size); - } + //************************************************************************* + // Reserves a memory area for reading up to the max_reserve_size + //************************************************************************* + span read_reserve(size_type max_reserve_size) + { + size_type reserve_size = max_reserve_size; + auto rindex = get_read_reserve(&reserve_size); + + return span(p_buffer + rindex, reserve_size); + } - // commits the previously reserved write memory area - // the reserve can be trimmed at the end before committing - // throws bip_buffer_reserve_invalid - void write_commit(const span &reserve) - { - size_type windex = etl::distance(p_buffer, reserve.data()); - apply_write_reserve(windex, reserve.size()); - } + //************************************************************************* + // Commits the previously reserved read memory area + // the reserve can be trimmed at the end before committing. + // Throws bip_buffer_reserve_invalid + //************************************************************************* + void read_commit(const span &reserve) + { + size_type rindex = etl::distance(p_buffer, reserve.data()); + apply_read_reserve(rindex, reserve.size()); + } - protected: - ibip_buffer_spsc_atomic(T* p_buffer_, size_type reserved_) - : base_t(reserved_), - p_buffer(p_buffer_) - { - } + //************************************************************************* + // Reserves a memory area for writing up to the max_reserve_size + //************************************************************************* + span write_reserve(size_type max_reserve_size) + { + size_type reserve_size = max_reserve_size; + auto windex = get_write_reserve(&reserve_size); + + return span(p_buffer + windex, reserve_size); + } - private: - // Disable copy construction and assignment. - ibip_buffer_spsc_atomic(const ibip_buffer_spsc_atomic&) ETL_DELETE; - ibip_buffer_spsc_atomic& operator =(const ibip_buffer_spsc_atomic&) ETL_DELETE; + //************************************************************************* + // Commits the previously reserved write memory area + // the reserve can be trimmed at the end before committing. + // Throws bip_buffer_reserve_invalid + //************************************************************************* + void write_commit(const span &reserve) + { + size_type windex = etl::distance(p_buffer, reserve.data()); + apply_write_reserve(windex, reserve.size()); + } + + protected: + + //************************************************************************* + ibip_buffer_spsc_atomic(T* p_buffer_, size_type reserved_) + : base_t(reserved_) + , p_buffer(p_buffer_) + { + } + + private: + + // Disable copy construction and assignment. + ibip_buffer_spsc_atomic(const ibip_buffer_spsc_atomic&) ETL_DELETE; + ibip_buffer_spsc_atomic& operator =(const ibip_buffer_spsc_atomic&) ETL_DELETE; #if ETL_CPP11_SUPPORTED - ibip_buffer_spsc_atomic(ibip_buffer_spsc_atomic&&) = delete; - ibip_buffer_spsc_atomic& operator =(ibip_buffer_spsc_atomic&&) = delete; + ibip_buffer_spsc_atomic(ibip_buffer_spsc_atomic&&) = delete; + ibip_buffer_spsc_atomic& operator =(ibip_buffer_spsc_atomic&&) = delete; #endif - T* const p_buffer; - }; + const T* p_buffer; + }; - //*************************************************************************** - /// A fixed capacity bipartite buffer. - /// This buffer supports concurrent access by one producer and one consumer. - /// \tparam T The type this buffer should support. - /// \tparam SIZE The maximum capacity of the buffer. - /// \tparam MEMORY_MODEL The memory model for the buffer. Determines the type of the internal counter variables. - //*************************************************************************** - template - class bip_buffer_spsc_atomic : public ibip_buffer_spsc_atomic + //*************************************************************************** + /// A fixed capacity bipartite buffer. + /// This buffer supports concurrent access by one producer and one consumer. + /// \tparam T The type this buffer should support. + /// \tparam SIZE The maximum capacity of the buffer. + /// \tparam MEMORY_MODEL The memory model for the buffer. Determines the type of the internal counter variables. + //*************************************************************************** + template + class bip_buffer_spsc_atomic : public ibip_buffer_spsc_atomic + { + private: + + typedef typename etl::ibip_buffer_spsc_atomic base_t; + + public: + + typedef typename base_t::size_type size_type; + + private: + + static ETL_CONSTANT size_type RESERVED_SIZE = size_type(SIZE); + + public: + + ETL_STATIC_ASSERT((SIZE <= (etl::integral_limits::max)), "Size too large for memory model"); + + static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE); + + bip_buffer_spsc_atomic() + : base_t(reinterpret_cast(&buffer[0]), RESERVED_SIZE) { - private: - typedef typename etl::ibip_buffer_spsc_atomic base_t; + } - public: - typedef typename base_t::size_type size_type; + private: - private: - static const size_type RESERVED_SIZE = size_type(SIZE); - - public: - ETL_STATIC_ASSERT((SIZE <= (etl::integral_limits::max)), "Size too large for memory model"); - - static const size_type MAX_SIZE = size_type(SIZE); - - bip_buffer_spsc_atomic() - : base_t(reinterpret_cast(&buffer[0]), RESERVED_SIZE) - { - } - - private: - - /// The uninitialised buffer of T used in the bip_buffer_spsc. - typename etl::aligned_storage::value>::type buffer[RESERVED_SIZE]; - }; + /// The uninitialised buffer of T used in the bip_buffer_spsc. + etl::uninitialized_buffer_of buffer; + }; } -#endif /* ETL_HAS_ATOMIC */ +#endif /* ETL_HAS_ATOMIC && ETL_CPP11_SUPPORTED */ #endif /* ETL_BIP_BUFFER_SPSC_ATOMIC_INCLUDED */ diff --git a/test/sanity-check/bip_buffer_spsc_atomic.h.t.cpp b/test/sanity-check/bip_buffer_spsc_atomic.h.t.cpp new file mode 100644 index 00000000..d3c54920 --- /dev/null +++ b/test/sanity-check/bip_buffer_spsc_atomic.h.t.cpp @@ -0,0 +1,29 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include diff --git a/test/sanity-check/c++03/CMakeLists.txt b/test/sanity-check/c++03/CMakeLists.txt index dea14a49..809b1668 100644 --- a/test/sanity-check/c++03/CMakeLists.txt +++ b/test/sanity-check/c++03/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(t98 PRIVATE etl_profile.h ../basic_string.h.t.cpp ../basic_string_stream.h.t.cpp ../binary.h.t.cpp + ../bip_buffer_spsc_atomic.h.t.cpp ../bitset.h.t.cpp ../bit_stream.h.t.cpp ../bloom_filter.h.t.cpp diff --git a/test/sanity-check/c++11/CMakeLists.txt b/test/sanity-check/c++11/CMakeLists.txt index 09193372..4443cc6e 100644 --- a/test/sanity-check/c++11/CMakeLists.txt +++ b/test/sanity-check/c++11/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(t11 PRIVATE etl_profile.h ../basic_string.h.t.cpp ../basic_string_stream.h.t.cpp ../binary.h.t.cpp + ../bip_buffer_spsc_atomic.h.t.cpp ../bitset.h.t.cpp ../bit_stream.h.t.cpp ../bloom_filter.h.t.cpp diff --git a/test/sanity-check/c++14/CMakeLists.txt b/test/sanity-check/c++14/CMakeLists.txt index e514d386..d991fca0 100644 --- a/test/sanity-check/c++14/CMakeLists.txt +++ b/test/sanity-check/c++14/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(t14 PRIVATE etl_profile.h ../basic_string.h.t.cpp ../basic_string_stream.h.t.cpp ../binary.h.t.cpp + ../bip_buffer_spsc_atomic.h.t.cpp ../bitset.h.t.cpp ../bit_stream.h.t.cpp ../bloom_filter.h.t.cpp diff --git a/test/sanity-check/c++17/CMakeLists.txt b/test/sanity-check/c++17/CMakeLists.txt index dd6b754a..2a96532e 100644 --- a/test/sanity-check/c++17/CMakeLists.txt +++ b/test/sanity-check/c++17/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(t17 PRIVATE etl_profile.h ../basic_string.h.t.cpp ../basic_string_stream.h.t.cpp ../binary.h.t.cpp + ../bip_buffer_spsc_atomic.h.t.cpp ../bitset.h.t.cpp ../bit_stream.h.t.cpp ../bloom_filter.h.t.cpp diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 54fffc50..e22b1840 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1698,6 +1698,23 @@ true true + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true true diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 53ab356c..3b6ef855 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -2549,6 +2549,9 @@ Source Files\Sanity Checks + + Source Files\Sanity Checks +