61 static_assert(
sizeof(T) == 1 ,
"sizeof t is one" ) ;
62 using value_type = T ;
63 using iterator = T * ;
64 using const_iterator =
const T * ;
65 Buffer()
noexcept = default ;
66 explicit Buffer( std::size_t n ) : m_n(n) , m_c(n)
68 m_p =
static_cast<T*
>(std::malloc(n)) ;
75 void reserve( std::size_t n )
79 T * new_p =
static_cast<T*
>( std::realloc(m_p,n) ) ;
80 m_p = checkalloc( new_p ) ;
84 void resize( std::size_t n ) { reserve( n ) ; m_n = n ; }
85 const T & operator[]( std::size_t i )
const noexcept {
return *(m_p+i) ; }
86 T & operator[]( std::size_t i )
noexcept {
return *(m_p+i) ; }
87 const T & at( std::size_t i )
const { checkindex( i ) ;
return *(m_p+i) ; }
88 T & at( std::size_t i ) { checkindex( i ) ;
return *(m_p+i) ; }
89 std::size_t size()
const noexcept {
return m_n ; }
90 std::size_t capacity()
const noexcept {
return m_c ; }
91 bool empty()
const noexcept {
return m_n == 0U ; }
92 void clear()
noexcept { m_n = 0 ; }
93 void shrink_to_fit()
noexcept {
if( empty() && m_p ) { std::free(m_p) ; m_p = nullptr ; m_c = 0U ; } }
94 iterator begin()
noexcept {
return m_p ? m_p : &m_c0 ; }
95 iterator end()
noexcept {
return m_p ? (m_p+m_n) : &m_c0 ; }
96 const value_type * data()
const noexcept {
return m_p ? m_p : &m_c0 ; }
97 value_type * data()
noexcept {
return m_p ? m_p : &m_c0 ; }
98 const_iterator begin()
const noexcept {
return m_p ? m_p : &m_c0 ; }
99 const_iterator end()
const noexcept {
return m_p ? (m_p+m_n) : &m_c0 ; }
100 const_iterator cbegin()
const noexcept {
return m_p ? m_p : &m_c0 ; }
101 const_iterator cend()
const noexcept {
return m_p ? (m_p+m_n) : &m_c0 ; }
102 iterator erase( iterator range_begin , iterator range_end )
noexcept
104 if( range_end == end() )
106 m_n = std::distance( begin() , range_begin ) ;
108 else if( range_begin != range_end )
110 std::size_t range = std::distance( range_begin , range_end ) ;
111 std::size_t end_offset = std::distance( begin() , range_end ) ;
112 std::memmove( range_begin , range_end , m_n-end_offset ) ;
117 template <
typename U>
void insert( iterator p , U range_begin , U range_end )
119 std::size_t range = std::distance( range_begin , range_end ) ;
122 p = makespace( p , range ) ;
123 std::copy( range_begin , range_end , p ) ;
126 template <
typename U>
void insert( iterator p , U * range_begin , U * range_end )
128 std::size_t range = std::distance( range_begin , range_end ) ;
131 p = makespace( p , range ) ;
132 std::memcpy( p , range_begin , range ) ;
137 std::swap( m_n , other.m_n ) ;
138 std::swap( m_p , other.m_p ) ;
139 std::swap( m_c , other.m_c ) ;
145 resize( other.m_n ) ;
146 std::memcpy( m_p , other.m_p , m_n ) ;
160 Buffer<T>(std::move(other)).swap(*
this) ;
163 template <
typename U> T * aligned()
165 if( m_n == 0U || m_p ==
nullptr )
return nullptr ;
167 std::size_t space = m_n ;
168 void * result =
std::align(
alignof(U) ,
sizeof(U) , vp , space ) ;
169 return static_cast<T*
>(result) ;
172 iterator makespace( iterator p , std::size_t range )
174 G_ASSERT( p >= begin() && p <= end() ) ;
175 G_ASSERT( range != 0U ) ;
176 std::size_t head = std::distance( begin() , p ) ;
177 std::size_t tail = std::distance( p , end() ) ;
178 resize( m_n + range ) ;
180 std::memmove( p+range , p , tail ) ;
183 void checkalloc() { checkalloc(m_p) ; }
184 T * checkalloc( T * p ) {
if( p ==
nullptr )
throw std::bad_alloc() ;
return p ; }
185 void checkindex( std::size_t i )
const {
if( i >= m_n )
throw std::out_of_range(
"G::Buffer") ; }
186 char * m_p{
nullptr} ;
187 std::size_t m_n{0U} ;
188 std::size_t m_c{0U} ;
189 value_type m_c0{
'\0'} ;
192 template <
typename Uptr,
typename T =
char>
195 using U =
typename std::remove_pointer<Uptr>::type ;
196 T * p = buffer.template aligned<U>() ;
197 G_ASSERT( p ==
nullptr || p == &buffer[0] ) ;
198 if( p != &buffer[0] )
199 throw std::bad_cast() ;
203 template <
typename Uptr,
typename T =
char>
204 Uptr buffer_cast( Buffer<T> & buffer , std::nothrow_t )
206 using U =
typename std::remove_pointer<Uptr>::type ;
207 T * p = buffer.template aligned<U>() ;
208 G_ASSERT( p ==
nullptr || p == &buffer[0] ) ;
209 if( p != &buffer[0] )
214 template <
typename Uptr,
typename T =
char>
215 Uptr buffer_cast(
const Buffer<T> & buffer )
217 using U =
typename std::remove_pointer<Uptr>::type ;
218 return const_cast<Uptr
>( buffer_cast<U*>(
const_cast<Buffer<T>&
>(buffer) ) ) ;
221 template <
typename T>
void swap( Buffer<T> & a , Buffer<T> & b )
noexcept
void * align(const char *buffer, std::size_t buffer_size)
Returns a pointer inside the given buffer that is aligned for values of type T.
A substitute for std::vector<char> that has more useful alignment guarantees and explicitly avoids de...