Skip to content

Commit ed71229

Browse files
committed
initial circular buffer implementation
1 parent fccbc96 commit ed71229

File tree

4 files changed

+357
-0
lines changed

4 files changed

+357
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
//
2+
//
3+
// uti
4+
// core/container/circular_buffer.hxx
5+
//
6+
7+
#pragma once
8+
9+
#include <uti/core/util/assert.hxx>
10+
#include <uti/core/type/traits.hxx>
11+
#include <uti/core/meta/concepts.hxx>
12+
13+
#include <uti/core/allocator/meta.hxx>
14+
15+
#include <uti/core/iterator/meta.hxx>
16+
#include <uti/core/iterator/circular_iterator.hxx>
17+
#include <uti/core/iterator/reverse_iterator.hxx>
18+
19+
20+
namespace uti
21+
{
22+
23+
24+
////////////////////////////////////////////////////////////////////////////////
25+
26+
template< meta::arithmetic T, ssize_t Capacity >
27+
class circular_buffer
28+
{
29+
static constexpr ssize_t capacity_ { Capacity } ;
30+
public:
31+
using value_type = T ;
32+
using size_type = size_t ;
33+
using ssize_type = ssize_t ;
34+
using difference_type = ssize_t ;
35+
36+
using pointer = value_type * ;
37+
using const_pointer = value_type const * ;
38+
using reference = value_type & ;
39+
using const_reference = value_type const & ;
40+
41+
using iterator = circular_iterator< circular_buffer > ;
42+
using const_iterator = circular_iterator< circular_buffer const > ;
43+
using reverse_iterator = ::uti::reverse_iterator< iterator > ;
44+
using const_reverse_iterator = ::uti::reverse_iterator< const_iterator > ;
45+
46+
using buffer_iterator = iterator_base< value_type , random_access_iterator_tag > ;
47+
using const_buffer_iterator = iterator_base< value_type const, random_access_iterator_tag > ;
48+
using reverse_buffer_iterator = ::uti::reverse_iterator< iterator > ;
49+
using const_reverse_buffer_iterator = ::uti::reverse_iterator< const_iterator > ;
50+
51+
constexpr circular_buffer () noexcept = default ;
52+
constexpr ~circular_buffer () noexcept = default ;
53+
54+
constexpr circular_buffer ( ssize_type _count_, value_type const & _value_ ) noexcept ;
55+
56+
constexpr void push_back ( value_type const & _value_ ) noexcept ;
57+
58+
UTI_NODISCARD constexpr ssize_type capacity () const noexcept { return capacity_ ; }
59+
UTI_NODISCARD constexpr ssize_type size () const noexcept { return _size() ; }
60+
UTI_NODISCARD constexpr bool empty () const noexcept { return begin_ == end_ ; }
61+
62+
UTI_NODISCARD constexpr pointer data () noexcept { return data_ ; }
63+
UTI_NODISCARD constexpr const_pointer data () const noexcept { return data_ ; }
64+
65+
UTI_NODISCARD constexpr iterator begin () noexcept { return iterator( *this, begin_, 0 ) ; }
66+
UTI_NODISCARD constexpr const_iterator begin () const noexcept { return const_iterator( *this, begin_, 0 ) ; }
67+
UTI_NODISCARD constexpr const_iterator cbegin () const noexcept { return begin() ; }
68+
69+
UTI_NODISCARD constexpr iterator end () noexcept { return iterator( *this, end_ + 1, size() ) ; }
70+
UTI_NODISCARD constexpr const_iterator end () const noexcept { return const_iterator( *this, end_ + 1, size() ) ; }
71+
UTI_NODISCARD constexpr const_iterator cend () const noexcept { return end() ; }
72+
73+
UTI_NODISCARD constexpr buffer_iterator buffer_begin () noexcept { return buffer_iterator( data_ ) ; }
74+
UTI_NODISCARD constexpr const_buffer_iterator buffer_begin () const noexcept { return const_buffer_iterator( data_ ) ; }
75+
UTI_NODISCARD constexpr const_buffer_iterator buffer_cbegin () const noexcept { return const_buffer_iterator( data_ ) ; }
76+
77+
UTI_NODISCARD constexpr buffer_iterator buffer_end () noexcept { return buffer_iterator( data_ + capacity_ ) ; }
78+
UTI_NODISCARD constexpr const_buffer_iterator buffer_end () const noexcept { return const_buffer_iterator( data_ + capacity_ ) ; }
79+
UTI_NODISCARD constexpr const_buffer_iterator buffer_cend () const noexcept { return const_buffer_iterator( data_ + capacity_ ) ; }
80+
private:
81+
value_type data_ [ capacity_ ] {} ;
82+
83+
pointer begin_ { data_ } ;
84+
pointer end_ { data_ } ;
85+
86+
bool full_ { false } ;
87+
88+
constexpr ssize_type _size () const noexcept { return full_ ? capacity_ : end_ - begin_ ; }
89+
} ;
90+
91+
////////////////////////////////////////////////////////////////////////////////
92+
////////////////////////////////////////////////////////////////////////////////
93+
94+
template< meta::arithmetic T, ssize_t Capacity >
95+
constexpr
96+
circular_buffer< T, Capacity >::circular_buffer ( ssize_type _count_, value_type const & _value_ ) noexcept
97+
{
98+
if( _count_ > capacity() ) _count_ = capacity() ;
99+
100+
for( ssize_type i = 0; i < _count_; ++i )
101+
{
102+
push_back( _value_ ) ;
103+
}
104+
}
105+
106+
////////////////////////////////////////////////////////////////////////////////
107+
108+
template< meta::arithmetic T, ssize_t Capacity >
109+
constexpr void
110+
circular_buffer< T, Capacity >::push_back ( value_type const & _value_ ) noexcept
111+
{
112+
*end_ = _value_ ;
113+
114+
if( full_ )
115+
{
116+
UTI_CEXPR_ASSERT( begin_ == end_, "uti::circular_buffer::push_back : internal error 116" ) ;
117+
118+
if( begin_ >= buffer_end() - 1 )
119+
{
120+
begin_ = buffer_begin() ;
121+
end_ = buffer_begin() ;
122+
}
123+
else
124+
{
125+
++begin_ ;
126+
++end_ ;
127+
}
128+
}
129+
else
130+
{
131+
UTI_CEXPR_ASSERT( begin_ == buffer_begin(), "uti::circular_buffer::push_back : internal error 131" ) ;
132+
133+
if( end_ >= buffer_end() - 1 )
134+
{
135+
end_ = buffer_begin() ;
136+
full_ = true ;
137+
}
138+
else
139+
{
140+
++end_ ;
141+
}
142+
}
143+
}
144+
145+
////////////////////////////////////////////////////////////////////////////////
146+
147+
148+
} // namespace uti

include/uti/core/iterator/base.hxx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ public:
235235
_rhs_.ptr_ = _tmp_ ;
236236
}
237237

238+
friend constexpr bool operator== ( iterator_base const & _lhs_, pointer const & _rhs_ ) noexcept
239+
{
240+
return _lhs_.ptr_ == _rhs_ ;
241+
}
242+
friend constexpr bool operator== ( pointer const & _lhs_, iterator_base const & _rhs_ ) noexcept
243+
{
244+
return _lhs_ == _rhs_.ptr_ ;
245+
}
246+
238247
friend constexpr bool operator== ( iterator_base const & _lhs_,
239248
iterator_base< remove_const_t< T >, IterCat, DiffType, add_pointer_t< remove_const_t< T > >,
240249
add_lvalue_reference_t< remove_const_t< T > > > const & _rhs_ ) noexcept
@@ -264,6 +273,54 @@ public:
264273
return _lhs_.ptr_ >= _rhs_.ptr_ ;
265274
}
266275

276+
friend constexpr bool operator< ( iterator_base const & _lhs_, pointer const & _rhs_ ) noexcept
277+
requires _has_random_access_iterator_category_v< _self >
278+
{
279+
return _lhs_.ptr_ < _rhs_ ;
280+
}
281+
282+
friend constexpr bool operator> ( iterator_base const & _lhs_, pointer const & _rhs_ ) noexcept
283+
requires _has_random_access_iterator_category_v< _self >
284+
{
285+
return _lhs_.ptr_ > _rhs_ ;
286+
}
287+
288+
friend constexpr bool operator<= ( iterator_base const & _lhs_, pointer const & _rhs_ ) noexcept
289+
requires _has_random_access_iterator_category_v< _self >
290+
{
291+
return _lhs_.ptr_ <= _rhs_ ;
292+
}
293+
294+
friend constexpr bool operator>= ( iterator_base const & _lhs_, pointer const & _rhs_ ) noexcept
295+
requires _has_random_access_iterator_category_v< _self >
296+
{
297+
return _lhs_.ptr_ >= _rhs_ ;
298+
}
299+
300+
friend constexpr bool operator< ( pointer const & _lhs_, iterator_base const & _rhs_ ) noexcept
301+
requires _has_random_access_iterator_category_v< _self >
302+
{
303+
return _lhs_ < _rhs_.ptr_ ;
304+
}
305+
306+
friend constexpr bool operator> ( pointer const & _lhs_, iterator_base const & _rhs_ ) noexcept
307+
requires _has_random_access_iterator_category_v< _self >
308+
{
309+
return _lhs_ > _rhs_.ptr_ ;
310+
}
311+
312+
friend constexpr bool operator<= ( pointer const & _lhs_, iterator_base const & _rhs_ ) noexcept
313+
requires _has_random_access_iterator_category_v< _self >
314+
{
315+
return _lhs_ <= _rhs_.ptr_ ;
316+
}
317+
318+
friend constexpr bool operator>= ( pointer const & _lhs_, iterator_base const & _rhs_ ) noexcept
319+
requires _has_random_access_iterator_category_v< _self >
320+
{
321+
return _lhs_ >= _rhs_.ptr_ ;
322+
}
323+
267324
friend constexpr bool operator< ( iterator_base const & _lhs_,
268325
iterator_base< remove_const_t< T >, IterCat, DiffType, add_pointer_t< remove_const_t< T > >,
269326
add_lvalue_reference_t< remove_const_t< T > > > const & _rhs_ ) noexcept
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//
2+
//
3+
// uti
4+
// core/iterator/circular_iterator.hxx
5+
//
6+
7+
#pragma once
8+
9+
#include <uti/core/iterator/meta.hxx>
10+
#include <uti/core/iterator/base.hxx>
11+
#include <uti/core/container/meta.hxx>
12+
13+
14+
namespace uti
15+
{
16+
17+
18+
////////////////////////////////////////////////////////////////////////////////
19+
20+
namespace meta
21+
{
22+
23+
24+
template< typename T >
25+
concept circular_container = requires( T & t, T const & ct )
26+
{
27+
simple_container< T > ;
28+
29+
{ T:: buffer_iterator } -> random_access_iterator ;
30+
{ T:: const_buffer_iterator } -> random_access_iterator ;
31+
{ T:: reverse_buffer_iterator } -> random_access_iterator ;
32+
{ T::const_reverse_buffer_iterator } -> random_access_iterator ;
33+
34+
{ t.buffer_begin() } -> same_as< typename T:: buffer_iterator > ;
35+
{ t.buffer_end () } -> same_as< typename T:: buffer_iterator > ;
36+
{ ct.buffer_begin() } -> same_as< typename T::const_buffer_iterator > ;
37+
{ ct.buffer_end () } -> same_as< typename T::const_buffer_iterator > ;
38+
} ;
39+
40+
41+
} // namespace meta
42+
43+
////////////////////////////////////////////////////////////////////////////////
44+
45+
template< typename T >
46+
class circular_iterator : public iterator_base< conditional_t< is_const_v< T >, typename T::value_type const, typename T::value_type >, circular_iterator_tag >
47+
{
48+
// static_assert( meta::circular_container< T > ) ;
49+
50+
using _self = circular_iterator ;
51+
using _base = iterator_base< conditional_t< is_const_v< T >, typename T::value_type const, typename T::value_type >, circular_iterator_tag > ;
52+
53+
using buffer_type = T ;
54+
public:
55+
using value_type = typename _base:: value_type ;
56+
using pointer = typename _base:: pointer ;
57+
using reference = typename _base:: reference ;
58+
using difference_type = typename _base:: difference_type ;
59+
using iterator_category = typename _base::iterator_category ;
60+
61+
constexpr circular_iterator ( buffer_type & _buffer_, pointer _ptr_, difference_type const _index_ ) noexcept : _base( _ptr_ ), buffer_{ _buffer_ }, index_{ _index_ } {}
62+
63+
constexpr circular_iterator & operator++ () noexcept
64+
{
65+
if( this->ptr_ >= buffer_.buffer_end() - 1 )
66+
{
67+
this->ptr_ = buffer_.buffer_begin() ;
68+
}
69+
else
70+
{
71+
++this->ptr_ ;
72+
}
73+
++index_ ;
74+
75+
return *this ;
76+
}
77+
constexpr circular_iterator operator++ ( int ) noexcept { auto prev = *this ; ++*this ; return prev ; }
78+
79+
constexpr circular_iterator & operator-- () noexcept
80+
{
81+
if( this->ptr_ == buffer_.buffer_begin() )
82+
{
83+
this->ptr_ = buffer_.buffer_end() - 1 ;
84+
}
85+
else
86+
{
87+
--this->ptr_ ;
88+
}
89+
--index_ ;
90+
91+
return *this ;
92+
}
93+
constexpr circular_iterator operator-- ( int ) noexcept { auto prev = *this ; --*this ; return prev ; }
94+
95+
constexpr circular_iterator & operator+= ( difference_type const _n_ ) noexcept ;
96+
constexpr circular_iterator & operator-= ( difference_type const _n_ ) noexcept ;
97+
98+
friend constexpr bool operator< ( circular_iterator const & _lhs_, circular_iterator const & _rhs_ ) noexcept { return _lhs_.index() < _rhs_.index() ; }
99+
friend constexpr bool operator> ( circular_iterator const & _lhs_, circular_iterator const & _rhs_ ) noexcept { return _lhs_.index() > _rhs_.index() ; }
100+
friend constexpr bool operator<= ( circular_iterator const & _lhs_, circular_iterator const & _rhs_ ) noexcept { return _lhs_.index() <= _rhs_.index() ; }
101+
friend constexpr bool operator>= ( circular_iterator const & _lhs_, circular_iterator const & _rhs_ ) noexcept { return _lhs_.index() >= _rhs_.index() ; }
102+
103+
friend constexpr bool operator== ( circular_iterator const & _lhs_, circular_iterator const & _rhs_ ) noexcept { return _lhs_.index() == _rhs_.index() ; }
104+
friend constexpr bool operator!= ( circular_iterator const & _lhs_, circular_iterator const & _rhs_ ) noexcept { return _lhs_.index() != _rhs_.index() ; }
105+
106+
friend constexpr bool operator< ( circular_iterator const & _lhs_ ,
107+
circular_iterator< remove_const_t< T > > const & _rhs_ ) noexcept
108+
requires is_const_v< T >
109+
{
110+
return _lhs_.index() < _rhs_.index() ;
111+
}
112+
113+
friend constexpr bool operator> ( circular_iterator const & _lhs_ ,
114+
circular_iterator< remove_const_t< T > > const & _rhs_ ) noexcept
115+
requires is_const_v< T >
116+
{
117+
return _lhs_.index() > _rhs_.index() ;
118+
}
119+
120+
friend constexpr bool operator< ( circular_iterator const & _lhs_ ,
121+
circular_iterator< T const > const & _rhs_ ) noexcept
122+
requires( !is_const_v< T > )
123+
{
124+
return _lhs_.index() < _rhs_.index() ;
125+
}
126+
127+
friend constexpr bool operator> ( circular_iterator const & _lhs_ ,
128+
circular_iterator< T const > const & _rhs_ ) noexcept
129+
requires( !is_const_v< T > )
130+
{
131+
return _lhs_.index() > _rhs_.index() ;
132+
}
133+
134+
constexpr difference_type index () const noexcept
135+
{
136+
return index_ ;
137+
}
138+
private:
139+
buffer_type & buffer_ ;
140+
difference_type index_ ;
141+
} ;
142+
143+
////////////////////////////////////////////////////////////////////////////////
144+
145+
146+
} // namespace uti

include/uti/core/iterator/meta.hxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct bidirectional_iterator_tag : public forward_iterator_tag {} ;
144144
struct random_access_iterator_tag : public bidirectional_iterator_tag {} ;
145145
struct contiguous_iterator_tag : public random_access_iterator_tag {} ;
146146
struct prefix_array_iterator_tag : public random_access_iterator_tag {} ;
147+
struct circular_iterator_tag : public random_access_iterator_tag {} ;
147148

148149
////////////////////////////////////////////////////////////////////////////////
149150

@@ -310,6 +311,11 @@ concept prefix_array_iterator =
310311
random_access_iterator< Iter > &&
311312
same_as< typename iterator_traits< Iter >::iterator_category, prefix_array_iterator_tag > ;
312313

314+
template< typename Iter >
315+
concept circular_iterator =
316+
random_access_iterator< Iter > &&
317+
same_as< typename iterator_traits< Iter >::iterator_category, circular_iterator_tag > ;
318+
313319

314320
} // namespace meta
315321

0 commit comments

Comments
 (0)