diff --git a/CMakeLists.txt b/CMakeLists.txt index 077e840..f4f1b84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,15 +3,36 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project(test-project CXX) +option(RING_BUFFER_CXXFLAGS "enable default CXXFLAGS" ON) option(RING_BUFFER_BUILD_TESTS "build test cases for the ring buffer library" ON) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +option(RING_BUFFER_FEATURE_DETECT "try to detect if c++ features are supported" ON) +option(RING_BUFFER_NOEXCEPT "enable conditionally noexcept ring_buffer (c++11)" OFF) +option(RING_BUFFER_CONSTEXPR "enable constexpr ring_buffer (c++11)" OFF) +option(RING_BUFFER_CONSTEXPR_DESTRUCTORS "enable constexpr destructor for ring_buffer (c++20)" OFF) + +if(RING_BUFFER_CXXFLAGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") + include(detect/standard.cmake) +endif() + +if(RING_BUFFER_FEATURE_DETECT) + include(detect/features.cmake) +endif() add_library(ring-buffer INTERFACE) target_include_directories(ring-buffer INTERFACE include/) +target_compile_features(ring-buffer INTERFACE cxx_std_11) + +if(RING_BUFFER_CONSTEXPR) + target_compile_definitions(ring-buffer INTERFACE RING_BUFFER_CONSTEXPR) +endif() +if(RING_BUFFER_NOEXCEPT) + target_compile_definitions(ring-buffer INTERFACE RING_BUFFER_NOEXCEPT) +endif() +if(RING_BUFFER_CONSTEXPR_DESTRUCTORS) + target_compile_definitions(ring-buffer INTERFACE RING_BUFFER_CONSTEXPR_DESTRUCTORS) +endif() if(RING_BUFFER_BUILD_TESTS) add_subdirectory(test) diff --git a/detect/constexpr_destructors.cpp b/detect/constexpr_destructors.cpp new file mode 100644 index 0000000..7628469 --- /dev/null +++ b/detect/constexpr_destructors.cpp @@ -0,0 +1,5 @@ +struct test { + constexpr ~test() {} +}; + +int main() {} diff --git a/detect/features.cmake b/detect/features.cmake new file mode 100644 index 0000000..f66417b --- /dev/null +++ b/detect/features.cmake @@ -0,0 +1,19 @@ +if(cxx_noexcept IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(RING_BUFFER_NOEXCEPT ON) + message(STATUS "Detected support for conditional noexcept") +endif() + +if(cxx_constexpr IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(RING_BUFFER_CONSTEXPR ON) + message(STATUS "Detected support for constexpr") +endif() + +try_compile(constexpr-destructors-compile ${CMAKE_BINARY_DIR}/detect ${CMAKE_SOURCE_DIR}/detect/constexpr_destructors.cpp + CXX_STANDARD ${CMAKE_CXX_STANDARD} + CXX_STANDARD_REQUIRED ${CMAKE_CXX_STANDARD_REQUIRED} + CXX_EXTENSIONS ${CMAKE_CXX_EXTENSIONS} +) +if(constexpr-destructors-compile) + set(RING_BUFFER_CONSTEXPR_DESTRUCTORS ON) + message(STATUS "Detected support for constexpr destructors") +endif() diff --git a/detect/standard.cmake b/detect/standard.cmake new file mode 100644 index 0000000..38839e0 --- /dev/null +++ b/detect/standard.cmake @@ -0,0 +1,15 @@ +if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +elseif(cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +elseif(cxx_std_14 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 14) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +elseif(cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +message(STATUS "Detected Standard Version: C++${CMAKE_CXX_STANDARD}") diff --git a/include/ring-buffer-config.h b/include/ring-buffer-config.h new file mode 100644 index 0000000..1e961b6 --- /dev/null +++ b/include/ring-buffer-config.h @@ -0,0 +1,22 @@ +#ifndef _RING_BUFFER_CONFIG_H +#define _RING_BUFFER_CONFIG_H + +#ifdef RING_BUFFER_NOEXCEPT +#define NOEXCEPT(x) noexcept(x) +#else +#define NOEXCEPT(x) +#endif + +#ifdef RING_BUFFER_CONSTEXPR +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + +#ifdef RING_BUFFER_CONSTEXPR_DESTRUCTORS +#define CONSTEXPR_D CONSTEXPR +#else +#define CONSTEXPR_D +#endif + +#endif diff --git a/include/ring-buffer-iterator.h b/include/ring-buffer-iterator.h new file mode 100644 index 0000000..cf067d8 --- /dev/null +++ b/include/ring-buffer-iterator.h @@ -0,0 +1,221 @@ +#ifndef _RING_BUFFER_ITERATOR_H +#define _RING_BUFFER_ITERATOR_H + +#include +#include + +template +class ring_buffer_iterator { +private: + using size_type = typename Container::size_type; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + + Container* container; + size_type front; + size_type index; + +public: + ring_buffer_iterator() = default; + ~ring_buffer_iterator() = default; + ring_buffer_iterator(Container& container, size_type front = 0, size_type index = 0) : container(&container), front(front), index(index) {} + ring_buffer_iterator(const ring_buffer_iterator&) = default; + ring_buffer_iterator(ring_buffer_iterator&&) = default; + ring_buffer_iterator& operator=(const ring_buffer_iterator&) = default; + ring_buffer_iterator& operator=(ring_buffer_iterator&&) = default; + + ring_buffer_iterator& operator+=(difference_type n) { + index += n; + } + ring_buffer_iterator& operator-=(difference_type n) { + index -= n; + } + + ring_buffer_iterator operator+(difference_type n) const { + return {container, front, index + n}; + } + ring_buffer_iterator operator-(difference_type n) const { + return {container, front, index - n}; + } + + reference operator*() { + return *(container->begin() + (front + index) % container->size()); + } + pointer operator->() { + return &**this; + } + reference operator[](difference_type n) { + return *(*this + n); + } + + ring_buffer_iterator& operator++() { + index++; + return *this; + } + ring_buffer_iterator operator++(int) { + ring_buffer_iterator old = *this; + *this++; + return old; + } + ring_buffer_iterator& operator--() { + index--; + return *this; + } + ring_buffer_iterator operator--(int) { + ring_buffer_iterator old = *this; + *this--; + return old; + } + + bool operator==(const ring_buffer_iterator& other) const { + return index == other.index; + } + bool operator!=(const ring_buffer_iterator& other) const { + return index != other.index; + } + + bool operator<(const ring_buffer_iterator& other) const { + return index < other.index; + } + bool operator>(const ring_buffer_iterator& other) const { + return index > other.index; + } + bool operator<=(const ring_buffer_iterator& other) const { + return index <= other.index; + } + bool operator>=(const ring_buffer_iterator& other) const { + return index >= other.index; + } + + friend ring_buffer_iterator operator+( difference_type n, const ring_buffer_iterator& it) { + return it + n; + } + friend void swap(ring_buffer_iterator& a, ring_buffer_iterator& b) { + using std::swap; + swap(a.container, b.container); + swap(a.front, b.front); + swap(a.index, b.index); + } +}; + +template +class ring_buffer_const_iterator { +private: + using size_type = typename Container::size_type; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + + const Container* container; + size_type front{}; + size_type index{}; + +public: + ring_buffer_const_iterator() = default; + ~ring_buffer_const_iterator() = default; + ring_buffer_const_iterator(const Container& container, size_type front = 0, size_type index = 0) : container(&container), front(front), index(index) {} + ring_buffer_const_iterator(const ring_buffer_const_iterator&) = default; + ring_buffer_const_iterator(ring_buffer_const_iterator&&) = default; + ring_buffer_const_iterator& operator=(const ring_buffer_const_iterator&) = default; + ring_buffer_const_iterator& operator=(ring_buffer_const_iterator&&) = default; + + ring_buffer_const_iterator& operator+=(difference_type n) { + index += n; + } + ring_buffer_const_iterator& operator-=(difference_type n) { + index -= n; + } + + ring_buffer_const_iterator operator+(difference_type n) const { + return {container, front, index + n}; + } + ring_buffer_const_iterator operator-(difference_type n) const { + return {container, front, index - n}; + } + + reference operator*() const { + return *(container->begin() + (front + index) % container->size()); + } + pointer operator->() const { + return &**this; + } + reference operator[](difference_type n) const { + return *(*this + n); + } + + ring_buffer_const_iterator& operator++() { + index++; + return *this; + } + ring_buffer_const_iterator operator++(int) { + ring_buffer_const_iterator old = *this; + *this++; + return old; + } + ring_buffer_const_iterator& operator--() { + index--; + return *this; + } + ring_buffer_const_iterator operator--(int) { + ring_buffer_const_iterator old = *this; + *this--; + return old; + } + + bool operator==(const ring_buffer_const_iterator& other) const { + return index == other.index; + } + bool operator!=(const ring_buffer_const_iterator& other) const { + return index != other.index; + } + + bool operator<(const ring_buffer_const_iterator& other) const { + return index < other.index; + } + bool operator>(const ring_buffer_const_iterator& other) const { + return index > other.index; + } + bool operator<=(const ring_buffer_const_iterator& other) const { + return index <= other.index; + } + bool operator>=(const ring_buffer_const_iterator& other) const { + return index >= other.index; + } + + friend ring_buffer_const_iterator operator+( difference_type n, const ring_buffer_const_iterator& it) { + return it + n; + } + friend void swap(ring_buffer_const_iterator& a, ring_buffer_const_iterator& b) { + using std::swap; + swap(a.container, b.container); + swap(a.front, b.front); + swap(a.index, b.index); + } +}; + +namespace std { + template + class iterator_traits> { + public: + using difference_type = typename std::make_signed::type; + using value_type = typename Container::value_type; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::random_access_iterator_tag; + }; + + template + class iterator_traits> { + public: + using difference_type = typename std::make_signed::type; + using value_type = const typename Container::value_type; + using pointer = const value_type*; + using reference = const value_type&; + using iterator_category = std::random_access_iterator_tag; + }; +} + +#endif diff --git a/include/ring-buffer.h b/include/ring-buffer.h index e291055..075dd91 100644 --- a/include/ring-buffer.h +++ b/include/ring-buffer.h @@ -1,198 +1,8 @@ -#include -#include -#include +#ifndef _RING_BUFFER_H +#define _RING_BUFFER_H -template -class ring_buffer_iterator { -private: - using size_type = typename Container::size_type; - using value_type = typename std::iterator_traits::value_type; - using difference_type = typename std::iterator_traits::difference_type; - using reference = typename std::iterator_traits::reference; - using pointer = typename std::iterator_traits::pointer; - - Container* container; - size_type front; - size_type index; - -public: - ring_buffer_iterator() = default; - ~ring_buffer_iterator() = default; - ring_buffer_iterator(Container& container, size_type front = 0, size_type index = 0) : container(&container), front(front), index(index) {} - ring_buffer_iterator(const ring_buffer_iterator&) = default; - ring_buffer_iterator(ring_buffer_iterator&&) = default; - ring_buffer_iterator& operator=(const ring_buffer_iterator&) = default; - ring_buffer_iterator& operator=(ring_buffer_iterator&&) = default; - - ring_buffer_iterator& operator+=(difference_type n) { - index += n; - } - ring_buffer_iterator& operator-=(difference_type n) { - index -= n; - } - - ring_buffer_iterator operator+(difference_type n) const { - return {container, front, index + n}; - } - ring_buffer_iterator operator-(difference_type n) const { - return {container, front, index - n}; - } - - reference operator*() { - return *(container->begin() + (front + index) % container->size()); - } - pointer operator->() { - return &**this; - } - reference operator[](difference_type n) { - return *(*this + n); - } - - ring_buffer_iterator& operator++() { - index++; - return *this; - } - ring_buffer_iterator operator++(int) { - ring_buffer_iterator old = *this; - *this++; - return old; - } - ring_buffer_iterator& operator--() { - index--; - return *this; - } - ring_buffer_iterator operator--(int) { - ring_buffer_iterator old = *this; - *this--; - return old; - } - - bool operator==(const ring_buffer_iterator& other) const { - return index == other.index; - } - bool operator!=(const ring_buffer_iterator& other) const { - return index != other.index; - } - - bool operator<(const ring_buffer_iterator& other) const { - return index < other.index; - } - bool operator>(const ring_buffer_iterator& other) const { - return index > other.index; - } - bool operator<=(const ring_buffer_iterator& other) const { - return index <= other.index; - } - bool operator>=(const ring_buffer_iterator& other) const { - return index >= other.index; - } - - friend ring_buffer_iterator operator+( difference_type n, const ring_buffer_iterator& it) { - return it + n; - } - friend void swap(ring_buffer_iterator& a, ring_buffer_iterator& b) { - using std::swap; - swap(a.container, b.container); - swap(a.front, b.front); - swap(a.index, b.index); - } -}; - -template -class ring_buffer_const_iterator { -private: - using size_type = typename Container::size_type; - using value_type = typename std::iterator_traits::value_type; - using difference_type = typename std::iterator_traits::difference_type; - using reference = typename std::iterator_traits::reference; - using pointer = typename std::iterator_traits::pointer; - - const Container* container; - size_type front{}; - size_type index{}; - -public: - ring_buffer_const_iterator() = default; - ~ring_buffer_const_iterator() = default; - ring_buffer_const_iterator(const Container& container, size_type front = 0, size_type index = 0) : container(&container), front(front), index(index) {} - ring_buffer_const_iterator(const ring_buffer_const_iterator&) = default; - ring_buffer_const_iterator(ring_buffer_const_iterator&&) = default; - ring_buffer_const_iterator& operator=(const ring_buffer_const_iterator&) = default; - ring_buffer_const_iterator& operator=(ring_buffer_const_iterator&&) = default; - - ring_buffer_const_iterator& operator+=(difference_type n) { - index += n; - } - ring_buffer_const_iterator& operator-=(difference_type n) { - index -= n; - } - - ring_buffer_const_iterator operator+(difference_type n) const { - return {container, front, index + n}; - } - ring_buffer_const_iterator operator-(difference_type n) const { - return {container, front, index - n}; - } - - reference operator*() const { - return *(container->begin() + (front + index) % container->size()); - } - pointer operator->() const { - return &**this; - } - reference operator[](difference_type n) const { - return *(*this + n); - } - - ring_buffer_const_iterator& operator++() { - index++; - return *this; - } - ring_buffer_const_iterator operator++(int) { - ring_buffer_const_iterator old = *this; - *this++; - return old; - } - ring_buffer_const_iterator& operator--() { - index--; - return *this; - } - ring_buffer_const_iterator operator--(int) { - ring_buffer_const_iterator old = *this; - *this--; - return old; - } - - bool operator==(const ring_buffer_const_iterator& other) const { - return index == other.index; - } - bool operator!=(const ring_buffer_const_iterator& other) const { - return index != other.index; - } - - bool operator<(const ring_buffer_const_iterator& other) const { - return index < other.index; - } - bool operator>(const ring_buffer_const_iterator& other) const { - return index > other.index; - } - bool operator<=(const ring_buffer_const_iterator& other) const { - return index <= other.index; - } - bool operator>=(const ring_buffer_const_iterator& other) const { - return index >= other.index; - } - - friend ring_buffer_const_iterator operator+( difference_type n, const ring_buffer_const_iterator& it) { - return it + n; - } - friend void swap(ring_buffer_const_iterator& a, ring_buffer_const_iterator& b) { - using std::swap; - swap(a.container, b.container); - swap(a.front, b.front); - swap(a.index, b.index); - } -}; +#include +#include template class basic_ring_buffer { @@ -207,8 +17,8 @@ private: size_type front_index{}; public: - basic_ring_buffer() noexcept = default; - ~basic_ring_buffer() noexcept = default; + CONSTEXPR basic_ring_buffer() NOEXCEPT() = default; + CONSTEXPR_D ~basic_ring_buffer() NOEXCEPT() = default; basic_ring_buffer(const basic_ring_buffer& other) = default; basic_ring_buffer(basic_ring_buffer&& other) = default; basic_ring_buffer& operator=(const basic_ring_buffer& other) = default; @@ -241,28 +51,8 @@ public: } }; -namespace std { - template - class iterator_traits> { - public: - using difference_type = typename std::make_signed::type; - using value_type = typename Container::value_type; - using pointer = value_type*; - using reference = value_type&; - using iterator_category = std::random_access_iterator_tag; - }; - - template - class iterator_traits> { - public: - using difference_type = typename std::make_signed::type; - using value_type = const typename Container::value_type; - using pointer = const value_type*; - using reference = const value_type&; - using iterator_category = std::random_access_iterator_tag; - }; -} - #include template using ring_buffer = basic_ring_buffer>; + +#endif