📄 auto_buffer.hpp
字号:
// Expansion; cases 1, 3 & 5
if(is_in_external_array_())
{
// Current buffer is allocated: case 5
pointer new_buffer = reallocate_(m_buffer, m_cItems, cItems);
// Still test for NULL here, since some allocators will
// not throw bad_alloc.
if(NULL == new_buffer)
{
return false;
}
// Now repoint to the new buffer
m_buffer = new_buffer;
}
else
{
// Expanding from internal buffer; cases 1 & 3
if(space < cItems)
{
// Expanding to allocated buffer; case 3
pointer new_buffer = allocate_(cItems);
// Still test for NULL here, since some allocators will
// not throw bad_alloc.
if(NULL == new_buffer)
{
return false;
}
block_copy(new_buffer, m_buffer, m_cItems);
m_buffer = new_buffer;
m_bExternal = true;
}
else
{
// Expanding to internal buffer; case 1
// Nothing to do
STLSOFT_ASSERT(!(space < cItems));
}
}
}
else
{
// Contraction; cases 2, 4 & 6
if(is_in_external_array_())
{
// Current buffer is allocated: cases 4 & 6
if(space < cItems)
{
// Contracting within allocated buffer; case 6
// Nothing to do
STLSOFT_ASSERT(space < cItems);
}
#if defined(STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK)
else
#else /* ? STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
else if(0 == cItems)
#endif /* STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
{
// Contracting back to internal; case 4
block_copy(const_cast<pointer>(&m_internal[0]), m_buffer, cItems);
deallocate_(m_buffer, m_cItems);
m_buffer = const_cast<pointer>(&m_internal[0]);
m_bExternal = false;
}
}
else
{
// Current buffer is internal; case 2
// Nothing to do
STLSOFT_ASSERT(!(space < cItems));
}
}
m_cItems = cItems;
STLSOFT_ASSERT(is_valid());
return true;
}
/// \brief Swaps contents with the given buffer
///
/// \note This method is only constant time when the memory for two buffers
/// has been acquired via the allocator. Otherwise, it will depend on the
/// costs of exchanging the memory
///
/// \note Exception-safety: Provides the no-throw guarantee
void swap(class_type& rhs) stlsoft_throw_0()
{
STLSOFT_ASSERT(is_valid());
if( is_in_external_array_() &&
rhs.is_in_external_array_())
{
// Both are allocated, so just swap them
std_swap(m_buffer, rhs.m_buffer);
}
else if(is_in_external_array_())
{
// *this is allocated on the heap, rhs is using m_internal
// 1. Copy the contents of rhs.m_internal to this->m_internal
block_copy(&m_internal[0], &rhs.m_internal[0], rhs.m_cItems);
// 2. Move m_buffer from *this to rhs
rhs.m_buffer = m_buffer;
// 3. Tell *this to use its internal buffer
m_buffer = &m_internal[0];
}
else if(rhs.is_in_external_array_())
{
// This is a lazy cheat, but eminently effective.
rhs.swap(*this);
return;
}
else
{
// Both are using internal buffers, so we exchange the contents
value_type t[space];
block_copy(&t[0], &rhs.m_internal[0], rhs.m_cItems);
block_copy(&rhs.m_internal[0], &m_internal[0], m_cItems);
block_copy(&m_internal[0], &t[0], rhs.m_cItems);
}
std_swap(m_cItems, rhs.m_cItems);
std_swap(m_bExternal, rhs.m_bExternal);
STLSOFT_ASSERT(is_valid());
}
/// @}
/// \name Operators
/// @{
public:
// Note: The following two const and non-const implicit conversion
// operators are correctly implemented. However, GCC will pedantically
// give a verbose warning describing its having selected one over the
// other, and this is, in current versions of the compiler, not
// suppressable. The warnings must, alas, simply be ignored.
#ifdef _STLSOFT_AUTO_BUFFER_ALLOW_NON_CONST_CONVERSION_OPERATOR
/// \brief An implicit conversion to a pointer to the start of the element array
///
/// \deprecate This is deprecated
operator pointer ()
{
STLSOFT_ASSERT(is_valid());
return m_buffer;
}
#else /* ? _STLSOFT_AUTO_BUFFER_ALLOW_NON_CONST_CONVERSION_OPERATOR */
/// \brief Subscript operator
reference operator [](size_type index)
{
STLSOFT_MESSAGE_ASSERT("Index is out of bounds", index <= m_cItems);
STLSOFT_ASSERT(is_valid());
return m_buffer[index];
}
/// \brief Subscript operator
const_reference operator [](size_type index) const
{
STLSOFT_MESSAGE_ASSERT("Index is out of bounds", index <= m_cItems);
STLSOFT_ASSERT(is_valid());
return m_buffer[index];
}
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_NON_CONST_CONVERSION_OPERATOR */
#ifdef _STLSOFT_AUTO_BUFFER_ALLOW_CONST_CONVERSION_OPERATOR
/// \brief An implicit conversion to a pointer-to-const to the start of the element array
operator const_pointer () const
{
STLSOFT_ASSERT(is_valid());
return m_buffer;
}
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_CONST_CONVERSION_OPERATOR */
/// @}
/// \name Accessors
/// @{
public:
/// \brief Returns a pointer to the element array
pointer data()
{
STLSOFT_ASSERT(is_valid());
return m_buffer;
}
/// \brief Returns a pointer-to-const to the element array
const_pointer data() const
{
STLSOFT_ASSERT(is_valid());
return m_buffer;
}
/// \brief Returns a reference to the last element in the buffer
///
/// \pre The buffer instance must not be empty
reference front()
{
STLSOFT_ASSERT(is_valid());
STLSOFT_MESSAGE_ASSERT("Cannot call front() on an empty buffer!", !empty());
return m_buffer[0];
}
/// \brief Returns a reference to the last element in the buffer
///
/// \pre The buffer instance must not be empty
reference back()
{
STLSOFT_ASSERT(is_valid());
STLSOFT_MESSAGE_ASSERT("Cannot call back() on an empty buffer!", !empty());
return m_buffer[size() - 1];
}
/// \brief Returns a non-mutating (const) reference to the last element
/// in the buffer
///
/// \pre The buffer instance must not be empty
const_reference front() const
{
STLSOFT_ASSERT(is_valid());
STLSOFT_MESSAGE_ASSERT("Cannot call front() on an empty buffer!", !empty());
return m_buffer[0];
}
/// \brief Returns a non-mutating (const) reference to the last element
/// in the buffer
///
/// \pre The buffer instance must not be empty
const_reference back() const
{
STLSOFT_ASSERT(is_valid());
STLSOFT_MESSAGE_ASSERT("Cannot call back() on an empty buffer!", !empty());
return m_buffer[size() - 1];
}
/// @}
/// \name Iteration
/// @{
public:
/// \brief Returns a non-mutating iterator representing the start of the sequence
const_iterator begin() const
{
STLSOFT_ASSERT(is_valid());
return m_buffer;
}
/// \brief Returns a non-mutating iterator representing the end of the sequence
///
/// \note In the case where memory allocation has failed in the context
/// where exceptions are not thrown for allocation failure, this method will
/// return the same value as begin(). Hence, operations on the <i>empty</i>
/// auto_buffer<> instance will be safe if made in respect of the range
/// defined by [begin(), end()).
const_iterator end() const
{
STLSOFT_ASSERT(is_valid());
return m_buffer + m_cItems;
}
/// \brief Returns a mutable iterator representing the start of the sequence
iterator begin()
{
STLSOFT_ASSERT(is_valid());
return m_buffer;
}
/// \brief Returns a mutable iterator representing the end of the sequence
///
/// \note In the case where memory allocation has failed in the context
/// where exceptions are not thrown for allocation failure, this method will
/// return the same value as begin(). Hence, operations on the <i>empty</i>
/// auto_buffer<> instance will be safe if made in respect of the range
/// defined by [begin(), end()).
iterator end()
{
STLSOFT_ASSERT(is_valid());
return m_buffer + m_cItems;
}
#if defined(STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT)
/// Begins the reverse iteration
///
/// \return An iterator representing the start of the reverse sequence
const_reverse_iterator rbegin() const
{
STLSOFT_ASSERT(is_valid());
return const_reverse_iterator(end());
}
/// Ends the reverse iteration
///
/// \return An iterator representing the end of the reverse sequence
const_reverse_iterator rend() const
{
STLSOFT_ASSERT(is_valid());
return const_reverse_iterator(begin());
}
/// Begins the reverse iteration
///
/// \return An iterator representing the start of the reverse sequence
reverse_iterator rbegin()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -