forked from Ferdi265/cxx-ring-buffer
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
6389462ce3 | |||
7859656ec2 | |||
3dc81a4e8e | |||
349a24bfdb | |||
010362d1f6 | |||
ab1a477757 | |||
4a019ad63c | |||
746672a6c1 | |||
1a8b098ed0 | |||
3bad408674 | |||
d9314150c2 | |||
5a6309dc28 | |||
795a4c3be7 | |||
5a021c46d0 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) [year] [fullname]
|
||||
|
||||
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.
|
@ -1,8 +1,5 @@
|
||||
try_compile(cxx-least-11 ${CMAKE_BINARY_DIR}/detect ${CMAKE_SOURCE_DIR}/detect/cxxstd.cpp
|
||||
COMPILE_DEFINITIONS -DCXX_STANDARD=201103
|
||||
CXX_STANDARD ${CMAKE_CXX_STANDARD}
|
||||
CXX_STANDARD_REQUIRED ${CMAKE_CXX_STANDARD_REQUIRED}
|
||||
CXX_EXTENSIONS ${CMAKE_CXX_EXTENSIONS}
|
||||
)
|
||||
|
||||
if(NOT cxx-least-11)
|
||||
@ -16,20 +13,13 @@ endif()
|
||||
|
||||
try_compile(cxx-least-14 ${CMAKE_BINARY_DIR}/detect ${CMAKE_SOURCE_DIR}/detect/cxxstd.cpp
|
||||
COMPILE_DEFINITIONS -DCXX_STANDARD=201402
|
||||
CXX_STANDARD ${CMAKE_CXX_STANDARD}
|
||||
CXX_STANDARD_REQUIRED ${CMAKE_CXX_STANDARD_REQUIRED}
|
||||
CXX_EXTENSIONS ${CMAKE_CXX_EXTENSIONS}
|
||||
)
|
||||
if(cxx-least-14)
|
||||
set(RING_BUFFER_CONSTEXPR ON)
|
||||
message(STATUS "Enabling RING_BUFFER_CONSTEXPR (C++14 and up)")
|
||||
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}
|
||||
)
|
||||
try_compile(constexpr-destructors-compile ${CMAKE_BINARY_DIR}/detect ${CMAKE_SOURCE_DIR}/detect/constexpr_destructors.cpp)
|
||||
if(constexpr-destructors-compile)
|
||||
set(RING_BUFFER_CONSTEXPR_DESTRUCTORS ON)
|
||||
message(STATUS "Enabling RING_BUFFER_CONSTEXPR_DESTRUCTORS (C++20 and up)")
|
||||
|
@ -41,6 +41,10 @@ public:
|
||||
return {*container_ptr, front, index - n};
|
||||
}
|
||||
|
||||
CONSTEXPR difference_type operator-(const ring_buffer_iterator& other) const NOEXCEPT {
|
||||
return index - other.index;
|
||||
}
|
||||
|
||||
CONSTEXPR reference operator*() COND_NOEXCEPT(noexcept(container_ptr->begin()) && noexcept(container_ptr->size())) {
|
||||
return *(container_ptr->begin() + (front + index) % container_ptr->size());
|
||||
}
|
||||
@ -57,7 +61,7 @@ public:
|
||||
}
|
||||
CONSTEXPR ring_buffer_iterator operator++(int) NOEXCEPT {
|
||||
ring_buffer_iterator old = *this;
|
||||
*this++;
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
CONSTEXPR ring_buffer_iterator& operator--() NOEXCEPT {
|
||||
@ -66,7 +70,7 @@ public:
|
||||
}
|
||||
CONSTEXPR ring_buffer_iterator operator--(int) NOEXCEPT {
|
||||
ring_buffer_iterator old = *this;
|
||||
*this--;
|
||||
--*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
@ -90,12 +94,12 @@ public:
|
||||
return index >= other.index;
|
||||
}
|
||||
|
||||
CONSTEXPR friend ring_buffer_iterator operator+( difference_type n, const ring_buffer_iterator& it) NOEXCEPT {
|
||||
CONSTEXPR friend ring_buffer_iterator operator+(difference_type n, const ring_buffer_iterator& it) NOEXCEPT {
|
||||
return it + n;
|
||||
}
|
||||
CONSTEXPR friend void swap(ring_buffer_iterator& a, ring_buffer_iterator& b) COND_NOEXCEPT(noexcept(std::swap(a.container, b.container))) {
|
||||
CONSTEXPR friend void swap(ring_buffer_iterator& a, ring_buffer_iterator& b) NOEXCEPT {
|
||||
using std::swap;
|
||||
swap(a.container, b.container);
|
||||
swap(a.container_ptr, b.container_ptr);
|
||||
swap(a.front, b.front);
|
||||
swap(a.index, b.index);
|
||||
}
|
||||
@ -137,6 +141,10 @@ public:
|
||||
return {*container_ptr, front, index - n};
|
||||
}
|
||||
|
||||
CONSTEXPR difference_type operator-(const ring_buffer_const_iterator& other) const NOEXCEPT {
|
||||
return index - other.index;
|
||||
}
|
||||
|
||||
CONSTEXPR reference operator*() const COND_NOEXCEPT(noexcept(container_ptr->cbegin()) && noexcept(container_ptr->size())) {
|
||||
return *(container_ptr->cbegin() + (front + index) % container_ptr->size());
|
||||
}
|
||||
@ -153,7 +161,7 @@ public:
|
||||
}
|
||||
CONSTEXPR ring_buffer_const_iterator operator++(int) NOEXCEPT {
|
||||
ring_buffer_const_iterator old = *this;
|
||||
*this++;
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
CONSTEXPR ring_buffer_const_iterator& operator--() NOEXCEPT {
|
||||
@ -162,7 +170,7 @@ public:
|
||||
}
|
||||
CONSTEXPR ring_buffer_const_iterator operator--(int) NOEXCEPT {
|
||||
ring_buffer_const_iterator old = *this;
|
||||
*this--;
|
||||
--*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
@ -186,12 +194,12 @@ public:
|
||||
return index >= other.index;
|
||||
}
|
||||
|
||||
CONSTEXPR friend ring_buffer_const_iterator operator+( difference_type n, const ring_buffer_const_iterator& it) NOEXCEPT {
|
||||
CONSTEXPR friend ring_buffer_const_iterator operator+(difference_type n, const ring_buffer_const_iterator& it) NOEXCEPT {
|
||||
return it + n;
|
||||
}
|
||||
CONSTEXPR friend void swap(ring_buffer_const_iterator& a, ring_buffer_const_iterator& b) COND_NOEXCEPT(noexcept(std::swap(a.container, b.container))) {
|
||||
CONSTEXPR friend void swap(ring_buffer_const_iterator& a, ring_buffer_const_iterator& b) NOEXCEPT {
|
||||
using std::swap;
|
||||
swap(a.container, b.container);
|
||||
swap(a.container_ptr, b.container_ptr);
|
||||
swap(a.front, b.front);
|
||||
swap(a.index, b.index);
|
||||
}
|
||||
|
@ -6,6 +6,14 @@
|
||||
#include <ring-buffer-config.h>
|
||||
#include <ring-buffer-iterator.h>
|
||||
|
||||
namespace detail {
|
||||
using std::swap;
|
||||
template <typename T>
|
||||
CONSTEXPR void adl_swap(T& a, T&b ) COND_NOEXCEPT(noexcept(swap(a, b))) {
|
||||
swap(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
class basic_ring_buffer {
|
||||
public:
|
||||
@ -22,7 +30,7 @@ public:
|
||||
basic_ring_buffer() = default;
|
||||
~basic_ring_buffer() = default;
|
||||
CONSTEXPR basic_ring_buffer(const Container& other) COND_NOEXCEPT(noexcept(Container(other))) : container(other) {}
|
||||
CONSTEXPR basic_ring_buffer(Container&& other) COND_NOEXCEPT(noexcept(Container(other))) : container(other) {}
|
||||
CONSTEXPR basic_ring_buffer(Container&& other) COND_NOEXCEPT(noexcept(Container(std::move(other)))) : container(std::move(other)) {}
|
||||
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;
|
||||
@ -71,6 +79,11 @@ public:
|
||||
CONSTEXPR const_iterator cend() const COND_NOEXCEPT(noexcept(container.size())) {
|
||||
return {container, front_index, container.size()};
|
||||
}
|
||||
CONSTEXPR friend void swap(basic_ring_buffer& a, basic_ring_buffer& b) COND_NOEXCEPT(noexcept(detail::adl_swap(a.container, b.container))) {
|
||||
using std::swap;
|
||||
swap(a.container, b.container);
|
||||
swap(a.front_index, b.front_index);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cxx-ring-buffer",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"build": {
|
||||
"includeDir": "include",
|
||||
"srcFilter":
|
||||
|
@ -1,11 +1,12 @@
|
||||
#ifndef _CONSTEXPR_ARRAY_SHIM_H
|
||||
#define _CONSTEXPR_ARRAY_SHIM_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <array>
|
||||
|
||||
#if defined( __cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201606L
|
||||
template <typename T, size_t N>
|
||||
using constexpr_array = array;
|
||||
using constexpr_array = std::array<T, N>;
|
||||
#else
|
||||
template <typename T, size_t N>
|
||||
struct constexpr_array {
|
||||
|
24
test/iterator-ops.cpp
Normal file
24
test/iterator-ops.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <ring-buffer.h>
|
||||
|
||||
int main() {
|
||||
ring_buffer<int, 4> buf;
|
||||
|
||||
buf.push_back(1);
|
||||
buf.push_back(2);
|
||||
buf.push_back(3);
|
||||
buf.push_back(4);
|
||||
buf.push_back(5);
|
||||
buf.push_back(6);
|
||||
|
||||
{
|
||||
auto it = buf.begin();
|
||||
++it;
|
||||
it++;
|
||||
assert(*it == 5);
|
||||
--it;
|
||||
it--;
|
||||
assert(*it == 3);
|
||||
}
|
||||
}
|
77
test/non-swappable-ring-buffer.cpp
Normal file
77
test/non-swappable-ring-buffer.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <ring-buffer.h>
|
||||
|
||||
struct non_swappable_array {
|
||||
using value_type = int;
|
||||
using size_type = size_t;
|
||||
int data[4];
|
||||
|
||||
// non-copyable
|
||||
non_swappable_array() = default;
|
||||
non_swappable_array(const non_swappable_array&) = delete;
|
||||
non_swappable_array& operator=(const non_swappable_array&) = delete;
|
||||
|
||||
size_t size() const {
|
||||
return 4;
|
||||
}
|
||||
|
||||
int * begin() {
|
||||
return std::begin(data);
|
||||
}
|
||||
|
||||
int * end() {
|
||||
return std::end(data);
|
||||
}
|
||||
|
||||
const int * cbegin() const {
|
||||
return std::cbegin(data);
|
||||
}
|
||||
|
||||
const int * cend() const {
|
||||
return std::cend(data);
|
||||
}
|
||||
|
||||
int& operator[](size_t i) {
|
||||
return data[i];
|
||||
}
|
||||
|
||||
const int& operator[](size_t i) const {
|
||||
return data[i];
|
||||
}
|
||||
|
||||
// note: no swap implementation
|
||||
};
|
||||
|
||||
int main() {
|
||||
basic_ring_buffer<non_swappable_array> buf;
|
||||
|
||||
buf.push_back(1);
|
||||
buf.push_back(2);
|
||||
buf.push_back(3);
|
||||
buf.push_back(4);
|
||||
buf.push_back(5);
|
||||
buf.push_back(6);
|
||||
|
||||
{
|
||||
std::vector<int> expected{13, 14, 15, 16};
|
||||
std::vector<int> actual;
|
||||
for (int& i : buf) {
|
||||
i += 10;
|
||||
actual.push_back(i);
|
||||
}
|
||||
assert(actual == expected);
|
||||
}
|
||||
|
||||
buf.push_back(7);
|
||||
|
||||
{
|
||||
std::vector<int> expected{24, 25, 26, 17};
|
||||
std::vector<int> actual;
|
||||
for (int& i : buf) {
|
||||
i += 10;
|
||||
actual.push_back(i);
|
||||
}
|
||||
assert(actual == expected);
|
||||
}
|
||||
}
|
33
test/swap-ring-buffer-iterator.cpp
Normal file
33
test/swap-ring-buffer-iterator.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <ring-buffer.h>
|
||||
#include <utility>
|
||||
|
||||
int main() {
|
||||
ring_buffer<int, 4> buf1;
|
||||
|
||||
buf1.push_back(1);
|
||||
buf1.push_back(2);
|
||||
buf1.push_back(3);
|
||||
buf1.push_back(4);
|
||||
buf1.push_back(5);
|
||||
buf1.push_back(6);
|
||||
|
||||
ring_buffer<int, 4> buf2;
|
||||
|
||||
buf2.push_back(10);
|
||||
buf2.push_back(20);
|
||||
buf2.push_back(30);
|
||||
buf2.push_back(40);
|
||||
buf2.push_back(50);
|
||||
buf2.push_back(60);
|
||||
|
||||
auto it1 = buf1.begin();
|
||||
auto it2 = buf2.begin();
|
||||
std::swap(it1, it2);
|
||||
|
||||
{
|
||||
assert(*it1 == 30);
|
||||
assert(*it2 == 3);
|
||||
}
|
||||
}
|
44
test/swap-ring-buffer.cpp
Normal file
44
test/swap-ring-buffer.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <ring-buffer.h>
|
||||
#include <utility>
|
||||
|
||||
int main() {
|
||||
ring_buffer<int, 4> buf1;
|
||||
|
||||
buf1.push_back(1);
|
||||
buf1.push_back(2);
|
||||
buf1.push_back(3);
|
||||
buf1.push_back(4);
|
||||
buf1.push_back(5);
|
||||
buf1.push_back(6);
|
||||
|
||||
ring_buffer<int, 4> buf2;
|
||||
|
||||
buf2.push_back(10);
|
||||
buf2.push_back(20);
|
||||
buf2.push_back(30);
|
||||
buf2.push_back(40);
|
||||
buf2.push_back(50);
|
||||
buf2.push_back(60);
|
||||
|
||||
std::swap(buf1, buf2);
|
||||
|
||||
{
|
||||
std::vector<int> expected{30, 40, 50, 60};
|
||||
std::vector<int> actual;
|
||||
for (int& i : buf1) {
|
||||
actual.push_back(i);
|
||||
}
|
||||
assert(actual == expected);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> expected{3, 4, 5, 6};
|
||||
std::vector<int> actual;
|
||||
for (int& i : buf2) {
|
||||
actual.push_back(i);
|
||||
}
|
||||
assert(actual == expected);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user