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.
1684 lines
57 KiB
1684 lines
57 KiB
/* /////////////////////////////////////////////////////////////////////////
|
|
* File: mfcstl/collections/carray_adaptors.hpp (derived from mfcstl_array_adaptor.h)
|
|
*
|
|
* Purpose: Contains the definition of the CArray_cadaptor and CArray_iadaptor
|
|
* class templates.
|
|
*
|
|
* Created: 1st December 2002
|
|
* Updated: 10th August 2009
|
|
*
|
|
* Thanks to: Nevin Liber and Scott Meyers for kicking my lazy behind, and
|
|
* requiring that I implement the full complement of standard
|
|
* comparison operations.
|
|
*
|
|
* Home: http://stlsoft.org/
|
|
*
|
|
* Copyright (c) 2002-2009, 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 mfcstl/collections/carray_adaptors.hpp
|
|
*
|
|
* \brief [C++ only] Definition of the mfcstl::CArray_cadaptor and
|
|
* mfcstl::CArray_iadaptor traits class templates
|
|
* (\ref group__library__collections "Collections" Library).
|
|
*/
|
|
|
|
#ifndef MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS
|
|
#define MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS
|
|
|
|
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
# define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_MAJOR 4
|
|
# define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_MINOR 2
|
|
# define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_REVISION 1
|
|
# define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_EDIT 82
|
|
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Compatibility
|
|
*/
|
|
|
|
/*
|
|
[Incompatibilies-start]
|
|
STLSOFT_COMPILER_IS_MSVC: _MSC_VER==1300
|
|
[Incompatibilies-end]
|
|
*/
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Includes
|
|
*/
|
|
|
|
#ifndef MFCSTL_INCL_MFCSTL_HPP_MFCSTL
|
|
# include <mfcstl/mfcstl.hpp>
|
|
#endif /* !MFCSTL_INCL_MFCSTL_HPP_MFCSTL */
|
|
#ifndef MFCSTL_INCL_MFCSTL_MEMORY_HPP_AFX_ALLOCATOR
|
|
# include <mfcstl/memory/afx_allocator.hpp>
|
|
#endif /* !MFCSTL_INCL_MFCSTL_MEMORY_HPP_AFX_ALLOCATOR */
|
|
#ifndef MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_SWAP
|
|
# include <mfcstl/collections/carray_swap.hpp>
|
|
#endif /* !MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_SWAP */
|
|
#ifndef MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_TRAITS
|
|
# include <mfcstl/collections/carray_traits.hpp>
|
|
#endif /* !MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_TRAITS */
|
|
#ifndef MFCSTL_INCL_MFCSTL_UTIL_HPP_MEMORY_EXCEPTION_TRANSLATION_POLICIES
|
|
# include <mfcstl/util/memory_exception_translation_policies.hpp>
|
|
#endif /* !MFCSTL_INCL_MFCSTL_UTIL_HPP_MEMORY_EXCEPTION_TRANSLATION_POLICIES */
|
|
#ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_GENERATORS
|
|
# include <stlsoft/util/std/iterator_generators.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_GENERATORS */
|
|
#ifndef STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES
|
|
# include <stlsoft/meta/capabilities.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES */
|
|
#ifdef STLSOFT_META_HAS_IS_SAME_TYPE
|
|
# ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE
|
|
# include <stlsoft/meta/is_same_type.hpp>
|
|
# endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE */
|
|
#endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
#ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
|
|
# include <stlsoft/collections/util/collections.hpp>
|
|
#endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
|
|
#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 */
|
|
|
|
#if defined(STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT) && \
|
|
!defined(MFCSTL_NO_INCLUDE_AFXTEMPL_BY_DEFAULT)
|
|
# include <afxtempl.h>
|
|
#endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT && !MFCSTL_NO_INCLUDE_AFXTEMPL_BY_DEFAULT */
|
|
|
|
#ifndef STLSOFT_INCL_ALGORITHM
|
|
# define STLSOFT_INCL_ALGORITHM
|
|
# include <algorithm>
|
|
#endif /* !STLSOFT_INCL_ALGORITHM */
|
|
|
|
#ifdef STLSOFT_UNITTEST
|
|
# include <afxtempl.h>
|
|
# include <stlsoft/string/simple_string.hpp>
|
|
#endif /* STLSOFT_UNITTEST */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Namespace
|
|
*/
|
|
|
|
#ifndef _MFCSTL_NO_NAMESPACE
|
|
# if defined(_STLSOFT_NO_NAMESPACE) || \
|
|
defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
|
|
/* There is no stlsoft namespace, so must define ::mfcstl */
|
|
namespace mfcstl
|
|
{
|
|
# else
|
|
/* Define stlsoft::mfcstl_project */
|
|
|
|
namespace stlsoft
|
|
{
|
|
|
|
namespace mfcstl_project
|
|
{
|
|
|
|
# endif /* _STLSOFT_NO_NAMESPACE */
|
|
#endif /* !_MFCSTL_NO_NAMESPACE */
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Classes
|
|
*/
|
|
|
|
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
// Forward declarations
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
class CArray_adaptor_base;
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k T
|
|
>
|
|
class CArray_cadaptor;
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k T
|
|
>
|
|
class CArray_iadaptor;
|
|
|
|
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
|
|
/** \brief Adaptor class, providing implementation for CArray_cadaptor and
|
|
* CArray_iadaptor classes
|
|
*
|
|
* \ingroup group__library__collections
|
|
*
|
|
* \param A The array class, e.g. CObArray, CArray<long>, etc.
|
|
* \param I The interface specialisation, e.g. CArray_cadaptor<CObArray>, CArray_iadaptor<CArray<long> >, etc.
|
|
* \param T The traits class, e.g. CArray_traits<CObArray>
|
|
*
|
|
* \note The elements in an adapted array are moved, during insertion / erasure, rather than copied. This
|
|
* means that if the elements in the container maintain pointers to their elements, or their peers, then
|
|
* they are not suitable for use.
|
|
*/
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
class CArray_adaptor_base
|
|
: public stlsoft_ns_qual(stl_collection_tag)
|
|
{
|
|
/// \name Member Types
|
|
/// @{
|
|
public:
|
|
/// The type of the underlying MFC array
|
|
typedef A array_type;
|
|
private:
|
|
typedef I interface_class_type;
|
|
typedef T array_traits_type;
|
|
#if defined(MFCSTL_CARRAY_ADAPTORS_USE_BAD_ALLOC_POLICY)
|
|
typedef bad_alloc_throwing_policy exception_translation_policy_type;
|
|
#else /* ? MFCSTL_CARRAY_ADAPTORS_USE_BAD_ALLOC_POLICY */
|
|
typedef CMemoryException_throwing_policy exception_translation_policy_type;
|
|
#endif /* MFCSTL_CARRAY_ADAPTORS_USE_BAD_ALLOC_POLICY */
|
|
public:
|
|
/// The value type
|
|
///
|
|
/// \note If the compiler report "use of undefined type" when you're using the adaptor class(es)
|
|
/// with CArray<>, ensure that you've included <b>afxtempl</b> <i>before</i> you include this file.
|
|
typedef ss_typename_type_k array_traits_type::value_type value_type;
|
|
/// The allocator type
|
|
typedef afx_allocator<value_type> allocator_type;
|
|
/// The mutating (non-const) reference type
|
|
typedef ss_typename_type_k allocator_type::reference reference;
|
|
/// The non-mutating (const) reference type
|
|
typedef ss_typename_type_k allocator_type::const_reference const_reference;
|
|
/// The mutating (non-const) pointer type
|
|
typedef ss_typename_type_k allocator_type::pointer pointer;
|
|
/// The non-mutating (const) pointer type
|
|
typedef ss_typename_type_k allocator_type::const_pointer const_pointer;
|
|
/// The mutating (non-const) 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 size type
|
|
typedef ms_size_t size_type;
|
|
/// The difference type
|
|
typedef ms_ptrdiff_t difference_type;
|
|
/// The instantiation of the current type
|
|
typedef CArray_adaptor_base<A, I, T> class_type;
|
|
#ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
|
|
/// The mutating (non-const) reverse iterator type
|
|
typedef ss_typename_type_k reverse_iterator_generator < iterator
|
|
, value_type
|
|
, reference
|
|
, pointer
|
|
, difference_type
|
|
>::type reverse_iterator;
|
|
|
|
/// The non-mutating (const) reverse iterator type
|
|
typedef ss_typename_type_k const_reverse_iterator_generator < const_iterator
|
|
, value_type
|
|
, const_reference
|
|
, const_pointer
|
|
, difference_type
|
|
>::type const_reverse_iterator;
|
|
#endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
|
|
/// @}
|
|
|
|
/// \name Member Constants
|
|
/// @{
|
|
protected:
|
|
enum { growthGranularity = 16 };
|
|
|
|
static size_type calc_increment_(size_type n)
|
|
{
|
|
size_type numBlocks = n / growthGranularity;
|
|
|
|
return (1 + numBlocks) * growthGranularity;
|
|
}
|
|
/// @}
|
|
|
|
/// \name Underlying Container Access
|
|
/// @{
|
|
public:
|
|
/// \brief Returns a mutating (non-const) reference to the underlying array
|
|
array_type &get_CArray()
|
|
{
|
|
return static_cast<interface_class_type*>(this)->get_actual_array();
|
|
}
|
|
/// \brief Returns a non-mutating (const) reference to the underlying array
|
|
array_type const &get_CArray() const
|
|
{
|
|
return static_cast<interface_class_type const*>(this)->get_actual_array();
|
|
}
|
|
/// @}
|
|
|
|
/// \name Construction
|
|
/// @{
|
|
protected:
|
|
/// \brief Default constructor.
|
|
///
|
|
/// This is protected, because CArray_adaptor_base serves as an abstract base
|
|
/// for CArray_cadaptor and CArray_iadaptor
|
|
CArray_adaptor_base()
|
|
{}
|
|
/// \brief Destructor
|
|
~CArray_adaptor_base() stlsoft_throw_0()
|
|
{}
|
|
public:
|
|
/// Returns a copy of the allocator used by the container
|
|
allocator_type get_allocator() const
|
|
{
|
|
return allocator_type();
|
|
}
|
|
#if defined(_DEBUG) || \
|
|
defined(MFCSTL_ARRAY_ADAPTORS_ALLOW_CAPACITY_PEEK)
|
|
public:
|
|
#else /* ? _DEBUG */
|
|
protected:
|
|
#endif /* _DEBUG */
|
|
size_type grow_increment() const
|
|
{
|
|
class GrowByGetter
|
|
: public array_type
|
|
{
|
|
public:
|
|
size_type grow_increment() const
|
|
{
|
|
return m_nGrowBy;
|
|
}
|
|
};
|
|
|
|
return static_cast<GrowByGetter const&>(get_CArray()).grow_increment();
|
|
}
|
|
size_type capacity() const
|
|
{
|
|
class CapacityGetter
|
|
: public array_type
|
|
{
|
|
public:
|
|
size_type capacity() const
|
|
{
|
|
return m_nMaxSize;
|
|
}
|
|
};
|
|
|
|
return static_cast<CapacityGetter const&>(get_CArray()).capacity();
|
|
}
|
|
/// @}
|
|
|
|
/// \name Assignment
|
|
/// @{
|
|
public:
|
|
/// \brief Assigns a number of copies of the given value to the array, erasing all prior content
|
|
///
|
|
/// \param n The number of values to assign
|
|
/// \param value The value of which n copies are to be assigned
|
|
///
|
|
/// \note Exception-safety is <b>strong</b> if MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT is defined, otherwise <b>weak</b>.
|
|
///
|
|
/// \note The elements are default constructed, and then copy-assigned
|
|
void assign(size_type n, value_type const& value)
|
|
{
|
|
#ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
|
|
try
|
|
{
|
|
array_type ar;
|
|
|
|
ar.SetSize(0, calc_increment_(n));
|
|
if(n > 0) // Can't pass 0 to InsertAt()
|
|
{
|
|
ar.InsertAt(0, value, static_cast<int>(n));
|
|
}
|
|
CArray_swap(this->get_CArray(), ar);
|
|
}
|
|
catch(CMemoryException *px)
|
|
{
|
|
exception_translation_policy_type::handle(px);
|
|
}
|
|
catch(mfcstl_ns_qual_std(bad_alloc) &x)
|
|
{
|
|
exception_translation_policy_type::handle(x);
|
|
}
|
|
#else /* ? MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
// if( empty() &&
|
|
// 0 != n)
|
|
// {
|
|
// resize(1);
|
|
// }
|
|
resize(n);
|
|
mfcstl_ns_qual_std(fill_n)(begin(), n, value);
|
|
#endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
|
|
// Postcondition
|
|
MFCSTL_ASSERT(size() == n);
|
|
}
|
|
|
|
/// \brief Assigns each element in the range [first, last) to the array, erasing all prior content
|
|
///
|
|
/// \param first The first element in the range
|
|
/// \param last The (one past the) last element in the range
|
|
///
|
|
/// \note Exception-safety is <b>strong</b> if MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT is defined, otherwise <b>weak</b>.
|
|
///
|
|
/// \note The elements are default constructed, and then copy-assigned
|
|
template <ss_typename_param_k I2>
|
|
void assign(I2 first, I2 last)
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(is_valid_source_range_(first, last));
|
|
|
|
#ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
|
|
if(empty())
|
|
{
|
|
// If "this" is empty, then we can call clear_and_assign_() to instantiate it
|
|
// and just catch any thrown exception and call clear() to ensure strong
|
|
// exception safety.
|
|
try
|
|
{
|
|
clear_and_assign_(first, last);
|
|
}
|
|
catch(...)
|
|
{
|
|
clear();
|
|
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Otherwise we need to do construct-and-swap idiom, indirectly, via
|
|
// an instance of the underlying array type and the CArray_iadaptor.
|
|
array_type ar;
|
|
CArray_iadaptor<array_type
|
|
, array_traits_type
|
|
> arp(ar);
|
|
arp.assign(first, last);
|
|
|
|
CArray_swap(this->get_CArray(), ar);
|
|
}
|
|
#else /* ? MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
clear_and_assign_(first, last);
|
|
#endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
}
|
|
/// @}
|
|
|
|
/// \name Size and Capacity
|
|
/// @{
|
|
public:
|
|
/// \brief The number of items in the array
|
|
size_type size() const
|
|
{
|
|
return static_cast<size_type>(get_CArray().GetSize());
|
|
}
|
|
/// \brief The maximum number of items that can be stored in the array
|
|
size_type max_size() const
|
|
{
|
|
return get_allocator().max_size();
|
|
}
|
|
/// \brief Indicates whether the array is empty
|
|
ms_bool_t empty() const
|
|
{
|
|
return 0 == size();
|
|
}
|
|
/// \brief Adjusts the number of elements in the array
|
|
///
|
|
/// \param n The number of elements that the array will contain after resizing
|
|
///
|
|
/// \note Exception-safety is <b>strong</b> if the default constructor of the value type
|
|
/// cannot throw exceptions, otherwise it is weak
|
|
void resize(size_type n)
|
|
{
|
|
try
|
|
{
|
|
get_CArray().SetSize(n, calc_increment_(n));
|
|
}
|
|
catch(CMemoryException *px)
|
|
{
|
|
exception_translation_policy_type::handle(px);
|
|
}
|
|
catch(mfcstl_ns_qual_std(bad_alloc) &x)
|
|
{
|
|
exception_translation_policy_type::handle(x);
|
|
}
|
|
|
|
// Postcondition
|
|
MFCSTL_ASSERT(size() == n);
|
|
}
|
|
/// \brief Adjusts the number of elements in the array
|
|
///
|
|
/// \param n The number of elements that the array will contain after resizing
|
|
/// \param value The value of any additional elements created during resizing
|
|
///
|
|
/// \note Due to the limitations of the underlying CArray-family containers, the
|
|
/// additional elements are default constructed and then subjected to
|
|
/// copy-assignment.
|
|
///
|
|
/// \note Exception-safety is <b>weak</b>, but the size is maintained in the case
|
|
/// where an exception is thrown by the copy assignment of any new elements.
|
|
void resize(size_type n, value_type value)
|
|
{
|
|
const size_type oldSize = size();
|
|
resize(n);
|
|
if(oldSize < n)
|
|
{
|
|
try
|
|
{
|
|
mfcstl_ns_qual_std(fill_n)(begin() + oldSize, n - oldSize, value);
|
|
}
|
|
catch(...)
|
|
{
|
|
resize(oldSize);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
/// @}
|
|
|
|
/// \name Element access
|
|
/// @{
|
|
public:
|
|
/// \brief Returns a mutable (non-const) reference to the element at the given index
|
|
///
|
|
/// \param n The requested index. Must be less than size()
|
|
///
|
|
/// \note The implementation will assert in debug mode if the index is out of range
|
|
reference operator [](size_type n)
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("index out of bounds", n < size());
|
|
|
|
return get_CArray()[n];
|
|
}
|
|
/// \brief Returns a non-mutable (const) reference to the element at the given index
|
|
///
|
|
/// \param n The requested index. Must be less than size()
|
|
///
|
|
/// \note The implementation will assert in debug mode if the index is out of range
|
|
const_reference operator [](size_type n) const
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("index out of bounds", n < size());
|
|
|
|
return get_CArray()[n];
|
|
}
|
|
/// \brief Returns a mutable (non-const) reference to the element at the given index
|
|
///
|
|
/// \param n The requested index. If the index is not less than size() an
|
|
/// instance of std::out_of_range will be thrown
|
|
reference at(size_type n)
|
|
{
|
|
if(n >= size())
|
|
{
|
|
STLSOFT_THROW_X(mfcstl_ns_qual_std(out_of_range)("Invalid index specified"));
|
|
}
|
|
|
|
return (*this)[n];
|
|
}
|
|
/// \brief Returns a non-mutable (const) reference to the element at the given index
|
|
///
|
|
/// \param n The requested index. If the index is not less than size() an
|
|
/// instance of std::out_of_range will be thrown
|
|
const_reference at(size_type n) const
|
|
{
|
|
if(n >= size())
|
|
{
|
|
STLSOFT_THROW_X(mfcstl_ns_qual_std(out_of_range)("Invalid index specified"));
|
|
}
|
|
return (*this)[n];
|
|
}
|
|
/// \brief Returns a mutable (non-const) reference to the first element in the array
|
|
reference front()
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("front() called on an empty instance", !empty());
|
|
|
|
return (*this)[0];
|
|
}
|
|
/// \brief Returns a mutable (non-const) reference to the last element in the array
|
|
reference back()
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("back() called on an empty instance", !empty());
|
|
|
|
return (*this)[size() - 1];
|
|
}
|
|
/// \brief Returns a non-mutable (const) reference to the first element in the array
|
|
const_reference front() const
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("front() called on an empty instance", !empty());
|
|
|
|
return (*this)[0];
|
|
}
|
|
/// \brief Returns a non-mutable (const) reference to the last element in the array
|
|
const_reference back() const
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("back() called on an empty instance", !empty());
|
|
|
|
return (*this)[size() - 1];
|
|
}
|
|
/// @}
|
|
|
|
/// \name Iteration
|
|
/// @{
|
|
public:
|
|
/// \brief Returns a mutable (non-const) iterator representing the start of the array
|
|
iterator begin()
|
|
{
|
|
return get_CArray().GetData();
|
|
}
|
|
/// \brief Returns a mutable (non-const) iterator representing the end of the array
|
|
iterator end()
|
|
{
|
|
return begin() + size();
|
|
}
|
|
/// \brief Returns a non-mutable (const) iterator representing the start of the array
|
|
const_iterator begin() const
|
|
{
|
|
// This is needed because CXxxxArray::GetData() const returns, e.g., const CObject** instead of CObject* const*
|
|
value_type const *p1 = get_CArray().GetData();
|
|
value_type *const p2 = const_cast<value_type *const>(p1);
|
|
|
|
return p2;
|
|
}
|
|
/// \brief Returns a non-mutable (const) iterator representing the end of the array
|
|
const_iterator end() const
|
|
{
|
|
return begin() + size();
|
|
}
|
|
#ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
|
|
/// \brief Returns a mutable (non-const) reverse iterator representing the start of the array
|
|
reverse_iterator rbegin()
|
|
{
|
|
return reverse_iterator(end());
|
|
}
|
|
/// \brief Returns a mutable (non-const) reverse iterator representing the end of the array
|
|
reverse_iterator rend()
|
|
{
|
|
return reverse_iterator(begin());
|
|
}
|
|
/// \brief Returns a non-mutable (const) reverse iterator representing the start of the array
|
|
const_reverse_iterator rbegin() const
|
|
{
|
|
return const_reverse_iterator(end());
|
|
}
|
|
/// \brief Returns a non-mutable (const) reverse iterator representing the end of the array
|
|
const_reverse_iterator rend() const
|
|
{
|
|
return const_reverse_iterator(begin());
|
|
}
|
|
#endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
|
|
/// @}
|
|
|
|
/// \name Comparison
|
|
/// @{
|
|
public:
|
|
template< ss_typename_param_k A2
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T2
|
|
>
|
|
ms_bool_t equal(CArray_adaptor_base<A2, I2, T2> const& rhs) const
|
|
{
|
|
typedef CArray_adaptor_base<A2, I2, T2> rhs_t;
|
|
typedef ss_typename_type_k rhs_t::value_type rhs_value_t;
|
|
|
|
STLSOFT_STATIC_ASSERT(sizeof(value_type) == sizeof(ss_typename_type_k rhs_t::value_type));
|
|
|
|
#ifdef STLSOFT_META_HAS_IS_SAME_TYPE
|
|
STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<value_type, rhs_value_t>::value));
|
|
#endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
|
|
return size() == rhs.size() && stlsoft_ns_qual_std(equal)(begin(), end(), rhs.begin());
|
|
}
|
|
|
|
ms_bool_t equal(array_type const& rhs) const
|
|
{
|
|
array_type const &lhs = this->get_CArray();
|
|
|
|
return lhs.GetSize() == rhs.GetSize() && stlsoft_ns_qual_std(equal)(begin(), end(), rhs.GetData());
|
|
}
|
|
|
|
template< ss_typename_param_k A2
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T2
|
|
>
|
|
ms_bool_t less_than(CArray_adaptor_base<A2, I2, T2> const& rhs) const
|
|
{
|
|
typedef CArray_adaptor_base<A2, I2, T2> rhs_t;
|
|
typedef ss_typename_type_k rhs_t::value_type rhs_value_t;
|
|
|
|
STLSOFT_STATIC_ASSERT(sizeof(value_type) == sizeof(ss_typename_type_k rhs_t::value_type));
|
|
|
|
#ifdef STLSOFT_META_HAS_IS_SAME_TYPE
|
|
STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<value_type, rhs_value_t>::value));
|
|
#endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
|
|
return stlsoft_ns_qual_std(lexicographical_compare)(begin(), end(), rhs.begin(), rhs.end());
|
|
}
|
|
|
|
ms_bool_t less_than(array_type const& rhs) const
|
|
{
|
|
return stlsoft_ns_qual_std(lexicographical_compare)(begin(), end(), rhs.GetData(), rhs.GetData() + rhs.GetSize());
|
|
}
|
|
|
|
template< ss_typename_param_k A2
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T2
|
|
>
|
|
ms_bool_t greater_than(CArray_adaptor_base<A2, I2, T2> const& rhs) const
|
|
{
|
|
typedef CArray_adaptor_base<A2, I2, T2> rhs_t;
|
|
typedef ss_typename_type_k rhs_t::value_type rhs_value_t;
|
|
|
|
STLSOFT_STATIC_ASSERT(sizeof(value_type) == sizeof(ss_typename_type_k rhs_t::value_type));
|
|
|
|
#ifdef STLSOFT_META_HAS_IS_SAME_TYPE
|
|
STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<value_type, rhs_value_t>::value));
|
|
#endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
|
|
return stlsoft_ns_qual_std(lexicographical_compare)(rhs.begin(), rhs.end(), begin(), end());
|
|
}
|
|
|
|
ms_bool_t greater_than(array_type const& rhs) const
|
|
{
|
|
return stlsoft_ns_qual_std(lexicographical_compare)(rhs.GetData(), rhs.GetData() + rhs.GetSize(), begin(), end());
|
|
}
|
|
/// @}
|
|
|
|
/// \name Modifiers
|
|
/// @{
|
|
public:
|
|
/// \brief Adds the given element to the end of the array
|
|
///
|
|
/// \param value The value to add to the end of the array
|
|
///
|
|
/// \note All iterators, pointers and references are invalidated
|
|
void push_back(value_type const& value)
|
|
{
|
|
const size_type oldSize = size();
|
|
|
|
resize(size());
|
|
|
|
try
|
|
{
|
|
try
|
|
{
|
|
get_CArray().Add(value);
|
|
}
|
|
catch(CMemoryException *px)
|
|
{
|
|
exception_translation_policy_type::handle(px);
|
|
}
|
|
catch(mfcstl_ns_qual_std(bad_alloc) &x)
|
|
{
|
|
exception_translation_policy_type::handle(x);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(size() != oldSize)
|
|
{
|
|
MFCSTL_ASSERT(size() == oldSize + 1);
|
|
|
|
resize(oldSize);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
/// \brief Removes the last element from the non-empty array
|
|
///
|
|
/// \note The behaviour is undefined if the array is empty
|
|
void pop_back() stlsoft_throw_0()
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_MESSAGE_ASSERT("pop_back() called on empty container", !empty());
|
|
|
|
get_CArray().RemoveAt(get_CArray().GetUpperBound());
|
|
}
|
|
/// \brief Inserts the given value at the given position
|
|
///
|
|
/// \param pos The position at which to insert. The value will be inserted
|
|
/// before the element referred to by pos, or at the end if pos == end()
|
|
/// \param value The value to be inserted
|
|
///
|
|
/// \retval The position of the inserted value
|
|
///
|
|
/// \note All iterators, pointers and references are invalidated
|
|
///
|
|
/// \note Any elements after the insertion position are moved using memmove,
|
|
/// rather than by copy construction. If the element type maintains
|
|
/// pointers to its internal members, or to its peer elements, then these
|
|
/// relationships will be broken, and the subsequent behaviour of the
|
|
/// program will be undefined
|
|
iterator insert(iterator pos, value_type const& value)
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
|
|
|
|
difference_type index = pos - begin();
|
|
const size_type oldSize = size();
|
|
|
|
resize(size());
|
|
|
|
try
|
|
{
|
|
try
|
|
{
|
|
get_CArray().InsertAt(static_cast<int>(index), value, 1);
|
|
}
|
|
catch(CMemoryException *px)
|
|
{
|
|
exception_translation_policy_type::handle(px);
|
|
}
|
|
catch(mfcstl_ns_qual_std(bad_alloc) &x)
|
|
{
|
|
exception_translation_policy_type::handle(x);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(size() != oldSize)
|
|
{
|
|
MFCSTL_ASSERT(size() == oldSize + 1);
|
|
|
|
get_CArray().RemoveAt(static_cast<int>(index), 1);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
|
|
return begin() + index;
|
|
}
|
|
/// \brief Inserts a number of copies of the given value at the given position
|
|
///
|
|
/// \param pos The position at which to insert. The value(s) will be inserted
|
|
/// before the element referred to by pos, or at the end if pos == end()
|
|
/// \param n The number of values to insert
|
|
/// \param value The value to be inserted
|
|
///
|
|
/// \note All iterators, pointers and references are invalidated
|
|
///
|
|
/// \note Any elements after the insertion position are moved using memmove,
|
|
/// rather than by copy construction. If the element type maintains
|
|
/// pointers to its internal members, or to its peer elements, then these
|
|
/// relationships will be broked, and the subsequent behaviour of the
|
|
/// program will be undefined
|
|
void insert(iterator pos, size_type n, value_type const& value)
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
|
|
|
|
difference_type index = pos - begin();
|
|
|
|
if(empty())
|
|
{
|
|
MFCSTL_ASSERT(0 == index);
|
|
|
|
assign(n, value);
|
|
}
|
|
else
|
|
{
|
|
const size_type oldSize = size();
|
|
|
|
resize(size());
|
|
|
|
try
|
|
{
|
|
try
|
|
{
|
|
if(n > 0) // Can't pass 0 to InsertAt()
|
|
{
|
|
get_CArray().InsertAt(static_cast<int>(index), value, n);
|
|
}
|
|
}
|
|
catch(CMemoryException *px)
|
|
{
|
|
exception_translation_policy_type::handle(px);
|
|
}
|
|
catch(mfcstl_ns_qual_std(bad_alloc) &x)
|
|
{
|
|
exception_translation_policy_type::handle(x);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(size() != oldSize)
|
|
{
|
|
MFCSTL_ASSERT(size() == oldSize + n);
|
|
|
|
get_CArray().RemoveAt(static_cast<int>(index), size() - oldSize);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
/// \brief Inserts the elements in the range [first, last) at the given position
|
|
///
|
|
/// \param pos The position at which to insert. The value(s) will be inserted
|
|
/// before the element referred to by pos, or at the end if pos == end()
|
|
/// \param first The start of the range of values to insert
|
|
/// \param last The (one past the) end of the range of values to insert
|
|
///
|
|
/// \note All iterators, pointers and references are invalidated
|
|
///
|
|
/// \note Any elements after the insertion position are moved using memmove,
|
|
/// rather than by copy construction. If the element type maintains
|
|
/// pointers to its internal members, or to its peer elements, then these
|
|
/// relationships will be broked, and the subsequent behaviour of the
|
|
/// program will be undefined
|
|
template <ss_typename_param_k I2>
|
|
void insert(iterator pos, I2 first, I2 last)
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(is_valid_source_range_(first, last));
|
|
MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
|
|
|
|
array_type ar;
|
|
CArray_iadaptor<array_type
|
|
, array_traits_type
|
|
> arp(ar);
|
|
arp.assign(first, last);
|
|
difference_type index = pos - begin();
|
|
const size_type oldSize = size();
|
|
const size_type n = arp.size();
|
|
|
|
resize(size());
|
|
|
|
try
|
|
{
|
|
try
|
|
{
|
|
get_CArray().InsertAt(static_cast<int>(index), &ar);
|
|
}
|
|
catch(CMemoryException *px)
|
|
{
|
|
exception_translation_policy_type::handle(px);
|
|
}
|
|
catch(mfcstl_ns_qual_std(bad_alloc) &x)
|
|
{
|
|
exception_translation_policy_type::handle(x);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
if(size() != oldSize)
|
|
{
|
|
MFCSTL_ASSERT(size() == oldSize + n);
|
|
|
|
get_CArray().RemoveAt(static_cast<int>(index), size() - oldSize);
|
|
}
|
|
|
|
throw;
|
|
}
|
|
}
|
|
/// \brief Erases the element at the given position
|
|
///
|
|
/// \param pos The position of the element to be removed
|
|
///
|
|
/// \retval The position of the value immediately following the element erased
|
|
///
|
|
/// \note Any iterators, pointers or references to elements at or after \c
|
|
/// pos will be invalidated. Those before \c pos remain valid
|
|
///
|
|
/// \note Any elements after the erasure position are moved using memmove,
|
|
/// rather than by copy construction. If the element type maintains
|
|
/// pointers to its internal members, or to its peer elements, then these
|
|
/// relationships will be broked, and the subsequent behaviour of the
|
|
/// program will be undefined
|
|
iterator erase(iterator pos) stlsoft_throw_0()
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
|
|
|
|
difference_type index = pos - begin();
|
|
get_CArray().RemoveAt(static_cast<int>(index), 1);
|
|
|
|
// Postcondition checks
|
|
MFCSTL_ASSERT(pos == begin() + index);
|
|
|
|
resize(size());
|
|
|
|
return pos;
|
|
}
|
|
/// \brief Erases a range of elements from the array
|
|
///
|
|
/// \param first The first element in the range to be removed
|
|
/// \param last The (one past the) end element in the range to be removed
|
|
///
|
|
/// \retval The position of the value immediately following the elements erased
|
|
///
|
|
/// \note Any iterators, pointers or references to elements at or after \c
|
|
/// first will be invalidated. Those before \c first remain valid
|
|
///
|
|
/// \note Any elements after the erasure position are moved using memmove,
|
|
/// rather than by copy construction. If the element type maintains
|
|
/// pointers to its internal members, or to its peer elements, then these
|
|
/// relationships will be broked, and the subsequent behaviour of the
|
|
/// program will be undefined
|
|
iterator erase(iterator first, iterator last) stlsoft_throw_0()
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(first <= last);
|
|
MFCSTL_ASSERT(first == end() || (first >= begin() && first < end()));
|
|
MFCSTL_ASSERT(last == end() || (last >= begin() && last < end()));
|
|
|
|
difference_type index = first - begin();
|
|
get_CArray().RemoveAt(static_cast<int>(index), mfcstl_ns_qual_std(distance)(first, last));
|
|
|
|
// Postcondition checks
|
|
MFCSTL_ASSERT(first == begin() + index);
|
|
|
|
resize(size());
|
|
|
|
return first;
|
|
}
|
|
/// \brief Removes all the elements from the array
|
|
void clear() stlsoft_throw_0()
|
|
{
|
|
get_CArray().RemoveAll();
|
|
|
|
resize(size());
|
|
}
|
|
|
|
#ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
|
|
/// \brief Efficiently exchanges the contents with those of another array
|
|
/// by swapping the internal structures
|
|
///
|
|
/// \param rhs The instance whose contents will be exchanged with the callee
|
|
///
|
|
/// \note This method is only defined if the preprocessor symbol
|
|
/// MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT is defined
|
|
void swap(class_type& rhs) stlsoft_throw_0()
|
|
{
|
|
mfcstl::CArray_swap(this->get_CArray(), rhs.get_CArray());
|
|
}
|
|
#endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
|
|
/// \brief Exchanges the contents with those of another array by copying
|
|
/// each of the constituents, using a temporary array instance.
|
|
///
|
|
/// \param rhs The instance whose contents will be exchanged with the callee
|
|
void swap_by_copy(class_type& rhs)
|
|
{
|
|
class_type t = rhs;
|
|
rhs = *this;
|
|
*this = t;
|
|
}
|
|
/// @}
|
|
|
|
/// \name Implementation
|
|
/// @{
|
|
private:
|
|
template <ss_typename_param_k I2>
|
|
# if defined(STLSOFT_COMPILER_IS_MWERKS)
|
|
// There seems to be a bug in CodeWarrior that makes it have a cow with iterator tags by value, so we just use a ptr
|
|
void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag) const*)
|
|
# else /* ? compiler */
|
|
void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag))
|
|
# endif /* compiler */
|
|
{
|
|
clear();
|
|
|
|
mfcstl_ns_qual_std(copy)(first, last, mfcstl_ns_qual_std(back_inserter)<class_type>(*this));
|
|
}
|
|
template <ss_typename_param_k I2>
|
|
# if defined(STLSOFT_COMPILER_IS_MWERKS)
|
|
// There seems to be a bug in CodeWarrior that makes it have a cow with iterator tags by value, so we just use a ptr
|
|
void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(forward_iterator_tag) const*)
|
|
# else /* ? compiler */
|
|
void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(forward_iterator_tag))
|
|
# endif /* compiler */
|
|
{
|
|
resize(mfcstl_ns_qual_std(distance)(first, last));
|
|
|
|
mfcstl_ns_qual_std(copy)(first, last, begin());
|
|
}
|
|
|
|
template <ss_typename_param_k I2>
|
|
void clear_and_assign_(I2 first, I2 last)
|
|
{
|
|
# if defined(STLSOFT_COMPILER_IS_GCC) && \
|
|
__GNUC__ < 3
|
|
typedef ss_typename_type_k mfcstl_ns_qual_std(iterator_traits)<I2> traits_t;
|
|
|
|
clear_and_assign_(first, last, traits_t::iterator_category());
|
|
# elif defined(STLSOFT_COMPILER_IS_MWERKS)
|
|
clear_and_assign_(first, last, stlsoft_iterator_query_category_ptr(I2, first));
|
|
# else /* ? compiler */
|
|
clear_and_assign_(first, last, stlsoft_iterator_query_category(I2, first));
|
|
# endif /* compiler */
|
|
}
|
|
|
|
protected:
|
|
#if ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
|
|
_MSC_VER > 1200)
|
|
template <ss_typename_param_k I2>
|
|
# if defined(STLSOFT_COMPILER_IS_MWERKS)
|
|
// There seems to be a bug in CodeWarrior that makes it have a cow with iterator tags by value, so we just use a ptr
|
|
static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag) const*)
|
|
# else /* ? compiler */
|
|
static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag))
|
|
# endif /* compiler */
|
|
{
|
|
return true; // Can't test them, as that eats their state, so have to assume yes
|
|
}
|
|
#endif /* compiler */
|
|
|
|
template< ss_typename_param_k I2
|
|
, ss_typename_param_k T2
|
|
>
|
|
static ms_bool_t is_valid_source_range_(I2 first, I2 last, T2)
|
|
{
|
|
return true; // FI and BI don't have <=, so cannot test, so have to assume yes
|
|
}
|
|
|
|
#if ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
|
|
_MSC_VER > 1200)
|
|
template <ss_typename_param_k I2>
|
|
# if defined(STLSOFT_COMPILER_IS_MWERKS)
|
|
// There seems to be a bug in CodeWarrior that makes it have a cow with iterator tags by value, so we just use a ptr
|
|
static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(random_access_iterator_tag) const*)
|
|
# else /* ? compiler */
|
|
static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(random_access_iterator_tag))
|
|
# endif /* compiler */
|
|
{
|
|
return first <= last;
|
|
}
|
|
#endif /* compiler */
|
|
|
|
template <ss_typename_param_k I2>
|
|
static ms_bool_t is_valid_source_range_(I2 first, I2 last)
|
|
{
|
|
# if defined(STLSOFT_COMPILER_IS_GCC) && \
|
|
__GNUC__ < 3
|
|
typedef ss_typename_type_k mfcstl_ns_qual_std(iterator_traits)<I2> traits_t;
|
|
|
|
return is_valid_source_range_(first, last, traits_t::iterator_category());
|
|
# elif defined(STLSOFT_COMPILER_IS_MWERKS)
|
|
return is_valid_source_range_(first, last, stlsoft_iterator_query_category_ptr(I2, first));
|
|
# elif defined(STLSOFT_COMPILER_IS_DMC)
|
|
return true;
|
|
# else /* ? compiler */
|
|
return is_valid_source_range_(first, last, stlsoft_iterator_query_category(I2, first));
|
|
# endif /* compiler */
|
|
}
|
|
|
|
#if 0
|
|
template <ss_typename_param_k T2>
|
|
static ms_bool_t is_valid_source_range_(T2* first, T2* last)
|
|
{
|
|
return first <= last;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
#if 0
|
|
template <ss_typename_param_k T2>
|
|
static ms_bool_t is_valid_source_range_(T2 const* first, T2 const* last)
|
|
{
|
|
return first <= last;
|
|
}
|
|
#endif /* 0 */
|
|
/// @}
|
|
|
|
/// \name Not to be implemented
|
|
/// @{
|
|
private:
|
|
CArray_adaptor_base(class_type const& rhs);
|
|
class_type& operator =(class_type const& rhs);
|
|
/// @}
|
|
};
|
|
|
|
#ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
/** \brief Adaptor class, representing a Class Adaptor over the CArray family
|
|
* of MFC containers
|
|
*
|
|
* \ingroup group__library__collections
|
|
*
|
|
* The adaptor, being a facade, is
|
|
*
|
|
* It is used as follows:
|
|
*
|
|
\code
|
|
mfcstl::CArray_cadaptor<CStringArray> ar;
|
|
|
|
// As an MFC CStringArray:
|
|
ar.Add("String 1");
|
|
ar.InsertAt(0, "String 0");
|
|
|
|
// As an STL container
|
|
ar.push_back("String 2");
|
|
std::list<CString> l;
|
|
l.push_back("String 3");
|
|
l.push_back("String 4");
|
|
ar.insert(ar.begin() + 2, l.begin(), l.end());
|
|
std::sort(ar.begin(), ar.end());
|
|
\endcode
|
|
*
|
|
* \param A The array class, e.g. CObArray, CArray<long>, etc.
|
|
*
|
|
* \note The elements in an adapted array are moved, during insertion / erasure, rather than copied. This
|
|
* means that if the elements in the container maintain pointers to their elements, or their peers, then
|
|
* they are not suitable for use.
|
|
*/
|
|
#endif /* STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k T = CArray_traits<A>
|
|
>
|
|
class CArray_cadaptor
|
|
: public A
|
|
, public CArray_adaptor_base<A, CArray_cadaptor<A, T>, T>
|
|
{
|
|
/// \name Member Types
|
|
/// @{
|
|
private:
|
|
typedef CArray_adaptor_base<A, CArray_cadaptor<A, T>, T> parent_class_type;
|
|
public:
|
|
/// The type of the underlying MFC array
|
|
typedef ss_typename_type_k parent_class_type::array_type array_type;
|
|
/// The value type
|
|
typedef ss_typename_type_k parent_class_type::value_type value_type;
|
|
/// The allocator type
|
|
typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
|
|
/// The mutating (non-const) reference type
|
|
typedef ss_typename_type_k parent_class_type::reference reference;
|
|
/// The non-mutating (const) reference type
|
|
typedef ss_typename_type_k parent_class_type::const_reference const_reference;
|
|
/// The mutating (non-const) pointer type
|
|
typedef ss_typename_type_k parent_class_type::pointer pointer;
|
|
/// The non-mutating (const) pointer type
|
|
typedef ss_typename_type_k parent_class_type::const_pointer const_pointer;
|
|
/// The mutating (non-const) iterator type
|
|
typedef ss_typename_type_k parent_class_type::iterator iterator;
|
|
/// The non-mutating (const) iterator type
|
|
typedef ss_typename_type_k parent_class_type::const_iterator const_iterator;
|
|
/// The size type
|
|
typedef ss_typename_type_k parent_class_type::size_type size_type;
|
|
/// The difference type
|
|
typedef ss_typename_type_k parent_class_type::difference_type difference_type;
|
|
/// The instantiation of the current type
|
|
typedef CArray_cadaptor<A, T> class_type;
|
|
/// @}
|
|
|
|
/// \name Identity
|
|
/// @{
|
|
private:
|
|
friend class CArray_adaptor_base<A, CArray_cadaptor<A, T>, T>;
|
|
|
|
array_type &get_actual_array()
|
|
{
|
|
return *this;
|
|
}
|
|
array_type const &get_actual_array() const
|
|
{
|
|
return *this;
|
|
}
|
|
/// @}
|
|
|
|
/// \name Construction
|
|
/// @{
|
|
public:
|
|
/// Default constructs an instance
|
|
///
|
|
/// \note It takes a parameter of type <code>allocator_type</code>, but
|
|
/// ignores it. This facilitates adaptation by the standard adaptor
|
|
/// <code>std::stack</code>.
|
|
ss_explicit_k CArray_cadaptor(allocator_type const& = allocator_type())
|
|
{
|
|
parent_class_type::resize(0); // DMC++ needs it to be qualified. Go figure!
|
|
}
|
|
/// Constructs an instance with the given number of elements
|
|
///
|
|
/// \param n The number of elements
|
|
explicit CArray_cadaptor(size_type n)
|
|
{
|
|
parent_class_type::resize(n);
|
|
}
|
|
/// Constructs an instance with the given number of elements
|
|
///
|
|
/// \param n The number of elements
|
|
/// \param value The value of each element
|
|
CArray_cadaptor(size_type n, value_type const& value)
|
|
{
|
|
parent_class_type::assign(n, value);
|
|
}
|
|
/// Copy constructor
|
|
CArray_cadaptor(class_type const& rhs)
|
|
{
|
|
parent_class_type::assign(rhs.begin(), rhs.end());
|
|
}
|
|
/// Copy constructs an instance from the given underlying array
|
|
CArray_cadaptor(array_type const& rhs)
|
|
{
|
|
parent_class_type::assign(rhs.GetData(), rhs.GetData() + rhs.GetSize());
|
|
}
|
|
/// Constructs an instance from the given range
|
|
template <ss_typename_param_k I2>
|
|
CArray_cadaptor(I2 first, I2 last)
|
|
{
|
|
// Precondition checks
|
|
MFCSTL_ASSERT(parent_class_type::is_valid_source_range_(first, last));
|
|
|
|
parent_class_type::assign(first, last);
|
|
}
|
|
~CArray_cadaptor() stlsoft_throw_0()
|
|
{
|
|
STLSOFT_STATIC_ASSERT(sizeof(A) == sizeof(ss_typename_type_k T::array_type));
|
|
}
|
|
/// @}
|
|
|
|
/// \name Assignment
|
|
/// @{
|
|
public:
|
|
class_type& operator =(class_type const& rhs)
|
|
{
|
|
#ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
|
|
class_type t(rhs);
|
|
t.swap(*this);
|
|
#else /* ? MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
parent_class_type::assign(rhs.begin(), rhs.end());
|
|
#endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
|
|
|
|
return *this;
|
|
}
|
|
/// @}
|
|
|
|
/// \name Element Access
|
|
/// @{
|
|
public:
|
|
#if defined(STLSOFT_COMPILER_IS_DMC)
|
|
reference operator [](size_type index)
|
|
{
|
|
return parent_class_type::operator [](index);
|
|
}
|
|
const_reference operator [](size_type index) const
|
|
{
|
|
return parent_class_type::operator [](index);
|
|
}
|
|
#else /* ? compiler */
|
|
using parent_class_type::operator [];
|
|
#endif /* compiler */
|
|
/// @}
|
|
};
|
|
|
|
|
|
#ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
|
|
/** \brief Adaptor class, representing an Instance Adaptor over the CArray
|
|
* family of MFC containers
|
|
*
|
|
* \ingroup group__library__collections
|
|
*
|
|
* It is used as follows:
|
|
*
|
|
\code
|
|
CStringArray ar;
|
|
mfcstl::CArray_iadaptor<CStringArray> arp(ar);
|
|
|
|
// As an MFC CStringArray:
|
|
ar.Add("String 1");
|
|
ar.InsertAt(0, "String 0");
|
|
|
|
// As an STL container
|
|
arp.push_back("String 2");
|
|
std::list<CString> l;
|
|
l.push_back("String 3");
|
|
l.push_back("String 4");
|
|
arp.insert(arp.begin() + 2, l.begin(), l.end());
|
|
std::sort(arp.begin(), arp.end());
|
|
\endcode
|
|
*
|
|
* \param A The array class, e.g. CObArray, CArray<long>, etc.
|
|
*
|
|
* \note The elements in an adapted array are moved, during insertion / erasure, rather than copied. This
|
|
* means that if the elements in the container maintain pointers to their elements, or their peers, then
|
|
* they are not suitable for use.
|
|
*/
|
|
#endif /* STLSOFT_DOCUMENTATION_SKIP_SECTION */
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k T = CArray_traits<A>
|
|
>
|
|
class CArray_iadaptor
|
|
: public CArray_adaptor_base<A, CArray_iadaptor<A, T>, T>
|
|
{
|
|
/// \name Member Types
|
|
/// @{
|
|
private:
|
|
typedef CArray_adaptor_base<A, CArray_iadaptor<A, T>, T> parent_class_type;
|
|
public:
|
|
/// The type of the underlying MFC array
|
|
typedef ss_typename_type_k parent_class_type::array_type array_type;
|
|
/// The value type
|
|
typedef ss_typename_type_k parent_class_type::value_type value_type;
|
|
/// The allocator type
|
|
typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
|
|
/// The mutating (non-const) reference type
|
|
typedef ss_typename_type_k parent_class_type::reference reference;
|
|
/// The non-mutating (const) reference type
|
|
typedef ss_typename_type_k parent_class_type::const_reference const_reference;
|
|
/// The mutating (non-const) pointer type
|
|
typedef ss_typename_type_k parent_class_type::pointer pointer;
|
|
/// The non-mutating (const) pointer type
|
|
typedef ss_typename_type_k parent_class_type::const_pointer const_pointer;
|
|
/// The mutating (non-const) iterator type
|
|
typedef ss_typename_type_k parent_class_type::iterator iterator;
|
|
/// The non-mutating (const) iterator type
|
|
typedef ss_typename_type_k parent_class_type::const_iterator const_iterator;
|
|
/// The size type
|
|
typedef ss_typename_type_k parent_class_type::size_type size_type;
|
|
/// The difference type
|
|
typedef ss_typename_type_k parent_class_type::difference_type difference_type;
|
|
/// The instantiation of the current type
|
|
typedef CArray_iadaptor<A, T> class_type;
|
|
/// @}
|
|
|
|
/// \name Identity
|
|
/// @{
|
|
private:
|
|
friend class CArray_adaptor_base<A, CArray_iadaptor<A, T>, T>;
|
|
|
|
array_type &get_actual_array()
|
|
{
|
|
MFCSTL_ASSERT(NULL != m_pArray);
|
|
return *m_pArray;
|
|
}
|
|
array_type const &get_actual_array() const
|
|
{
|
|
MFCSTL_ASSERT(NULL != m_pArray);
|
|
return *m_pArray;
|
|
}
|
|
/// @}
|
|
|
|
/// \name Construction
|
|
/// @{
|
|
public:
|
|
template <ss_typename_param_k A2>
|
|
CArray_iadaptor(A2 &array)
|
|
: m_pArray(&array)
|
|
{
|
|
STLSOFT_STATIC_ASSERT(sizeof(array_type) == sizeof(A2));
|
|
#ifdef STLSOFT_META_HAS_IS_SAME_TYPE
|
|
STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<array_type, A2>::value));
|
|
#else /* ? STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
ASSERT(0 == ::lstrcmpA(array.GetRuntimeClass()->m_lpszClassName, array_type().GetRuntimeClass()->m_lpszClassName));
|
|
# ifdef _CPPRTTI
|
|
ASSERT(0 == ::lstrcmpA(typeid(A2).name(), typeid(array_type).name()));
|
|
# endif /* _CPPRTTI */
|
|
#endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
}
|
|
template <ss_typename_param_k A2>
|
|
CArray_iadaptor(A2 *pArray)
|
|
: m_pArray(pArray)
|
|
{
|
|
MFCSTL_MESSAGE_ASSERT("Cannot initialise a CArray_iadaptor with a NULL pointer", NULL != pArray);
|
|
|
|
STLSOFT_STATIC_ASSERT(sizeof(array_type) == sizeof(A2));
|
|
#ifdef STLSOFT_META_HAS_IS_SAME_TYPE
|
|
STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<array_type, A2>::value));
|
|
#else /* ? STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
ASSERT(0 == ::lstrcmpA(pArray->GetRuntimeClass()->m_lpszClassName, array_type().GetRuntimeClass()->m_lpszClassName));
|
|
# ifdef _CPPRTTI
|
|
ASSERT(0 == ::lstrcmpA(typeid(A2).name(), typeid(array_type).name()));
|
|
# endif /* _CPPRTTI */
|
|
#endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
|
|
}
|
|
/// @}
|
|
|
|
/// \name Members
|
|
/// @{
|
|
private:
|
|
array_type *m_pArray;
|
|
/// @}
|
|
|
|
/// \name Not to be implemented
|
|
/// @{
|
|
private:
|
|
CArray_iadaptor(class_type const& rhs); // Only possible semantics for copy-ctor are share underlying array
|
|
class_type& operator =(class_type const& rhs); // Could either repoint, or could do deep copy.
|
|
/// @}
|
|
};
|
|
|
|
/* /////////////////////////////////////////////////////////////////////////
|
|
* Comparison
|
|
*/
|
|
|
|
template< ss_typename_param_k A1
|
|
, ss_typename_param_k A2
|
|
, ss_typename_param_k I1
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T1
|
|
, ss_typename_param_k T2
|
|
>
|
|
inline ms_bool_t operator ==(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
|
|
{
|
|
return lhs.equal(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A1
|
|
, ss_typename_param_k A2
|
|
, ss_typename_param_k I1
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T1
|
|
, ss_typename_param_k T2
|
|
>
|
|
inline ms_bool_t operator !=(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
|
|
{
|
|
return !lhs.equal(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A1
|
|
, ss_typename_param_k A2
|
|
, ss_typename_param_k I1
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T1
|
|
, ss_typename_param_k T2
|
|
>
|
|
inline ms_bool_t operator <(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
|
|
{
|
|
return lhs.less_than(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A1
|
|
, ss_typename_param_k A2
|
|
, ss_typename_param_k I1
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T1
|
|
, ss_typename_param_k T2
|
|
>
|
|
inline ms_bool_t operator <=(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
|
|
{
|
|
return !lhs.greater_than(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A1
|
|
, ss_typename_param_k A2
|
|
, ss_typename_param_k I1
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T1
|
|
, ss_typename_param_k T2
|
|
>
|
|
inline ms_bool_t operator >(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
|
|
{
|
|
return lhs.greater_than(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A1
|
|
, ss_typename_param_k A2
|
|
, ss_typename_param_k I1
|
|
, ss_typename_param_k I2
|
|
, ss_typename_param_k T1
|
|
, ss_typename_param_k T2
|
|
>
|
|
inline ms_bool_t operator >=(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
|
|
{
|
|
return !lhs.less_than(rhs);
|
|
}
|
|
|
|
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator ==(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
|
|
{
|
|
return lhs.equal(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator !=(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
|
|
{
|
|
return !lhs.equal(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator <(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
|
|
{
|
|
return lhs.less_than(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator <=(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
|
|
{
|
|
return !lhs.greater_than(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator >(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
|
|
{
|
|
return lhs.greater_than(rhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator >=(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
|
|
{
|
|
return !lhs.less_than(rhs);
|
|
}
|
|
|
|
|
|
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator ==(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
|
|
{
|
|
return rhs.equal(lhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator !=(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
|
|
{
|
|
return !rhs.equal(lhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator <(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
|
|
{
|
|
return !(rhs.greater_than(lhs) || rhs == lhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator <=(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
|
|
{
|
|
return !rhs.less_than(lhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator >(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
|
|
{
|
|
return !(rhs.less_than(lhs) || rhs == lhs);
|
|
}
|
|
|
|
template< ss_typename_param_k A
|
|
, ss_typename_param_k I
|
|
, ss_typename_param_k T
|
|
>
|
|
inline ms_bool_t operator >=(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
|
|
{
|
|
return !rhs.greater_than(lhs);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Unit-testing
|
|
|
|
#ifdef STLSOFT_UNITTEST
|
|
# include "./unittest/carray_adaptors_unittest_.h"
|
|
#endif /* STLSOFT_UNITTEST */
|
|
|
|
/* ////////////////////////////////////////////////////////////////////// */
|
|
|
|
#ifndef _MFCSTL_NO_NAMESPACE
|
|
# if defined(_STLSOFT_NO_NAMESPACE) || \
|
|
defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
|
|
} // namespace mfcstl
|
|
# else
|
|
} // namespace mfcstl_project
|
|
} // namespace stlsoft
|
|
# endif /* _STLSOFT_NO_NAMESPACE */
|
|
#endif /* !_MFCSTL_NO_NAMESPACE */
|
|
|
|
/* ////////////////////////////////////////////////////////////////////// */
|
|
|
|
#endif /* !MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS */
|
|
|
|
/* ///////////////////////////// end of file //////////////////////////// */
|