Bonita Montero
2024-09-20 13:18:22 UTC
Just a ring-buffer with functional access:
#pragma once
#include <utility>
#include <cassert>
#include <memory>
#include <span>
#include "invoke_on_destruct.h"
#include "nui.h"
#if defined(__llvm__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wparentheses"
#pragma clang diagnostic ignored "-Wunqualified-std-cast-call"
#endif
template<typename T, typename Alloc = std::allocator<T>>
struct ring_deque
{
ring_deque( ptrdiff_t capacity = 0, Alloc const &alloc = Alloc() );
~ring_deque();
ring_deque( ring_deque<T, Alloc> const &other );
ring_deque( ring_deque<T, Alloc> &&other ) noexcept;
ring_deque<T, Alloc> &operator =( ring_deque<T, Alloc> const &other );
ring_deque<T, Alloc> &operator =( ring_deque<T, Alloc> &&other ) noexcept;
template<bool Forward, typename Consumer>
void scan( Consumer consumer )
requires requires( T &value ) { { consumer( value ) }; };
template<bool Forward, typename Consumer>
void scan( Consumer consumer ) const
requires requires( T const &value ) { { consumer( value ) }; };
T &front() noexcept;
T const &front() const noexcept;
T &back() noexcept;
T const &back() const noexcept;
template<bool Forward, typename Consumer>
size_t consume( Consumer consumer )
requires requires( T &value ) { { consumer( value ) } ->
std::same_as<int>; };
template<bool Back, typename ... Args>
T &emplace( Args &&... args )
requires std::is_constructible_v<T, Args ...>;
void pop_back() noexcept;
void pop_front() noexcept;
void pop_n( ptrdiff_t n ) noexcept;
void shrink_to_fit();
bool empty() const noexcept;
size_t size() const noexcept;
size_t capacity() const noexcept;
void clear();
T &operator []( ptrdiff_t i ) noexcept;
T const &operator []( ptrdiff_t i ) const noexcept;
void reserve( ptrdiff_t capacity );
private:
using span_t = std::span<T>;
span_t allocRing( size_t capacity );
void freeRing( span_t sp );
template<bool Forward, typename Consumer>
void scanInternal( Consumer consumer );
template<bool Forward, typename Consumer>
void scanInternal( span_t::iterator &it, Consumer consumer );
void grow();
void reCap( ptrdiff_t capacity );
static size_t normCap( ptrdiff_t capacity );
using alloc_t = Alloc;
NO_UNIQUE_ADDRESS alloc_t m_alloc;
span_t m_ring;
span_t::iterator m_front, m_back;
size_t m_n;
};
template<typename T, typename Alloc>
ring_deque<T, Alloc>::ring_deque( ptrdiff_t capacity, Alloc const &alloc ) :
m_alloc( alloc ),
m_ring( allocRing( normCap( capacity ) ) ),
m_front( m_ring.begin() ),
m_back( m_ring.begin() ),
m_n( 0 )
{
}
template<typename T, typename Alloc>
ring_deque<T, Alloc>::~ring_deque()
{
consume<true>( [&]( T & ) -> int { return 1; } );
freeRing( m_ring );
}
template<typename T, typename Alloc>
ring_deque<T, Alloc>::ring_deque( ring_deque<T, Alloc> const &other ) :
ring_deque( other.m_n, other.m_alloc )
{
invoke_on_destruct reset( [&] { this->~ring_deque(); } );
other.scanInternal<true>( [&]( T const &value ) { emplace_back( value
); return true; } );
reset.disable();
}
template<typename T, typename Alloc>
ring_deque<T, Alloc>::ring_deque( ring_deque<T, Alloc> &&other ) noexcept :
m_alloc( other.m_alloc ),
m_ring( other.m_ring ),
m_front( other.m_front ),
m_back( other.m_back ),
m_n( other.m_n )
{
other.m_ring = span_t();
other.m_n = 0;
#if !defined(NDEBUG)
other.m_front = span_t().begin();
other.m_back = span_t().begin();
#endif
}
template<typename T, typename Alloc>
ring_deque<T, Alloc> &ring_deque<T, Alloc>::operator =( ring_deque<T,
Alloc> const &other )
{
clear();
reserve( other.size() );
other.scanInternal<true>( [&]( T const &value ) { emplace_back( value
); return true; } );
return *this;
}
template<typename T, typename Alloc>
ring_deque<T, Alloc> &ring_deque<T, Alloc>::operator =( ring_deque<T,
Alloc> &&other ) noexcept
{
freeRing( m_ring );
m_alloc = other.m_alloc;
m_ring = other.m_ring;
m_front = other.m_front;
m_back = other.m_back;
m_n = other.m_n;
other.m_ring = span_t();
other.m_n = 0;
#if !defined(NDEBUG)
other.m_front = span_t().begin();
other.m_back = span_t().begin();
#endif
return *this;
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scan( Consumer consumer )
requires requires( T &value ) { { consumer( value ) }; }
{
using namespace std;
scanInternal<Forward>( [&]( T &value )
{
bool ret = true;
if constexpr( requires() { { consumer( value ) } ->
convertible_to<bool>; } )
ret = consumer( value );
else
consumer( value );
return ret;
} );
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scan( Consumer consumer ) const
requires requires( T const &value ) { { consumer( value ) }; }
{
const_cast<ring_deque<T, Alloc> *>(this)->scan<Forward>( [&]( T &value
) { return consumer( value ); } );
}
template<typename T, typename Alloc>
inline T &ring_deque<T, Alloc>::front() noexcept
{
assert(m_n);
return *m_front;
}
template<typename T, typename Alloc>
inline T const &ring_deque<T, Alloc>::front() const noexcept
{
assert(m_n);
return *m_front;
}
template<typename T, typename Alloc>
inline T &ring_deque<T, Alloc>::back() noexcept
{
assert(m_n);
return m_back[-1];
}
template<typename T, typename Alloc>
inline T const &ring_deque<T, Alloc>::back() const noexcept
{
assert(m_n);
return m_back[-1];
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline size_t ring_deque<T, Alloc>::consume( Consumer consumer )
requires requires( T &value ) { { consumer( value ) } ->
std::same_as<int>; }
{
size_t nInitial = m_n;
typename span_t::iterator it = Forward ? m_front : m_back;
invoke_on_destruct adjust( [&] { (Forward ? m_front : m_back) = it; } );
scanInternal<Forward>( it, [&]( T &value ) -> bool
{
int cont = consumer( value );
if( cont >= 0 ) [[likely]]
{
value.~T();
--m_n;
}
return cont > 0;
} );
return nInitial - m_n;
}
template<typename T, typename Alloc>
template<bool Back, typename ... Args>
T &ring_deque<T, Alloc>::emplace( Args &&... args )
requires std::is_constructible_v<T, Args ...>
{
using namespace std;
assert(m_ring.size() >= m_n);
if( m_n == m_ring.size() ) [[unlikely]]
grow();
auto next = Back ? m_back : m_front;
if( next == (Back ? m_ring.end() : m_ring.begin()) ) [[unlikely]]
next = Back ? m_ring.begin() : m_ring.end();
next -= !Back;
new( (void *)&*next ) T( forward<Args>( args ) ... );
next += Back;
(Back ? m_back : m_front) = next;
++m_n;
return *(Back ? m_back - 1 : m_front);
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::pop_back() noexcept
{
assert(m_n);
(*--m_back).~T();
if( m_back == m_ring.begin() ) [[unlikely]]
m_back = m_ring.end();
--m_n;
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::pop_front() noexcept
{
assert(m_n);
(*m_front++).~T();
if( m_front == m_ring.end() ) [[unlikely]]
m_front = m_ring.begin();
--m_n;
}
template<typename T, typename Alloc>
void ring_deque<T, Alloc>::pop_n( ptrdiff_t n ) noexcept
{
if( n > 0 )
{
assert(m_n >= (size_t)n);
size_t dest = m_n - n;
consume<true>( [&]( T &value ) -> int { return --m_n != dest; } );
}
else if( n < 0 )
{
assert(m_n >= (size_t)-n);
size_t dest = m_n - -n;
consume<false>( [&]( T &value ) -> int { return --m_n != dest; } );
}
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::shrink_to_fit()
{
reCap( m_n );
}
template<typename T, typename Alloc>
inline bool ring_deque<T, Alloc>::empty() const noexcept
{
return !size();
}
template<typename T, typename Alloc>
inline size_t ring_deque<T, Alloc>::size() const noexcept
{
return m_n;
}
template<typename T, typename Alloc>
inline size_t ring_deque<T, Alloc>::capacity() const noexcept
{
return m_ring.size();
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::clear()
{
pop_n( m_n );
}
template<typename T, typename Alloc>
T &ring_deque<T, Alloc>::operator []( ptrdiff_t i ) noexcept
{
using namespace std;
if( i >= 0 )
{
assert((size_t)i < m_n);
ptrdiff_t headRun = m_ring.end() - m_front;
if( i < headRun )
return m_front[i];
else
return m_ring.begin()[i - headRun];
}
else
{
assert((size_t)-i <= m_n);
ptrdiff_t tailRun = m_ring.begin() - m_back;
if( i >= tailRun )
return m_back[i];
else
return m_ring.end()[i - tailRun];
}
}
template<typename T, typename Alloc>
inline T const &ring_deque<T, Alloc>::operator []( ptrdiff_t i ) const
noexcept
{
return (*const_cast<ring_deque<T, Alloc> *>(this))[i];
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::reserve( ptrdiff_t capacity )
{
reCap( capacity );
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scanInternal( Consumer consumer )
{
typename span_t::iterator it;
scanInternal<Forward>( it, consumer );
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scanInternal( span_t::iterator &it,
Consumer consumer )
{
using namespace std;
it = Forward ? m_front : m_back;
for( size_t n = m_n; n; --n )
{
if( !consumer( it[-(ptrdiff_t)!Forward] ) ) [[unlikely]]
break;
it = it + (Forward - !Forward);
if( it == (Forward ? m_ring.end() : m_ring.begin()) ) [[unlikely]]
it = Forward ? m_ring.begin() : m_ring.end();
}
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::grow()
{
size_t nBefore = m_ring.size();
reCap( 2 * nBefore + (size_t)!nBefore );
}
template<typename T, typename Alloc>
void ring_deque<T, Alloc>::reCap( ptrdiff_t capacity )
{
using namespace std;
size_t n = normCap( capacity );;
if( n <= m_n )
return;
span_t ring( allocRing( n ) );
size_t nElements = m_n;
invoke_on_destruct finalize( [&]
{
m_n = nElements;
freeRing( ring );
} );
auto it = ring.begin();
invoke_on_destruct moveBack( [&]
{
while( it != ring.begin() )
{
if constexpr( is_move_constructible_v<T> )
emplace<false>( move( *--it ) );
(*it).~T();
}
} );
if constexpr( is_move_constructible_v<T> )
consume<true>( [&]( T &value )
{
new( (void *)&*it ) T( move( value ) );
++it;
return 1;
} );
else
scan<true>( [&]( T &value )
{
new( (void *)&*it ) T( move( value ) );
++it;
return true;
} );
moveBack.disable();
swap( m_ring, ring );
m_front = m_ring.begin();
m_back = it;
}
template<typename T, typename Alloc>
inline size_t ring_deque<T, Alloc>::normCap( ptrdiff_t capacity )
{
if( capacity < 0 ) [[unlikely]]
capacity = (size_t)-capacity / sizeof(T);
return capacity;
}
template<typename T, typename Alloc>
typename ring_deque<T, Alloc>::span_t ring_deque<T, Alloc>::allocRing(
size_t capacity )
{
using namespace std;
if( !capacity )
return span_t();
#if !defined(__cpp_lib_allocate_at_least) && defined(_MSC_VER)
allocation_result<T *, size_t> ar( m_alloc.allocate_at_least( capacity ) );
return span_t( ar.ptr, ar.count );
#else
return span_t( m_alloc.allocate( capacity ), capacity );
#endif
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::freeRing( span_t sp )
{
if( to_address( sp.begin() ) )
m_alloc.deallocate( sp.data(), sp.size() );
}
#if defined(__llvm__)
#pragma clang diagnostic pop
#endif
#pragma once
#include <utility>
#include <cassert>
#include <memory>
#include <span>
#include "invoke_on_destruct.h"
#include "nui.h"
#if defined(__llvm__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wparentheses"
#pragma clang diagnostic ignored "-Wunqualified-std-cast-call"
#endif
template<typename T, typename Alloc = std::allocator<T>>
struct ring_deque
{
ring_deque( ptrdiff_t capacity = 0, Alloc const &alloc = Alloc() );
~ring_deque();
ring_deque( ring_deque<T, Alloc> const &other );
ring_deque( ring_deque<T, Alloc> &&other ) noexcept;
ring_deque<T, Alloc> &operator =( ring_deque<T, Alloc> const &other );
ring_deque<T, Alloc> &operator =( ring_deque<T, Alloc> &&other ) noexcept;
template<bool Forward, typename Consumer>
void scan( Consumer consumer )
requires requires( T &value ) { { consumer( value ) }; };
template<bool Forward, typename Consumer>
void scan( Consumer consumer ) const
requires requires( T const &value ) { { consumer( value ) }; };
T &front() noexcept;
T const &front() const noexcept;
T &back() noexcept;
T const &back() const noexcept;
template<bool Forward, typename Consumer>
size_t consume( Consumer consumer )
requires requires( T &value ) { { consumer( value ) } ->
std::same_as<int>; };
template<bool Back, typename ... Args>
T &emplace( Args &&... args )
requires std::is_constructible_v<T, Args ...>;
void pop_back() noexcept;
void pop_front() noexcept;
void pop_n( ptrdiff_t n ) noexcept;
void shrink_to_fit();
bool empty() const noexcept;
size_t size() const noexcept;
size_t capacity() const noexcept;
void clear();
T &operator []( ptrdiff_t i ) noexcept;
T const &operator []( ptrdiff_t i ) const noexcept;
void reserve( ptrdiff_t capacity );
private:
using span_t = std::span<T>;
span_t allocRing( size_t capacity );
void freeRing( span_t sp );
template<bool Forward, typename Consumer>
void scanInternal( Consumer consumer );
template<bool Forward, typename Consumer>
void scanInternal( span_t::iterator &it, Consumer consumer );
void grow();
void reCap( ptrdiff_t capacity );
static size_t normCap( ptrdiff_t capacity );
using alloc_t = Alloc;
NO_UNIQUE_ADDRESS alloc_t m_alloc;
span_t m_ring;
span_t::iterator m_front, m_back;
size_t m_n;
};
template<typename T, typename Alloc>
ring_deque<T, Alloc>::ring_deque( ptrdiff_t capacity, Alloc const &alloc ) :
m_alloc( alloc ),
m_ring( allocRing( normCap( capacity ) ) ),
m_front( m_ring.begin() ),
m_back( m_ring.begin() ),
m_n( 0 )
{
}
template<typename T, typename Alloc>
ring_deque<T, Alloc>::~ring_deque()
{
consume<true>( [&]( T & ) -> int { return 1; } );
freeRing( m_ring );
}
template<typename T, typename Alloc>
ring_deque<T, Alloc>::ring_deque( ring_deque<T, Alloc> const &other ) :
ring_deque( other.m_n, other.m_alloc )
{
invoke_on_destruct reset( [&] { this->~ring_deque(); } );
other.scanInternal<true>( [&]( T const &value ) { emplace_back( value
); return true; } );
reset.disable();
}
template<typename T, typename Alloc>
ring_deque<T, Alloc>::ring_deque( ring_deque<T, Alloc> &&other ) noexcept :
m_alloc( other.m_alloc ),
m_ring( other.m_ring ),
m_front( other.m_front ),
m_back( other.m_back ),
m_n( other.m_n )
{
other.m_ring = span_t();
other.m_n = 0;
#if !defined(NDEBUG)
other.m_front = span_t().begin();
other.m_back = span_t().begin();
#endif
}
template<typename T, typename Alloc>
ring_deque<T, Alloc> &ring_deque<T, Alloc>::operator =( ring_deque<T,
Alloc> const &other )
{
clear();
reserve( other.size() );
other.scanInternal<true>( [&]( T const &value ) { emplace_back( value
); return true; } );
return *this;
}
template<typename T, typename Alloc>
ring_deque<T, Alloc> &ring_deque<T, Alloc>::operator =( ring_deque<T,
Alloc> &&other ) noexcept
{
freeRing( m_ring );
m_alloc = other.m_alloc;
m_ring = other.m_ring;
m_front = other.m_front;
m_back = other.m_back;
m_n = other.m_n;
other.m_ring = span_t();
other.m_n = 0;
#if !defined(NDEBUG)
other.m_front = span_t().begin();
other.m_back = span_t().begin();
#endif
return *this;
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scan( Consumer consumer )
requires requires( T &value ) { { consumer( value ) }; }
{
using namespace std;
scanInternal<Forward>( [&]( T &value )
{
bool ret = true;
if constexpr( requires() { { consumer( value ) } ->
convertible_to<bool>; } )
ret = consumer( value );
else
consumer( value );
return ret;
} );
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scan( Consumer consumer ) const
requires requires( T const &value ) { { consumer( value ) }; }
{
const_cast<ring_deque<T, Alloc> *>(this)->scan<Forward>( [&]( T &value
) { return consumer( value ); } );
}
template<typename T, typename Alloc>
inline T &ring_deque<T, Alloc>::front() noexcept
{
assert(m_n);
return *m_front;
}
template<typename T, typename Alloc>
inline T const &ring_deque<T, Alloc>::front() const noexcept
{
assert(m_n);
return *m_front;
}
template<typename T, typename Alloc>
inline T &ring_deque<T, Alloc>::back() noexcept
{
assert(m_n);
return m_back[-1];
}
template<typename T, typename Alloc>
inline T const &ring_deque<T, Alloc>::back() const noexcept
{
assert(m_n);
return m_back[-1];
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline size_t ring_deque<T, Alloc>::consume( Consumer consumer )
requires requires( T &value ) { { consumer( value ) } ->
std::same_as<int>; }
{
size_t nInitial = m_n;
typename span_t::iterator it = Forward ? m_front : m_back;
invoke_on_destruct adjust( [&] { (Forward ? m_front : m_back) = it; } );
scanInternal<Forward>( it, [&]( T &value ) -> bool
{
int cont = consumer( value );
if( cont >= 0 ) [[likely]]
{
value.~T();
--m_n;
}
return cont > 0;
} );
return nInitial - m_n;
}
template<typename T, typename Alloc>
template<bool Back, typename ... Args>
T &ring_deque<T, Alloc>::emplace( Args &&... args )
requires std::is_constructible_v<T, Args ...>
{
using namespace std;
assert(m_ring.size() >= m_n);
if( m_n == m_ring.size() ) [[unlikely]]
grow();
auto next = Back ? m_back : m_front;
if( next == (Back ? m_ring.end() : m_ring.begin()) ) [[unlikely]]
next = Back ? m_ring.begin() : m_ring.end();
next -= !Back;
new( (void *)&*next ) T( forward<Args>( args ) ... );
next += Back;
(Back ? m_back : m_front) = next;
++m_n;
return *(Back ? m_back - 1 : m_front);
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::pop_back() noexcept
{
assert(m_n);
(*--m_back).~T();
if( m_back == m_ring.begin() ) [[unlikely]]
m_back = m_ring.end();
--m_n;
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::pop_front() noexcept
{
assert(m_n);
(*m_front++).~T();
if( m_front == m_ring.end() ) [[unlikely]]
m_front = m_ring.begin();
--m_n;
}
template<typename T, typename Alloc>
void ring_deque<T, Alloc>::pop_n( ptrdiff_t n ) noexcept
{
if( n > 0 )
{
assert(m_n >= (size_t)n);
size_t dest = m_n - n;
consume<true>( [&]( T &value ) -> int { return --m_n != dest; } );
}
else if( n < 0 )
{
assert(m_n >= (size_t)-n);
size_t dest = m_n - -n;
consume<false>( [&]( T &value ) -> int { return --m_n != dest; } );
}
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::shrink_to_fit()
{
reCap( m_n );
}
template<typename T, typename Alloc>
inline bool ring_deque<T, Alloc>::empty() const noexcept
{
return !size();
}
template<typename T, typename Alloc>
inline size_t ring_deque<T, Alloc>::size() const noexcept
{
return m_n;
}
template<typename T, typename Alloc>
inline size_t ring_deque<T, Alloc>::capacity() const noexcept
{
return m_ring.size();
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::clear()
{
pop_n( m_n );
}
template<typename T, typename Alloc>
T &ring_deque<T, Alloc>::operator []( ptrdiff_t i ) noexcept
{
using namespace std;
if( i >= 0 )
{
assert((size_t)i < m_n);
ptrdiff_t headRun = m_ring.end() - m_front;
if( i < headRun )
return m_front[i];
else
return m_ring.begin()[i - headRun];
}
else
{
assert((size_t)-i <= m_n);
ptrdiff_t tailRun = m_ring.begin() - m_back;
if( i >= tailRun )
return m_back[i];
else
return m_ring.end()[i - tailRun];
}
}
template<typename T, typename Alloc>
inline T const &ring_deque<T, Alloc>::operator []( ptrdiff_t i ) const
noexcept
{
return (*const_cast<ring_deque<T, Alloc> *>(this))[i];
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::reserve( ptrdiff_t capacity )
{
reCap( capacity );
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scanInternal( Consumer consumer )
{
typename span_t::iterator it;
scanInternal<Forward>( it, consumer );
}
template<typename T, typename Alloc>
template<bool Forward, typename Consumer>
inline void ring_deque<T, Alloc>::scanInternal( span_t::iterator &it,
Consumer consumer )
{
using namespace std;
it = Forward ? m_front : m_back;
for( size_t n = m_n; n; --n )
{
if( !consumer( it[-(ptrdiff_t)!Forward] ) ) [[unlikely]]
break;
it = it + (Forward - !Forward);
if( it == (Forward ? m_ring.end() : m_ring.begin()) ) [[unlikely]]
it = Forward ? m_ring.begin() : m_ring.end();
}
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::grow()
{
size_t nBefore = m_ring.size();
reCap( 2 * nBefore + (size_t)!nBefore );
}
template<typename T, typename Alloc>
void ring_deque<T, Alloc>::reCap( ptrdiff_t capacity )
{
using namespace std;
size_t n = normCap( capacity );;
if( n <= m_n )
return;
span_t ring( allocRing( n ) );
size_t nElements = m_n;
invoke_on_destruct finalize( [&]
{
m_n = nElements;
freeRing( ring );
} );
auto it = ring.begin();
invoke_on_destruct moveBack( [&]
{
while( it != ring.begin() )
{
if constexpr( is_move_constructible_v<T> )
emplace<false>( move( *--it ) );
(*it).~T();
}
} );
if constexpr( is_move_constructible_v<T> )
consume<true>( [&]( T &value )
{
new( (void *)&*it ) T( move( value ) );
++it;
return 1;
} );
else
scan<true>( [&]( T &value )
{
new( (void *)&*it ) T( move( value ) );
++it;
return true;
} );
moveBack.disable();
swap( m_ring, ring );
m_front = m_ring.begin();
m_back = it;
}
template<typename T, typename Alloc>
inline size_t ring_deque<T, Alloc>::normCap( ptrdiff_t capacity )
{
if( capacity < 0 ) [[unlikely]]
capacity = (size_t)-capacity / sizeof(T);
return capacity;
}
template<typename T, typename Alloc>
typename ring_deque<T, Alloc>::span_t ring_deque<T, Alloc>::allocRing(
size_t capacity )
{
using namespace std;
if( !capacity )
return span_t();
#if !defined(__cpp_lib_allocate_at_least) && defined(_MSC_VER)
allocation_result<T *, size_t> ar( m_alloc.allocate_at_least( capacity ) );
return span_t( ar.ptr, ar.count );
#else
return span_t( m_alloc.allocate( capacity ), capacity );
#endif
}
template<typename T, typename Alloc>
inline void ring_deque<T, Alloc>::freeRing( span_t sp )
{
if( to_address( sp.begin() ) )
m_alloc.deallocate( sp.data(), sp.size() );
}
#if defined(__llvm__)
#pragma clang diagnostic pop
#endif