You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1363 lines
50 KiB
1363 lines
50 KiB
/* /////////////////////////////////////////////////////////////////////////
|
|
* File: stlsoft/memory/auto_buffer.hpp (originally MTLocBfr.h, ::SynesisStl)
|
|
*
|
|
* Purpose: Contains the auto_buffer template class.
|
|
*
|
|
* Created: 19th January 2002
|
|
* Updated: 21st June 2010
|
|
*
|
|
* Thanks: To Thorsten Ottosen for pointing out that allocators were
|
|
* not swapped.
|
|
*
|
|
* Home: http://stlsoft.org/
|
|
*
|
|
* Copyright (c) 2002-2010, Matthew Wilson and Synesis Software
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* - Neither the name(s) of Matthew Wilson and Synesis Software nor the
|
|
* names of any contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ////////////////////////////////////////////////////////////////////// */
|
|
|
|
|
|
/** \file stlsoft/memory/auto_buffer.hpp
|
|
*
|
|
* \brief [C++ only] Definition of the stlsoft::auto_buffer class template
|
|
* (\ref group__library__memory "Memory" Library).
|
|
*/
|
|
|
|
#ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
|
|
#define STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
|
|
|
|
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
# define STLSOFT_VER_STLSOFT_MEMORY_HPP_AUTO_BUFFER_MAJOR 5
|
|
# define STLSOFT_VER_STLSOFT_MEMORY_HPP_AUTO_BUFFER_MINOR 2
|
|
# define STLSOFT_VER_STLSOFT_MEMORY_HPP_AUTO_BUFFER_REVISION 4
|
|
# define STLSOFT_VER_STLSOFT_MEMORY_HPP_AUTO_BUFFER_EDIT 163
|
|
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Compatibility
|
|
*/
|
|
|
|
/*
|
|
[Incompatibilies-start]
|
|
STLSOFT_COMPILER_IS_GCC: __GNUC__ < 3
|
|
[Incompatibilies-end]
|
|
[DocumentationStatus:Ready]
|
|
*/
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Includes
|
|
*/
|
|
|
|
#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
|
|
# include <stlsoft/stlsoft.h>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
|
|
#ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_FEATURES
|
|
# include <stlsoft/memory/allocator_features.hpp> // for STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT
|
|
#endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_FEATURES */
|
|
#ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR
|
|
# include <stlsoft/memory/allocator_selector.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR */
|
|
#ifndef STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_POD
|
|
# include <stlsoft/algorithms/pod.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_HPP_ALGORITHMS_POD */
|
|
#ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP
|
|
# include <stlsoft/util/std_swap.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP */
|
|
#ifdef _STLSOFT_AUTO_BUFFER_ALLOW_UDT
|
|
# define _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD
|
|
# ifdef STLSOFT_CF_PRAGMA_MESSAGE_SUPPORT
|
|
# pragma message("_STLSOFT_AUTO_BUFFER_ALLOW_UDT is deprecated. Use _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD instead")
|
|
# endif /* STLSOFT_CF_PRAGMA_MESSAGE_SUPPORT */
|
|
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_UDT */
|
|
#ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
|
|
# include <stlsoft/util/std/iterator_helper.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
|
|
#ifndef _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD
|
|
# ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS
|
|
# include <stlsoft/util/constraints.hpp>
|
|
# endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS */
|
|
#endif /* _STLSOFT_AUTO_BUFFER_ALLOW_NON_POD */
|
|
#ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
|
|
# include <stlsoft/collections/util/collections.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
|
|
|
|
#ifdef STLSOFT_UNITTEST
|
|
# include <algorithm>
|
|
# if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
|
|
# include <numeric>
|
|
# endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
|
|
# include <stdio.h>
|
|
#endif /* STLSOFT_UNITTEST */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Namespace
|
|
*/
|
|
|
|
#ifndef _STLSOFT_NO_NAMESPACE
|
|
namespace stlsoft
|
|
{
|
|
#endif /* _STLSOFT_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Classes
|
|
*/
|
|
|
|
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
# if !defined(STLSOFT_COMPILER_IS_BORLAND) && \
|
|
!defined(STLSOFT_COMPILER_IS_DMC)
|
|
|
|
struct auto_buffer_internal_default
|
|
{
|
|
enum { min_value = 32 };
|
|
enum { max_value = 256 };
|
|
enum { division_factor = 2 };
|
|
};
|
|
|
|
template <ss_typename_param_k T>
|
|
struct auto_buffer_internal_size_calculator
|
|
: private auto_buffer_internal_default
|
|
{
|
|
private:
|
|
// Stupid, stupid, stupid GCC requires them all to share the same
|
|
// enum, which totally sucks. It whinges about comparisons between
|
|
// enumerals (sic.) of different types. Thankfully it's irrelevant
|
|
// because they're private
|
|
enum
|
|
{
|
|
min_value = auto_buffer_internal_default::min_value
|
|
, max_value = auto_buffer_internal_default::max_value
|
|
, division_factor = auto_buffer_internal_default::division_factor
|
|
, divided_value_ = static_cast<int>((division_factor * max_value) / sizeof(T))
|
|
, divided_value = (max_value < divided_value_)
|
|
? max_value
|
|
: divided_value_
|
|
};
|
|
public:
|
|
enum { value = 1 == sizeof(T)
|
|
? max_value
|
|
: divided_value < min_value
|
|
? min_value
|
|
: divided_value };
|
|
};
|
|
|
|
STLSOFT_TEMPLATE_SPECIALISATION
|
|
struct auto_buffer_internal_size_calculator<ss_char_a_t>
|
|
{
|
|
enum { value = auto_buffer_internal_default::max_value };
|
|
};
|
|
# if defined(STLSOFT_CF_NATIVE_WCHAR_T_SUPPORT) || \
|
|
defined(STLSOFT_CF_TYPEDEF_WCHAR_T_SUPPORT)
|
|
STLSOFT_TEMPLATE_SPECIALISATION
|
|
struct auto_buffer_internal_size_calculator<ss_char_w_t>
|
|
{
|
|
enum { value = auto_buffer_internal_default::max_value };
|
|
};
|
|
# endif /* STLSOFT_CF_NATIVE_WCHAR_T_SUPPORT */
|
|
|
|
# endif /* compiler */
|
|
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
|
|
|
|
|
|
// class auto_buffer
|
|
//
|
|
/** \brief This class provides an efficient variable automatic buffer
|
|
*
|
|
* \ingroup group__library__memory
|
|
*
|
|
* \param T The type of the elements in the array
|
|
* \param SPACE The number of elements in the array. For translators that
|
|
* support default template arguments, this is defaulted to <b>256</b>
|
|
* \param A The allocator type. Defaults to
|
|
* \link stlsoft::allocator_selector allocator_selector<T>::allocator_type\endlink
|
|
* for translators that support default template arguments.
|
|
*
|
|
* This class provides an efficient replacement for dynamic memory block
|
|
* allocation when the block size generally falls under a predictable limit. In
|
|
* such cases, significant performance benefits can be achieved by using an
|
|
* instance of a parameterisation of auto_buffer, whose size parameter SPACE
|
|
* is set to a level to cater for most of the requested sizes. Only where
|
|
* the size of the buffer needs to be larger than this limit does an
|
|
* allocation occur from the heap/free-store via the given allocator.
|
|
*
|
|
* Using <code>auto_buffer</code> means one can avoid use of heap memory in
|
|
* circumstances where stack memory is unsuitable, i.e. where there is no
|
|
* maximum size to a memory requirement, or the maximum size is potentially
|
|
* very large (and considerably larger than the median size). Consider the
|
|
* following code extract from the core of the
|
|
* <a href = "http://pantheios.org/">Pantheios</a> logging library:
|
|
\code
|
|
int pantheios_log_n( pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices)
|
|
{
|
|
typedef stlsoft::auto_buffer<char, 2048> buffer_t;
|
|
|
|
// Calculate the total size of the log statement, by summation of the slice array
|
|
const size_t n = std::accumulate(stlsoft::member_selector(slices, &pan_slice_t::len)
|
|
, stlsoft::member_selector(slices + numSlices, &pan_slice_t::len)
|
|
, size_t(0));
|
|
buffer_t buffer(1 + n);
|
|
|
|
. . .
|
|
\endcode
|
|
*
|
|
* This use of auto_buffer illustrates two important features:
|
|
* - there is no (compile-time) limit on the maximum size of a log statement
|
|
* - memory is only allocated from the heap in the case where the total statement length >= 2047 bytes.
|
|
*
|
|
* Without auto_buffer, we would have three choices, all bad:
|
|
*
|
|
* 1. We could go to the heap in all cases:
|
|
\code
|
|
int pantheios_log_n( pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices)
|
|
{
|
|
typedef stlsoft::vector<char> buffer_t;
|
|
|
|
// Calculate the total size of the log statement, by summation of the slice array
|
|
const size_t n = std::accumulate(stlsoft::member_selector(slices, &pan_slice_t::len)
|
|
, stlsoft::member_selector(slices + numSlices, &pan_slice_t::len)
|
|
, size_t(0));
|
|
buffer_t buffer(1 + n);
|
|
|
|
. . .
|
|
\endcode
|
|
* But this would have an unacceptable performance hit (since the vast
|
|
* majority of log statements are less than 2K in extent).
|
|
*
|
|
* 2. We could use a stack buffer, and truncate any log statement exceeding
|
|
* the limit:
|
|
\code
|
|
int pantheios_log_n( pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices)
|
|
{
|
|
// Calculate the total size of the log statement, by summation of the slice array
|
|
const size_t n = std::accumulate(stlsoft::member_selector(slices, &pan_slice_t::len)
|
|
, stlsoft::member_selector(slices + numSlices, &pan_slice_t::len)
|
|
, size_t(0));
|
|
char buffer[2048];
|
|
|
|
. . . // make sure to truncate the statement to a max 2047 characters
|
|
|
|
\endcode
|
|
* But this would unnecessarily constrain users of the Pantheios logging
|
|
* functionality.
|
|
*
|
|
* 3. Finally, we could synthesise the functionality of auto_buffer
|
|
* manually, as in:
|
|
\code
|
|
int pantheios_log_n( pan_sev_t severity
|
|
, size_t numSlices
|
|
, pan_slice_t const* slices)
|
|
{
|
|
// Calculate the total size of the log statement, by summation of the slice array
|
|
const size_t n = std::accumulate(stlsoft::member_selector(slices, &pan_slice_t::len)
|
|
, stlsoft::member_selector(slices + numSlices, &pan_slice_t::len)
|
|
, size_t(0));
|
|
char buff[2048];
|
|
char *buffer = (n < 2048) ? &buff[0] : new char[1 + n];
|
|
|
|
. . .
|
|
|
|
if(buffer != &buff[0])
|
|
{
|
|
delete [] buffer;
|
|
}
|
|
\endcode
|
|
* But this is onerous manual fiddling, and exception-unsafe. What would be
|
|
* the point, when auto_buffer already does this (safely) for us?
|
|
*
|
|
* As a consequence of its blending of the best features of stack and heap
|
|
* memory, auto_buffer is an invaluable component in the implementation of
|
|
* many components within the STLSoft libraries, and in several other
|
|
* open-source projects, including:
|
|
* <a href = "http://synesis.com.au/software/b64.html">b64</a>,
|
|
* <a href = "http://openrj.org/">Open-RJ</a>,
|
|
* <a href = "http://pantheios.org/">Pantheios</a>,
|
|
* <a href = "http://recls.org/">recls</a>,
|
|
* and
|
|
* <a href = "http://shwild.org/">shwild</a>.
|
|
*
|
|
* \remarks auto_buffer works correctly whether the given allocator throws an
|
|
* exception on allocation failure, or returns <code>NULL</code>. In the
|
|
* latter case, construction failure to allocate is reflected by the size()
|
|
* method returning 0.
|
|
*
|
|
* \remarks The design of auto_buffer is described in Chapter 32 of
|
|
* <a href = "http://imperfectcplusplus.com">Imperfect C++</a>, and its
|
|
* interface is discussed in detail in Section 16.2 of
|
|
* <a href = "http://extendedstl.com">Extended STL, volume 1</a>.
|
|
*
|
|
* \note With version 1.9 of STLSoft, the order of the space and allocator
|
|
* arguments were reversed. Further, the allocator default changed from
|
|
* stlsoft::new_allocator to <code>std::allocator</code> for translators that support
|
|
* the standard library. If you need the old characteristics, you can
|
|
* <code>\#define</code> the symbol <b>STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS</b>.
|
|
*/
|
|
|
|
#if defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
_MSC_VER < 1200
|
|
# define STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
#endif /* compiler */
|
|
|
|
|
|
#if defined(STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS)
|
|
|
|
# ifdef STLSOFT_AUTO_BUFFER_NEW_FORM
|
|
# undef STLSOFT_AUTO_BUFFER_NEW_FORM
|
|
# endif /* STLSOFT_AUTO_BUFFER_NEW_FORM */
|
|
|
|
// //////////////////////////////////////////////
|
|
// This is the pre-1.9 template parameter list
|
|
|
|
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 = int(SPACE) // int() required for 64-bit compatibility
|
|
};
|
|
#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_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
|
|
/// The iterator type
|
|
typedef value_type* iterator;
|
|
/// The non-mutable (const) iterator type
|
|
typedef value_type const* const_iterator;
|
|
#else /* ? !STLSOFT_LF_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_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
|
|
/// @}
|
|
|
|
/// \name Implementation
|
|
/// @{
|
|
private:
|
|
pointer allocate_(size_type cItems, void const* hint)
|
|
{
|
|
#ifdef STLSOFT_LF_ALLOCATOR_ALLOCATE_HAS_HINT
|
|
# ifdef STLSOFT_CF_STD_LIBRARY_IS_SUNPRO_RW
|
|
return static_cast<pointer>(get_allocator().allocate(cItems, const_cast<void*>(hint)));
|
|
# else /* ? STLSOFT_CF_STD_LIBRARY_IS_SUNPRO_RW */
|
|
return get_allocator().allocate(cItems, hint);
|
|
# endif /* STLSOFT_CF_STD_LIBRARY_IS_SUNPRO_RW */
|
|
#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)
|
|
{
|
|
return allocate_(cItems, NULL);
|
|
}
|
|
|
|
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)
|
|
{
|
|
// 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());
|
|
|
|
// Swap:
|
|
//
|
|
// 1. Allocator
|
|
// 2. Member variables
|
|
|
|
// 1. Allocator
|
|
#if !defined(STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE)
|
|
std_swap(static_cast<allocator_type&>(*this), static_cast<allocator_type&>(rhs));
|
|
#endif /* !STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
|
|
|
|
// 2. Member variables
|
|
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_LF_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()
|
|
{
|
|
STLSOFT_ASSERT(is_valid());
|
|
|
|
return reverse_iterator(end());
|
|
}
|
|
/// Ends the reverse iteration
|
|
///
|
|
/// \return An iterator representing the end of the reverse sequence
|
|
reverse_iterator rend()
|
|
{
|
|
STLSOFT_ASSERT(is_valid());
|
|
|
|
return reverse_iterator(begin());
|
|
}
|
|
#endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
|
|
|
|
/// @}
|
|
|
|
/// \name Attributes
|
|
/// @{
|
|
public:
|
|
/// \brief Returns the number of elements in the auto_buffer
|
|
///
|
|
/// \note In the case where memory allocation has failed in the context
|
|
/// where exceptions are not thrown for allocation failure in the
|
|
/// constructor, this method will return 0. Hence, operations on the
|
|
/// <i>empty</i> auto_buffer<> instance will be safe if made in respect of
|
|
/// the value returned by this method.
|
|
size_type size() const
|
|
{
|
|
STLSOFT_ASSERT(is_valid());
|
|
|
|
return m_cItems;
|
|
}
|
|
|
|
/// \brief Returns the number of elements in the auto_buffer's internal buffer
|
|
static size_type internal_size()
|
|
{
|
|
return space;
|
|
}
|
|
|
|
/// \brief Indicates whether the buffer has any contents
|
|
///
|
|
/// \note This will only ever be true when an allocation above the number
|
|
/// of elements in the internal array has been requested, and failed.
|
|
ss_bool_t empty() const
|
|
{
|
|
STLSOFT_ASSERT(is_valid());
|
|
|
|
return 0 == m_cItems;
|
|
}
|
|
|
|
#if defined(STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVEx)
|
|
/// \brief Returns an instance of the allocator used to specialise the
|
|
/// instance.
|
|
static allocator_type &get_allocator()
|
|
{
|
|
# if !defined(STLSOFT_STRICT) && \
|
|
defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
_MSC_VER >= 1310
|
|
# pragma warning(push)
|
|
# pragma warning(disable : 4640) /* "construction of local static object is not thread-safe" - since it is here! (As long as one uses a 'conformant' allocator) - maybe use a spin_mutex in future */
|
|
# endif /* compiler */
|
|
|
|
static allocator_type s_allocator;
|
|
|
|
return s_allocator;
|
|
|
|
# if !defined(STLSOFT_STRICT) && \
|
|
defined(STLSOFT_COMPILER_IS_MSVC) && \
|
|
_MSC_VER >= 1310
|
|
# pragma warning(pop)
|
|
# endif /* compiler */
|
|
}
|
|
#else /* ? STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
|
|
/// \brief Returns an instance of the allocator used to specialise the
|
|
/// instance.
|
|
allocator_type get_allocator() const
|
|
{
|
|
# if defined(STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE)
|
|
return allocator_type();
|
|
# else /* ? STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
|
|
return *this;
|
|
# endif /* STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
|
|
}
|
|
#endif /* STLSOFT_CF_ALLOCATOR_BASE_EXPENSIVE */
|
|
/// @}
|
|
|
|
/// \name Implementation
|
|
/// @{
|
|
private:
|
|
ss_bool_t is_valid() const
|
|
{
|
|
ss_bool_t bRet = true;
|
|
|
|
#if defined(STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK)
|
|
if( space < m_cItems &&
|
|
!m_bExternal)
|
|
{
|
|
# ifdef STLSOFT_UNITTEST
|
|
printf("auto_buffer is in external domain, but think's it isn't\n");
|
|
# endif /* STLSOFT_UNITTEST */
|
|
|
|
bRet = false;
|
|
}
|
|
if( !(space < m_cItems) &&
|
|
m_bExternal)
|
|
{
|
|
# ifdef STLSOFT_UNITTEST
|
|
printf("auto_buffer is in internal domain, but think's it isn't\n");
|
|
# endif /* STLSOFT_UNITTEST */
|
|
|
|
bRet = false;
|
|
}
|
|
#else /* ? STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
|
|
|
|
if( space < m_cItems &&
|
|
!m_bExternal)
|
|
{
|
|
# ifdef STLSOFT_UNITTEST
|
|
printf("auto_buffer is in external domain, but think's it isn't\n");
|
|
# endif /* STLSOFT_UNITTEST */
|
|
|
|
bRet = false;
|
|
}
|
|
#endif /* STLSOFT_AUTO_BUFFER_AGGRESSIVE_SHRINK */
|
|
|
|
if(m_bExternal)
|
|
{
|
|
if(m_buffer == &m_internal[0])
|
|
{
|
|
#ifdef STLSOFT_UNITTEST
|
|
printf("auto_buffer is in external domain, but buffer refers to internal array\n");
|
|
#endif /* STLSOFT_UNITTEST */
|
|
|
|
bRet = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_buffer != &m_internal[0])
|
|
{
|
|
#ifdef STLSOFT_UNITTEST
|
|
printf("auto_buffer is in internal domain, but buffer does not refer to internal array\n");
|
|
#endif /* STLSOFT_UNITTEST */
|
|
|
|
bRet = false;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
/// @}
|
|
|
|
/// \name Members
|
|
/// @{
|
|
private:
|
|
pointer m_buffer; // Pointer to used buffer
|
|
size_type m_cItems; // Number of items in buffer
|
|
ss_bool_t m_bExternal; // This is required, since not allowed to compare m_buffer with &m_internal[0] - can't remember why; // NOTE: Check std
|
|
value_type m_internal[space]; // Internal storage
|
|
/// @}
|
|
|
|
// Not to be implemented
|
|
private:
|
|
auto_buffer(class_type const& rhs);
|
|
auto_buffer const& operator =(class_type const& rhs);
|
|
};
|
|
|
|
|
|
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
|
|
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) && \
|
|
!defined(STLSOFT_COMPILER_IS_DMC)
|
|
, ss_size_t SPACE = auto_buffer_internal_size_calculator<T>::value
|
|
# else /* ? compiler */
|
|
, ss_size_t SPACE = 256
|
|
# endif /* compiler */
|
|
# else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT */
|
|
, ss_size_t SPACE /* = auto_buffer_internal_size_calculator<T>::value */
|
|
# endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_FUNDAMENTAL_ARGUMENT_SUPPORT */
|
|
>
|
|
class auto_buffer_old
|
|
# if defined(STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS)
|
|
: public auto_buffer<T, A, SPACE>
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
: public auto_buffer<T, SPACE, A>
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
{
|
|
/// \name Member Types
|
|
/// @{
|
|
private:
|
|
# if defined(STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS)
|
|
typedef auto_buffer<T, A, SPACE> parent_class_type;
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
typedef auto_buffer<T, SPACE, A> parent_class_type;
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
typedef auto_buffer_old<T, A, SPACE> class_type;
|
|
|
|
public:
|
|
typedef ss_typename_type_k parent_class_type::value_type value_type;
|
|
typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
|
|
typedef ss_typename_type_k parent_class_type::reference reference;
|
|
typedef ss_typename_type_k parent_class_type::const_reference const_reference;
|
|
typedef ss_typename_type_k parent_class_type::pointer pointer;
|
|
typedef ss_typename_type_k parent_class_type::const_pointer const_pointer;
|
|
typedef ss_typename_type_k parent_class_type::size_type size_type;
|
|
typedef ss_typename_type_k parent_class_type::difference_type difference_type;
|
|
typedef ss_typename_type_k parent_class_type::iterator iterator;
|
|
typedef ss_typename_type_k parent_class_type::const_iterator const_iterator;
|
|
# if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
|
|
typedef ss_typename_type_k parent_class_type::reverse_iterator reverse_iterator;
|
|
typedef ss_typename_type_k parent_class_type::const_reverse_iterator const_reverse_iterator;
|
|
# endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
|
|
/// @}
|
|
|
|
/// \name Construction
|
|
/// @{
|
|
public:
|
|
ss_explicit_k auto_buffer_old(size_type cItems)
|
|
: parent_class_type(cItems)
|
|
{}
|
|
/// @}
|
|
|
|
// Not to be implemented
|
|
private:
|
|
auto_buffer_old(class_type const& rhs);
|
|
class_type& operator =(class_type const& rhs);
|
|
};
|
|
|
|
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* swapping
|
|
*/
|
|
|
|
#if !defined(STLSOFT_COMPILER_IS_WATCOM)
|
|
template< ss_typename_param_k T
|
|
# ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
, ss_typename_param_k A
|
|
, ss_size_t SPACE
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
, ss_size_t SPACE
|
|
, ss_typename_param_k A
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
>
|
|
# ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
inline void swap(auto_buffer<T, A, SPACE>& lhs, auto_buffer<T, A, SPACE>& rhs)
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
inline void swap(auto_buffer<T, SPACE, A>& lhs, auto_buffer<T, SPACE, A>& rhs)
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
{
|
|
lhs.swap(rhs);
|
|
}
|
|
#endif /* compiler */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Shims
|
|
*/
|
|
|
|
#ifndef STLSOFT_CF_TEMPLATE_SHIMS_NOT_SUPPORTED
|
|
|
|
template< ss_typename_param_k T
|
|
# ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
, ss_typename_param_k A
|
|
, ss_size_t SPACE
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
, ss_size_t SPACE
|
|
, ss_typename_param_k A
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
>
|
|
# ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
inline ss_bool_t is_empty(auto_buffer<T, A, SPACE> const& b)
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
inline ss_bool_t is_empty(auto_buffer<T, SPACE, A> const& b)
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
{
|
|
return b.empty();
|
|
}
|
|
|
|
#endif /* !STLSOFT_CF_TEMPLATE_SHIMS_NOT_SUPPORTED */
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Unit-testing
|
|
|
|
#ifdef STLSOFT_UNITTEST
|
|
# include "./unittest/auto_buffer_unittest_.h"
|
|
#endif /* STLSOFT_UNITTEST */
|
|
|
|
/* ////////////////////////////////////////////////////////////////////// */
|
|
|
|
#ifndef _STLSOFT_NO_NAMESPACE
|
|
} // namespace stlsoft
|
|
#endif /* _STLSOFT_NO_NAMESPACE */
|
|
|
|
/* In the special case of Intel behaving as VC++ 7.0 or earlier on Win32, we
|
|
* illegally insert into the std namespace.
|
|
*/
|
|
#if defined(STLSOFT_CF_std_NAMESPACE)
|
|
# if ( ( defined(STLSOFT_COMPILER_IS_INTEL) && \
|
|
defined(_MSC_VER))) && \
|
|
_MSC_VER < 1310
|
|
namespace std
|
|
{
|
|
template< ss_typename_param_k T
|
|
# ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
, ss_typename_param_k A
|
|
, stlsoft_ns_qual(ss_size_t) SPACE
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
, stlsoft_ns_qual(ss_size_t) SPACE
|
|
, ss_typename_param_k A
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
>
|
|
# ifdef STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS
|
|
inline void swap(stlsoft_ns_qual(auto_buffer)<T, A, SPACE>& lhs, stlsoft_ns_qual(auto_buffer)<T, A, SPACE>& rhs)
|
|
# else /* ? STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
inline void swap(stlsoft_ns_qual(auto_buffer)<T, SPACE, A>& lhs, stlsoft_ns_qual(auto_buffer)<T, SPACE, A>& rhs)
|
|
# endif /* STLSOFT_AUTO_BUFFER_USE_PRE_1_9_CHARACTERISTICS */
|
|
{
|
|
lhs.swap(rhs);
|
|
}
|
|
} // namespace std
|
|
# endif /* INTEL && _MSC_VER < 1310 */
|
|
#endif /* STLSOFT_CF_std_NAMESPACE */
|
|
|
|
/* ////////////////////////////////////////////////////////////////////// */
|
|
|
|
#endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
|
|
|
|
/* ///////////////////////////// end of file //////////////////////////// */
|