📄 auto_buffer.hpp
字号:
template< ss_typename_param_k T
# ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
, ss_typename_param_k A = ss_typename_type_def_k allocator_selector<T>::allocator_type
# else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
, ss_typename_param_k A
# endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
# ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT
# if defined(STLSOFT_COMPILER_IS_BORLAND)
, ss_size_t space = 256
# elif defined(STLSOFT_COMPILER_IS_DMC)
, ss_size_t SPACE = 256
# else /* ? compiler */
, ss_size_t SPACE = auto_buffer_internal_size_calculator<T>::value
# endif /* compiler */
# else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
# if !defined(STLSOFT_COMPILER_IS_BORLAND)
, ss_size_t SPACE /* = auto_buffer_internal_size_calculator<T>::value */
# else /* ? compiler */
, ss_size_t space /* = 256 */
# endif /* compiler */
# endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT */
>
// End of pre-1.9 template parameter list
// //////////////////////////////////////////////
#else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
// //////////////////////////////////////////////
// This is the 1.9+ template parameter list
# ifndef STLSOFT_AUTO_BUFFER_NEW_FORM
# define STLSOFT_AUTO_BUFFER_NEW_FORM
# endif /* !STLSOFT_AUTO_BUFFER_NEW_FORM */
template< ss_typename_param_k T
# ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT
# if defined(STLSOFT_COMPILER_IS_BORLAND)
, ss_size_t space = 256
# elif defined(STLSOFT_COMPILER_IS_DMC)
, ss_size_t SPACE = 256
# else /* ? compiler */
, ss_size_t SPACE = auto_buffer_internal_size_calculator<T>::value
# endif /* compiler */
# else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT */
# if !defined(STLSOFT_COMPILER_IS_BORLAND)
, ss_size_t SPACE /* = auto_buffer_internal_size_calculator<T>::value */
# else /* ? compiler */
, ss_size_t space /* = 256 */
# endif /* compiler */
# endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT */
# ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
, ss_typename_param_k A = ss_typename_type_def_k allocator_selector<T>::allocator_type
# else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
, ss_typename_param_k A
# endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
>
// End of 1.9+ template parameter list
// //////////////////////////////////////////////
#endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
class auto_buffer
#if !defined(STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE)
: protected A
, public stl_collection_tag
#else /* ? STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
: public stl_collection_tag
#endif /* !STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
{
/// \name Member Types
/// @{
public:
/// The value type
typedef T value_type;
/// The allocator type
typedef A allocator_type;
#if !defined(STLSOFT_COMPILER_IS_BORLAND)
enum
{
/// The number of items in the internal buffer
space = SPACE
};
#endif /* compiler */
/// The type of the current parameterisation
#ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
typedef auto_buffer<T, A, space> class_type;
#else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
typedef auto_buffer<T, space, A> class_type;
#endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
/// The reference type
typedef ss_typename_type_k allocator_type::reference reference;
/// The non-mutable (const) reference type
typedef ss_typename_type_k allocator_type::const_reference const_reference;
/// The pointer type
typedef ss_typename_type_k allocator_type::pointer pointer;
/// The non-mutable (const) pointer type
typedef ss_typename_type_k allocator_type::const_pointer const_pointer;
/// The size type
typedef ss_size_t size_type;
/// The difference type
typedef ss_ptrdiff_t difference_type;
#if !defined(STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT)
/// The iterator type
typedef value_type *iterator;
/// The non-mutable (const) iterator type
typedef value_type const *const_iterator;
#else /* ? !STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT */
/// The iterator type
typedef
# if !defined(STLSOFT_COMPILER_IS_BORLAND)
ss_typename_type_k
# endif /* compiler */
pointer_iterator < value_type
, pointer
, reference
>::type iterator;
/// The non-mutating (const) iterator type
typedef
# if !defined(STLSOFT_COMPILER_IS_BORLAND)
ss_typename_type_k
# endif /* compiler */
pointer_iterator < value_type const
, const_pointer
, const_reference
>::type const_iterator;
/// The mutating (non-const) reverse iterator type
typedef reverse_iterator_base < iterator
, value_type
, reference
, pointer
, difference_type
> reverse_iterator;
/// The non-mutating (const) reverse iterator type
typedef const_reverse_iterator_base < const_iterator
, value_type const
, const_reference
, const_pointer
, difference_type
> const_reverse_iterator;
#endif /* !STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT */
/// @}
/// \name Implementation
/// @{
private:
pointer allocate_(size_type cItems, void const* hint)
{
#ifdef STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT
return get_allocator().allocate(cItems, hint);
#else /* ? STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT */
STLSOFT_SUPPRESS_UNUSED(hint);
return get_allocator().allocate(cItems);
#endif /* STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT */
}
pointer allocate_(size_type cItems)
{
#ifdef STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT
return get_allocator().allocate(cItems, NULL);
#else /* ? STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT */
return get_allocator().allocate(cItems);
#endif /* STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT */
}
void deallocate_(pointer p, size_type cItems)
{
STLSOFT_ASSERT(NULL != p);
#ifdef STLSOFT_LF_ALLOCATOR_DEALLOCATE_HAS_COUNT
get_allocator().deallocate(p, cItems);
#else /* ? STLSOFT_LF_ALLOCATOR_DEALLOCATE_HAS_COUNT */
STLSOFT_SUPPRESS_UNUSED(cItems);
get_allocator().deallocate(p);
#endif /* STLSOFT_LF_ALLOCATOR_DEALLOCATE_HAS_COUNT */
}
pointer reallocate_(pointer p, size_type cItems, size_type cNewItems)
{
pointer new_p = allocate_(cNewItems, p);
// This test is needed, since some allocators may not throw
// bad_alloc
if(NULL != new_p)
{
block_copy(new_p, p, cItems);
deallocate_(p, cItems);
}
return new_p;
}
protected:
static void block_copy(pointer dest, const_pointer src, size_type cItems)
{
pod_copy_n(dest, src, cItems);
}
static void block_set(pointer dest, size_type cItems, const_reference value)
{
pod_fill_n(dest, cItems, value);
}
/// @}
/// \name Construction
/// @{
public:
/// \brief Constructs an auto_buffer with the given number of elements
///
/// Constructs an auto_buffer with the given number of elements. If the
/// allocation fails by throwing an exception, that exception is passed
/// through to the caller. If allocation fails by returning a null
/// pointer the auto_buffer instance is correctly constructed, and the
/// \link #size size() \endlink method returns 0.
///
/// \see \link #size size() \endlink
/// \param cItems The number of items in the constructed instance
ss_explicit_k auto_buffer(size_type cItems)
: m_buffer((space < cItems) ? allocate_(cItems) : const_cast<pointer>(&m_internal[0]))
, m_cItems((NULL != m_buffer) ? cItems : 0)
, m_bExternal(space < cItems)
{
// Can't create one with an empty buffer. Though such is not legal
// it is supported by some compilers, so we must ensure it cannot be
// so
STLSOFT_STATIC_ASSERT(0 != space);
// These assertions ensure that the member ordering is not
// changed, invalidating the initialisation logic of m_buffer and
// m_cItems. The runtime assert is included for those compilers that
// do not implement compile-time asserts.
#ifdef STLSOFT_CF_USE_RAW_OFFSETOF_IN_STATIC_ASSERT
STLSOFT_STATIC_ASSERT(STLSOFT_RAW_OFFSETOF(class_type, m_buffer) < STLSOFT_RAW_OFFSETOF(class_type, m_cItems));
#endif /* STLSOFT_CF_USE_RAW_OFFSETOF_IN_STATIC_ASSERT */
STLSOFT_MESSAGE_ASSERT("m_buffer must be before m_cItems in the auto_buffer definition", stlsoft_reinterpret_cast(ss_byte_t*, &m_buffer) < stlsoft_reinterpret_cast(ss_byte_t*, &m_cItems));
#ifndef _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD
// Use the must_be_pod constraint to ensure that
// no type is managed in auto_buffer which would result in
// dangerous mismanagement of the lifetime of its instances.
//
// Preprocessor specification of _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD
// prevents this, but the natural rules of the language will
// still prevent non POD types being placed in m_internal[].
stlsoft_constraint_must_be_pod(value_type);
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD */
STLSOFT_ASSERT(is_valid());
}
/// \brief Releases the allocated element array
///
/// Releases any allocated memory. If the internal memory buffer was
/// used, then nothing is done, otherwise the allocated memory is
/// returned to the allocator.
#if defined(STLSOFT_CF_EXCEPTION_SIGNATURE_SUPPORT)
~auto_buffer()
#else /* ? STLSOFT_CF_EXCEPTION_SIGNATURE_SUPPORT */
~auto_buffer() stlsoft_throw_0()
#endif /* STLSOFT_CF_EXCEPTION_SIGNATURE_SUPPORT */
{
STLSOFT_ASSERT(is_valid());
if(is_in_external_array_())
{
STLSOFT_ASSERT(NULL != m_buffer);
STLSOFT_ASSERT(m_bExternal);
STLSOFT_ASSERT(&m_internal[0] != m_buffer);
deallocate_(m_buffer, m_cItems);
}
}
/// @}
/// \name Operations
/// @{
private:
// Policy functions
ss_bool_t is_in_external_array_() const
{
#if defined(STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK)
// Old implementation always uses internal array if size() <= internal_size()
STLSOFT_ASSERT((space < m_cItems) == (m_buffer != &m_internal[0]));
return space < m_cItems;
#else /* ? STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
// Old implementation always uses internal array if size() <= internal_size()
// STLSOFT_ASSERT((m_buffer != &m_internal[0]) || !(space < m_cItems));
STLSOFT_ASSERT((m_buffer != &m_internal[0]) == m_bExternal);
STLSOFT_ASSERT(m_bExternal || !(space < m_cItems));
// return m_buffer != &m_internal[0];
return m_bExternal;
#endif /* STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
}
public:
/// \brief Expands or contracts the number of items in the buffer
///
/// \param cItems The number of items to change in the buffer. If 0, the
/// external array (if allocated) will be deallocated.
/// \return Returns \c true if successful. Function failure occurs when
/// sufficient storage for the requested items cannot be allocated. In
/// that case, std::bad_alloc will be throw for allocators that
/// support it, otherwise the function will return \c false. In either
/// case, the original storage and contents of the buffer will remain
/// unchanged.
///
/// \note When reducing the number of elements, the implementation
/// favours speed above memory consumption. If the new item size is
/// still larger than the internal storage size (\c internal_size())
/// then the heap allocated block will not be changed (i.e. it will
/// not be exchanged for a smaller block).
///
/// \note As from STLSoft version 1.9, the external array is not
/// discarded in favour of the internal array when
/// <code>0 < cItems < internal_size()</code>.
/// Only <code>resize(0)</code> will deallocate the external array.
ss_bool_t resize(size_type cItems)
{
STLSOFT_ASSERT(is_valid());
// There are four changes possible:
//
// 1. Expansion within the internal buffer
// 2. Contraction within the internal buffer
// 3. Expansion from the internal buffer to an allocated buffer
// 4. Contraction from an allocated buffer to the internal buffer
// 4.a Where n is 0, or when STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK is defined
// 4.b Where 0 < n <= internal_size() - this is new behaviour - we do not go to the internal array
// 5. Expansion from the allocated buffer to another allocated buffer
// 6. Contraction from the allocated buffer to another allocated buffer
if(m_cItems < cItems)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -