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

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: mfcstl/collections/carray_adaptors.hpp (derived from mfcstl_array_adaptor.h)
  3. *
  4. * Purpose: Contains the definition of the CArray_cadaptor and CArray_iadaptor
  5. * class templates.
  6. *
  7. * Created: 1st December 2002
  8. * Updated: 10th August 2009
  9. *
  10. * Thanks to: Nevin Liber and Scott Meyers for kicking my lazy behind, and
  11. * requiring that I implement the full complement of standard
  12. * comparison operations.
  13. *
  14. * Home: http://stlsoft.org/
  15. *
  16. * Copyright (c) 2002-2009, Matthew Wilson and Synesis Software
  17. * All rights reserved.
  18. *
  19. * Redistribution and use in source and binary forms, with or without
  20. * modification, are permitted provided that the following conditions are met:
  21. *
  22. * - Redistributions of source code must retain the above copyright notice, this
  23. * list of conditions and the following disclaimer.
  24. * - Redistributions in binary form must reproduce the above copyright notice,
  25. * this list of conditions and the following disclaimer in the documentation
  26. * and/or other materials provided with the distribution.
  27. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  28. * any contributors may be used to endorse or promote products derived from
  29. * this software without specific prior written permission.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  32. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  35. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  36. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  37. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  38. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  39. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41. * POSSIBILITY OF SUCH DAMAGE.
  42. *
  43. * ////////////////////////////////////////////////////////////////////// */
  44. /** \file mfcstl/collections/carray_adaptors.hpp
  45. *
  46. * \brief [C++ only] Definition of the mfcstl::CArray_cadaptor and
  47. * mfcstl::CArray_iadaptor traits class templates
  48. * (\ref group__library__collections "Collections" Library).
  49. */
  50. #ifndef MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS
  51. #define MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS
  52. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  53. # define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_MAJOR 4
  54. # define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_MINOR 2
  55. # define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_REVISION 1
  56. # define MFCSTL_VER_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS_EDIT 82
  57. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  58. /* /////////////////////////////////////////////////////////////////////////
  59. * Compatibility
  60. */
  61. /*
  62. [Incompatibilies-start]
  63. STLSOFT_COMPILER_IS_MSVC: _MSC_VER==1300
  64. [Incompatibilies-end]
  65. */
  66. /* /////////////////////////////////////////////////////////////////////////
  67. * Includes
  68. */
  69. #ifndef MFCSTL_INCL_MFCSTL_HPP_MFCSTL
  70. # include <mfcstl/mfcstl.hpp>
  71. #endif /* !MFCSTL_INCL_MFCSTL_HPP_MFCSTL */
  72. #ifndef MFCSTL_INCL_MFCSTL_MEMORY_HPP_AFX_ALLOCATOR
  73. # include <mfcstl/memory/afx_allocator.hpp>
  74. #endif /* !MFCSTL_INCL_MFCSTL_MEMORY_HPP_AFX_ALLOCATOR */
  75. #ifndef MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_SWAP
  76. # include <mfcstl/collections/carray_swap.hpp>
  77. #endif /* !MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_SWAP */
  78. #ifndef MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_TRAITS
  79. # include <mfcstl/collections/carray_traits.hpp>
  80. #endif /* !MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_TRAITS */
  81. #ifndef MFCSTL_INCL_MFCSTL_UTIL_HPP_MEMORY_EXCEPTION_TRANSLATION_POLICIES
  82. # include <mfcstl/util/memory_exception_translation_policies.hpp>
  83. #endif /* !MFCSTL_INCL_MFCSTL_UTIL_HPP_MEMORY_EXCEPTION_TRANSLATION_POLICIES */
  84. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_GENERATORS
  85. # include <stlsoft/util/std/iterator_generators.hpp>
  86. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_GENERATORS */
  87. #ifndef STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES
  88. # include <stlsoft/meta/capabilities.hpp>
  89. #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES */
  90. #ifdef STLSOFT_META_HAS_IS_SAME_TYPE
  91. # ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE
  92. # include <stlsoft/meta/is_same_type.hpp>
  93. # endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE */
  94. #endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
  95. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  96. # include <stlsoft/collections/util/collections.hpp>
  97. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  98. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  99. # include <stlsoft/util/std/iterator_helper.hpp>
  100. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  101. #if defined(STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT) && \
  102. !defined(MFCSTL_NO_INCLUDE_AFXTEMPL_BY_DEFAULT)
  103. # include <afxtempl.h>
  104. #endif /* STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT && !MFCSTL_NO_INCLUDE_AFXTEMPL_BY_DEFAULT */
  105. #ifndef STLSOFT_INCL_ALGORITHM
  106. # define STLSOFT_INCL_ALGORITHM
  107. # include <algorithm>
  108. #endif /* !STLSOFT_INCL_ALGORITHM */
  109. #ifdef STLSOFT_UNITTEST
  110. # include <afxtempl.h>
  111. # include <stlsoft/string/simple_string.hpp>
  112. #endif /* STLSOFT_UNITTEST */
  113. /* /////////////////////////////////////////////////////////////////////////
  114. * Namespace
  115. */
  116. #ifndef _MFCSTL_NO_NAMESPACE
  117. # if defined(_STLSOFT_NO_NAMESPACE) || \
  118. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  119. /* There is no stlsoft namespace, so must define ::mfcstl */
  120. namespace mfcstl
  121. {
  122. # else
  123. /* Define stlsoft::mfcstl_project */
  124. namespace stlsoft
  125. {
  126. namespace mfcstl_project
  127. {
  128. # endif /* _STLSOFT_NO_NAMESPACE */
  129. #endif /* !_MFCSTL_NO_NAMESPACE */
  130. /* /////////////////////////////////////////////////////////////////////////
  131. * Classes
  132. */
  133. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  134. // Forward declarations
  135. template< ss_typename_param_k A
  136. , ss_typename_param_k I
  137. , ss_typename_param_k T
  138. >
  139. class CArray_adaptor_base;
  140. template< ss_typename_param_k A
  141. , ss_typename_param_k T
  142. >
  143. class CArray_cadaptor;
  144. template< ss_typename_param_k A
  145. , ss_typename_param_k T
  146. >
  147. class CArray_iadaptor;
  148. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  149. /** \brief Adaptor class, providing implementation for CArray_cadaptor and
  150. * CArray_iadaptor classes
  151. *
  152. * \ingroup group__library__collections
  153. *
  154. * \param A The array class, e.g. CObArray, CArray<long>, etc.
  155. * \param I The interface specialisation, e.g. CArray_cadaptor<CObArray>, CArray_iadaptor<CArray<long> >, etc.
  156. * \param T The traits class, e.g. CArray_traits<CObArray>
  157. *
  158. * \note The elements in an adapted array are moved, during insertion / erasure, rather than copied. This
  159. * means that if the elements in the container maintain pointers to their elements, or their peers, then
  160. * they are not suitable for use.
  161. */
  162. template< ss_typename_param_k A
  163. , ss_typename_param_k I
  164. , ss_typename_param_k T
  165. >
  166. class CArray_adaptor_base
  167. : public stlsoft_ns_qual(stl_collection_tag)
  168. {
  169. /// \name Member Types
  170. /// @{
  171. public:
  172. /// The type of the underlying MFC array
  173. typedef A array_type;
  174. private:
  175. typedef I interface_class_type;
  176. typedef T array_traits_type;
  177. #if defined(MFCSTL_CARRAY_ADAPTORS_USE_BAD_ALLOC_POLICY)
  178. typedef bad_alloc_throwing_policy exception_translation_policy_type;
  179. #else /* ? MFCSTL_CARRAY_ADAPTORS_USE_BAD_ALLOC_POLICY */
  180. typedef CMemoryException_throwing_policy exception_translation_policy_type;
  181. #endif /* MFCSTL_CARRAY_ADAPTORS_USE_BAD_ALLOC_POLICY */
  182. public:
  183. /// The value type
  184. ///
  185. /// \note If the compiler report "use of undefined type" when you're using the adaptor class(es)
  186. /// with CArray<>, ensure that you've included <b>afxtempl</b> <i>before</i> you include this file.
  187. typedef ss_typename_type_k array_traits_type::value_type value_type;
  188. /// The allocator type
  189. typedef afx_allocator<value_type> allocator_type;
  190. /// The mutating (non-const) reference type
  191. typedef ss_typename_type_k allocator_type::reference reference;
  192. /// The non-mutating (const) reference type
  193. typedef ss_typename_type_k allocator_type::const_reference const_reference;
  194. /// The mutating (non-const) pointer type
  195. typedef ss_typename_type_k allocator_type::pointer pointer;
  196. /// The non-mutating (const) pointer type
  197. typedef ss_typename_type_k allocator_type::const_pointer const_pointer;
  198. /// The mutating (non-const) iterator type
  199. typedef
  200. # if !defined(STLSOFT_COMPILER_IS_BORLAND)
  201. ss_typename_type_k
  202. # endif /* compiler */
  203. pointer_iterator < value_type
  204. , pointer
  205. , reference
  206. >::type iterator;
  207. /// The non-mutating (const) iterator type
  208. typedef
  209. # if !defined(STLSOFT_COMPILER_IS_BORLAND)
  210. ss_typename_type_k
  211. # endif /* compiler */
  212. pointer_iterator < value_type const
  213. , const_pointer
  214. , const_reference
  215. >::type const_iterator;
  216. /// The size type
  217. typedef ms_size_t size_type;
  218. /// The difference type
  219. typedef ms_ptrdiff_t difference_type;
  220. /// The instantiation of the current type
  221. typedef CArray_adaptor_base<A, I, T> class_type;
  222. #ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
  223. /// The mutating (non-const) reverse iterator type
  224. typedef ss_typename_type_k reverse_iterator_generator < iterator
  225. , value_type
  226. , reference
  227. , pointer
  228. , difference_type
  229. >::type reverse_iterator;
  230. /// The non-mutating (const) reverse iterator type
  231. typedef ss_typename_type_k const_reverse_iterator_generator < const_iterator
  232. , value_type
  233. , const_reference
  234. , const_pointer
  235. , difference_type
  236. >::type const_reverse_iterator;
  237. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  238. /// @}
  239. /// \name Member Constants
  240. /// @{
  241. protected:
  242. enum { growthGranularity = 16 };
  243. static size_type calc_increment_(size_type n)
  244. {
  245. size_type numBlocks = n / growthGranularity;
  246. return (1 + numBlocks) * growthGranularity;
  247. }
  248. /// @}
  249. /// \name Underlying Container Access
  250. /// @{
  251. public:
  252. /// \brief Returns a mutating (non-const) reference to the underlying array
  253. array_type &get_CArray()
  254. {
  255. return static_cast<interface_class_type*>(this)->get_actual_array();
  256. }
  257. /// \brief Returns a non-mutating (const) reference to the underlying array
  258. array_type const &get_CArray() const
  259. {
  260. return static_cast<interface_class_type const*>(this)->get_actual_array();
  261. }
  262. /// @}
  263. /// \name Construction
  264. /// @{
  265. protected:
  266. /// \brief Default constructor.
  267. ///
  268. /// This is protected, because CArray_adaptor_base serves as an abstract base
  269. /// for CArray_cadaptor and CArray_iadaptor
  270. CArray_adaptor_base()
  271. {}
  272. /// \brief Destructor
  273. ~CArray_adaptor_base() stlsoft_throw_0()
  274. {}
  275. public:
  276. /// Returns a copy of the allocator used by the container
  277. allocator_type get_allocator() const
  278. {
  279. return allocator_type();
  280. }
  281. #if defined(_DEBUG) || \
  282. defined(MFCSTL_ARRAY_ADAPTORS_ALLOW_CAPACITY_PEEK)
  283. public:
  284. #else /* ? _DEBUG */
  285. protected:
  286. #endif /* _DEBUG */
  287. size_type grow_increment() const
  288. {
  289. class GrowByGetter
  290. : public array_type
  291. {
  292. public:
  293. size_type grow_increment() const
  294. {
  295. return m_nGrowBy;
  296. }
  297. };
  298. return static_cast<GrowByGetter const&>(get_CArray()).grow_increment();
  299. }
  300. size_type capacity() const
  301. {
  302. class CapacityGetter
  303. : public array_type
  304. {
  305. public:
  306. size_type capacity() const
  307. {
  308. return m_nMaxSize;
  309. }
  310. };
  311. return static_cast<CapacityGetter const&>(get_CArray()).capacity();
  312. }
  313. /// @}
  314. /// \name Assignment
  315. /// @{
  316. public:
  317. /// \brief Assigns a number of copies of the given value to the array, erasing all prior content
  318. ///
  319. /// \param n The number of values to assign
  320. /// \param value The value of which n copies are to be assigned
  321. ///
  322. /// \note Exception-safety is <b>strong</b> if MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT is defined, otherwise <b>weak</b>.
  323. ///
  324. /// \note The elements are default constructed, and then copy-assigned
  325. void assign(size_type n, value_type const& value)
  326. {
  327. #ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
  328. try
  329. {
  330. array_type ar;
  331. ar.SetSize(0, calc_increment_(n));
  332. if(n > 0) // Can't pass 0 to InsertAt()
  333. {
  334. ar.InsertAt(0, value, static_cast<int>(n));
  335. }
  336. CArray_swap(this->get_CArray(), ar);
  337. }
  338. catch(CMemoryException *px)
  339. {
  340. exception_translation_policy_type::handle(px);
  341. }
  342. catch(mfcstl_ns_qual_std(bad_alloc) &x)
  343. {
  344. exception_translation_policy_type::handle(x);
  345. }
  346. #else /* ? MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  347. // if( empty() &&
  348. // 0 != n)
  349. // {
  350. // resize(1);
  351. // }
  352. resize(n);
  353. mfcstl_ns_qual_std(fill_n)(begin(), n, value);
  354. #endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  355. // Postcondition
  356. MFCSTL_ASSERT(size() == n);
  357. }
  358. /// \brief Assigns each element in the range [first, last) to the array, erasing all prior content
  359. ///
  360. /// \param first The first element in the range
  361. /// \param last The (one past the) last element in the range
  362. ///
  363. /// \note Exception-safety is <b>strong</b> if MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT is defined, otherwise <b>weak</b>.
  364. ///
  365. /// \note The elements are default constructed, and then copy-assigned
  366. template <ss_typename_param_k I2>
  367. void assign(I2 first, I2 last)
  368. {
  369. // Precondition checks
  370. MFCSTL_ASSERT(is_valid_source_range_(first, last));
  371. #ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
  372. if(empty())
  373. {
  374. // If "this" is empty, then we can call clear_and_assign_() to instantiate it
  375. // and just catch any thrown exception and call clear() to ensure strong
  376. // exception safety.
  377. try
  378. {
  379. clear_and_assign_(first, last);
  380. }
  381. catch(...)
  382. {
  383. clear();
  384. throw;
  385. }
  386. }
  387. else
  388. {
  389. // Otherwise we need to do construct-and-swap idiom, indirectly, via
  390. // an instance of the underlying array type and the CArray_iadaptor.
  391. array_type ar;
  392. CArray_iadaptor<array_type
  393. , array_traits_type
  394. > arp(ar);
  395. arp.assign(first, last);
  396. CArray_swap(this->get_CArray(), ar);
  397. }
  398. #else /* ? MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  399. clear_and_assign_(first, last);
  400. #endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  401. }
  402. /// @}
  403. /// \name Size and Capacity
  404. /// @{
  405. public:
  406. /// \brief The number of items in the array
  407. size_type size() const
  408. {
  409. return static_cast<size_type>(get_CArray().GetSize());
  410. }
  411. /// \brief The maximum number of items that can be stored in the array
  412. size_type max_size() const
  413. {
  414. return get_allocator().max_size();
  415. }
  416. /// \brief Indicates whether the array is empty
  417. ms_bool_t empty() const
  418. {
  419. return 0 == size();
  420. }
  421. /// \brief Adjusts the number of elements in the array
  422. ///
  423. /// \param n The number of elements that the array will contain after resizing
  424. ///
  425. /// \note Exception-safety is <b>strong</b> if the default constructor of the value type
  426. /// cannot throw exceptions, otherwise it is weak
  427. void resize(size_type n)
  428. {
  429. try
  430. {
  431. get_CArray().SetSize(n, calc_increment_(n));
  432. }
  433. catch(CMemoryException *px)
  434. {
  435. exception_translation_policy_type::handle(px);
  436. }
  437. catch(mfcstl_ns_qual_std(bad_alloc) &x)
  438. {
  439. exception_translation_policy_type::handle(x);
  440. }
  441. // Postcondition
  442. MFCSTL_ASSERT(size() == n);
  443. }
  444. /// \brief Adjusts the number of elements in the array
  445. ///
  446. /// \param n The number of elements that the array will contain after resizing
  447. /// \param value The value of any additional elements created during resizing
  448. ///
  449. /// \note Due to the limitations of the underlying CArray-family containers, the
  450. /// additional elements are default constructed and then subjected to
  451. /// copy-assignment.
  452. ///
  453. /// \note Exception-safety is <b>weak</b>, but the size is maintained in the case
  454. /// where an exception is thrown by the copy assignment of any new elements.
  455. void resize(size_type n, value_type value)
  456. {
  457. const size_type oldSize = size();
  458. resize(n);
  459. if(oldSize < n)
  460. {
  461. try
  462. {
  463. mfcstl_ns_qual_std(fill_n)(begin() + oldSize, n - oldSize, value);
  464. }
  465. catch(...)
  466. {
  467. resize(oldSize);
  468. throw;
  469. }
  470. }
  471. }
  472. /// @}
  473. /// \name Element access
  474. /// @{
  475. public:
  476. /// \brief Returns a mutable (non-const) reference to the element at the given index
  477. ///
  478. /// \param n The requested index. Must be less than size()
  479. ///
  480. /// \note The implementation will assert in debug mode if the index is out of range
  481. reference operator [](size_type n)
  482. {
  483. MFCSTL_MESSAGE_ASSERT("index out of bounds", n < size());
  484. return get_CArray()[n];
  485. }
  486. /// \brief Returns a non-mutable (const) reference to the element at the given index
  487. ///
  488. /// \param n The requested index. Must be less than size()
  489. ///
  490. /// \note The implementation will assert in debug mode if the index is out of range
  491. const_reference operator [](size_type n) const
  492. {
  493. MFCSTL_MESSAGE_ASSERT("index out of bounds", n < size());
  494. return get_CArray()[n];
  495. }
  496. /// \brief Returns a mutable (non-const) reference to the element at the given index
  497. ///
  498. /// \param n The requested index. If the index is not less than size() an
  499. /// instance of std::out_of_range will be thrown
  500. reference at(size_type n)
  501. {
  502. if(n >= size())
  503. {
  504. STLSOFT_THROW_X(mfcstl_ns_qual_std(out_of_range)("Invalid index specified"));
  505. }
  506. return (*this)[n];
  507. }
  508. /// \brief Returns a non-mutable (const) reference to the element at the given index
  509. ///
  510. /// \param n The requested index. If the index is not less than size() an
  511. /// instance of std::out_of_range will be thrown
  512. const_reference at(size_type n) const
  513. {
  514. if(n >= size())
  515. {
  516. STLSOFT_THROW_X(mfcstl_ns_qual_std(out_of_range)("Invalid index specified"));
  517. }
  518. return (*this)[n];
  519. }
  520. /// \brief Returns a mutable (non-const) reference to the first element in the array
  521. reference front()
  522. {
  523. MFCSTL_MESSAGE_ASSERT("front() called on an empty instance", !empty());
  524. return (*this)[0];
  525. }
  526. /// \brief Returns a mutable (non-const) reference to the last element in the array
  527. reference back()
  528. {
  529. MFCSTL_MESSAGE_ASSERT("back() called on an empty instance", !empty());
  530. return (*this)[size() - 1];
  531. }
  532. /// \brief Returns a non-mutable (const) reference to the first element in the array
  533. const_reference front() const
  534. {
  535. MFCSTL_MESSAGE_ASSERT("front() called on an empty instance", !empty());
  536. return (*this)[0];
  537. }
  538. /// \brief Returns a non-mutable (const) reference to the last element in the array
  539. const_reference back() const
  540. {
  541. MFCSTL_MESSAGE_ASSERT("back() called on an empty instance", !empty());
  542. return (*this)[size() - 1];
  543. }
  544. /// @}
  545. /// \name Iteration
  546. /// @{
  547. public:
  548. /// \brief Returns a mutable (non-const) iterator representing the start of the array
  549. iterator begin()
  550. {
  551. return get_CArray().GetData();
  552. }
  553. /// \brief Returns a mutable (non-const) iterator representing the end of the array
  554. iterator end()
  555. {
  556. return begin() + size();
  557. }
  558. /// \brief Returns a non-mutable (const) iterator representing the start of the array
  559. const_iterator begin() const
  560. {
  561. // This is needed because CXxxxArray::GetData() const returns, e.g., const CObject** instead of CObject* const*
  562. value_type const *p1 = get_CArray().GetData();
  563. value_type *const p2 = const_cast<value_type *const>(p1);
  564. return p2;
  565. }
  566. /// \brief Returns a non-mutable (const) iterator representing the end of the array
  567. const_iterator end() const
  568. {
  569. return begin() + size();
  570. }
  571. #ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
  572. /// \brief Returns a mutable (non-const) reverse iterator representing the start of the array
  573. reverse_iterator rbegin()
  574. {
  575. return reverse_iterator(end());
  576. }
  577. /// \brief Returns a mutable (non-const) reverse iterator representing the end of the array
  578. reverse_iterator rend()
  579. {
  580. return reverse_iterator(begin());
  581. }
  582. /// \brief Returns a non-mutable (const) reverse iterator representing the start of the array
  583. const_reverse_iterator rbegin() const
  584. {
  585. return const_reverse_iterator(end());
  586. }
  587. /// \brief Returns a non-mutable (const) reverse iterator representing the end of the array
  588. const_reverse_iterator rend() const
  589. {
  590. return const_reverse_iterator(begin());
  591. }
  592. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  593. /// @}
  594. /// \name Comparison
  595. /// @{
  596. public:
  597. template< ss_typename_param_k A2
  598. , ss_typename_param_k I2
  599. , ss_typename_param_k T2
  600. >
  601. ms_bool_t equal(CArray_adaptor_base<A2, I2, T2> const& rhs) const
  602. {
  603. typedef CArray_adaptor_base<A2, I2, T2> rhs_t;
  604. typedef ss_typename_type_k rhs_t::value_type rhs_value_t;
  605. STLSOFT_STATIC_ASSERT(sizeof(value_type) == sizeof(ss_typename_type_k rhs_t::value_type));
  606. #ifdef STLSOFT_META_HAS_IS_SAME_TYPE
  607. STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<value_type, rhs_value_t>::value));
  608. #endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
  609. return size() == rhs.size() && stlsoft_ns_qual_std(equal)(begin(), end(), rhs.begin());
  610. }
  611. ms_bool_t equal(array_type const& rhs) const
  612. {
  613. array_type const &lhs = this->get_CArray();
  614. return lhs.GetSize() == rhs.GetSize() && stlsoft_ns_qual_std(equal)(begin(), end(), rhs.GetData());
  615. }
  616. template< ss_typename_param_k A2
  617. , ss_typename_param_k I2
  618. , ss_typename_param_k T2
  619. >
  620. ms_bool_t less_than(CArray_adaptor_base<A2, I2, T2> const& rhs) const
  621. {
  622. typedef CArray_adaptor_base<A2, I2, T2> rhs_t;
  623. typedef ss_typename_type_k rhs_t::value_type rhs_value_t;
  624. STLSOFT_STATIC_ASSERT(sizeof(value_type) == sizeof(ss_typename_type_k rhs_t::value_type));
  625. #ifdef STLSOFT_META_HAS_IS_SAME_TYPE
  626. STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<value_type, rhs_value_t>::value));
  627. #endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
  628. return stlsoft_ns_qual_std(lexicographical_compare)(begin(), end(), rhs.begin(), rhs.end());
  629. }
  630. ms_bool_t less_than(array_type const& rhs) const
  631. {
  632. return stlsoft_ns_qual_std(lexicographical_compare)(begin(), end(), rhs.GetData(), rhs.GetData() + rhs.GetSize());
  633. }
  634. template< ss_typename_param_k A2
  635. , ss_typename_param_k I2
  636. , ss_typename_param_k T2
  637. >
  638. ms_bool_t greater_than(CArray_adaptor_base<A2, I2, T2> const& rhs) const
  639. {
  640. typedef CArray_adaptor_base<A2, I2, T2> rhs_t;
  641. typedef ss_typename_type_k rhs_t::value_type rhs_value_t;
  642. STLSOFT_STATIC_ASSERT(sizeof(value_type) == sizeof(ss_typename_type_k rhs_t::value_type));
  643. #ifdef STLSOFT_META_HAS_IS_SAME_TYPE
  644. STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<value_type, rhs_value_t>::value));
  645. #endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
  646. return stlsoft_ns_qual_std(lexicographical_compare)(rhs.begin(), rhs.end(), begin(), end());
  647. }
  648. ms_bool_t greater_than(array_type const& rhs) const
  649. {
  650. return stlsoft_ns_qual_std(lexicographical_compare)(rhs.GetData(), rhs.GetData() + rhs.GetSize(), begin(), end());
  651. }
  652. /// @}
  653. /// \name Modifiers
  654. /// @{
  655. public:
  656. /// \brief Adds the given element to the end of the array
  657. ///
  658. /// \param value The value to add to the end of the array
  659. ///
  660. /// \note All iterators, pointers and references are invalidated
  661. void push_back(value_type const& value)
  662. {
  663. const size_type oldSize = size();
  664. resize(size());
  665. try
  666. {
  667. try
  668. {
  669. get_CArray().Add(value);
  670. }
  671. catch(CMemoryException *px)
  672. {
  673. exception_translation_policy_type::handle(px);
  674. }
  675. catch(mfcstl_ns_qual_std(bad_alloc) &x)
  676. {
  677. exception_translation_policy_type::handle(x);
  678. }
  679. }
  680. catch(...)
  681. {
  682. if(size() != oldSize)
  683. {
  684. MFCSTL_ASSERT(size() == oldSize + 1);
  685. resize(oldSize);
  686. }
  687. throw;
  688. }
  689. }
  690. /// \brief Removes the last element from the non-empty array
  691. ///
  692. /// \note The behaviour is undefined if the array is empty
  693. void pop_back() stlsoft_throw_0()
  694. {
  695. // Precondition checks
  696. MFCSTL_MESSAGE_ASSERT("pop_back() called on empty container", !empty());
  697. get_CArray().RemoveAt(get_CArray().GetUpperBound());
  698. }
  699. /// \brief Inserts the given value at the given position
  700. ///
  701. /// \param pos The position at which to insert. The value will be inserted
  702. /// before the element referred to by pos, or at the end if pos == end()
  703. /// \param value The value to be inserted
  704. ///
  705. /// \retval The position of the inserted value
  706. ///
  707. /// \note All iterators, pointers and references are invalidated
  708. ///
  709. /// \note Any elements after the insertion position are moved using memmove,
  710. /// rather than by copy construction. If the element type maintains
  711. /// pointers to its internal members, or to its peer elements, then these
  712. /// relationships will be broken, and the subsequent behaviour of the
  713. /// program will be undefined
  714. iterator insert(iterator pos, value_type const& value)
  715. {
  716. // Precondition checks
  717. MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
  718. difference_type index = pos - begin();
  719. const size_type oldSize = size();
  720. resize(size());
  721. try
  722. {
  723. try
  724. {
  725. get_CArray().InsertAt(static_cast<int>(index), value, 1);
  726. }
  727. catch(CMemoryException *px)
  728. {
  729. exception_translation_policy_type::handle(px);
  730. }
  731. catch(mfcstl_ns_qual_std(bad_alloc) &x)
  732. {
  733. exception_translation_policy_type::handle(x);
  734. }
  735. }
  736. catch(...)
  737. {
  738. if(size() != oldSize)
  739. {
  740. MFCSTL_ASSERT(size() == oldSize + 1);
  741. get_CArray().RemoveAt(static_cast<int>(index), 1);
  742. }
  743. throw;
  744. }
  745. return begin() + index;
  746. }
  747. /// \brief Inserts a number of copies of the given value at the given position
  748. ///
  749. /// \param pos The position at which to insert. The value(s) will be inserted
  750. /// before the element referred to by pos, or at the end if pos == end()
  751. /// \param n The number of values to insert
  752. /// \param value The value to be inserted
  753. ///
  754. /// \note All iterators, pointers and references are invalidated
  755. ///
  756. /// \note Any elements after the insertion position are moved using memmove,
  757. /// rather than by copy construction. If the element type maintains
  758. /// pointers to its internal members, or to its peer elements, then these
  759. /// relationships will be broked, and the subsequent behaviour of the
  760. /// program will be undefined
  761. void insert(iterator pos, size_type n, value_type const& value)
  762. {
  763. // Precondition checks
  764. MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
  765. difference_type index = pos - begin();
  766. if(empty())
  767. {
  768. MFCSTL_ASSERT(0 == index);
  769. assign(n, value);
  770. }
  771. else
  772. {
  773. const size_type oldSize = size();
  774. resize(size());
  775. try
  776. {
  777. try
  778. {
  779. if(n > 0) // Can't pass 0 to InsertAt()
  780. {
  781. get_CArray().InsertAt(static_cast<int>(index), value, n);
  782. }
  783. }
  784. catch(CMemoryException *px)
  785. {
  786. exception_translation_policy_type::handle(px);
  787. }
  788. catch(mfcstl_ns_qual_std(bad_alloc) &x)
  789. {
  790. exception_translation_policy_type::handle(x);
  791. }
  792. }
  793. catch(...)
  794. {
  795. if(size() != oldSize)
  796. {
  797. MFCSTL_ASSERT(size() == oldSize + n);
  798. get_CArray().RemoveAt(static_cast<int>(index), size() - oldSize);
  799. }
  800. throw;
  801. }
  802. }
  803. }
  804. /// \brief Inserts the elements in the range [first, last) at the given position
  805. ///
  806. /// \param pos The position at which to insert. The value(s) will be inserted
  807. /// before the element referred to by pos, or at the end if pos == end()
  808. /// \param first The start of the range of values to insert
  809. /// \param last The (one past the) end of the range of values to insert
  810. ///
  811. /// \note All iterators, pointers and references are invalidated
  812. ///
  813. /// \note Any elements after the insertion position are moved using memmove,
  814. /// rather than by copy construction. If the element type maintains
  815. /// pointers to its internal members, or to its peer elements, then these
  816. /// relationships will be broked, and the subsequent behaviour of the
  817. /// program will be undefined
  818. template <ss_typename_param_k I2>
  819. void insert(iterator pos, I2 first, I2 last)
  820. {
  821. // Precondition checks
  822. MFCSTL_ASSERT(is_valid_source_range_(first, last));
  823. MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
  824. array_type ar;
  825. CArray_iadaptor<array_type
  826. , array_traits_type
  827. > arp(ar);
  828. arp.assign(first, last);
  829. difference_type index = pos - begin();
  830. const size_type oldSize = size();
  831. const size_type n = arp.size();
  832. resize(size());
  833. try
  834. {
  835. try
  836. {
  837. get_CArray().InsertAt(static_cast<int>(index), &ar);
  838. }
  839. catch(CMemoryException *px)
  840. {
  841. exception_translation_policy_type::handle(px);
  842. }
  843. catch(mfcstl_ns_qual_std(bad_alloc) &x)
  844. {
  845. exception_translation_policy_type::handle(x);
  846. }
  847. }
  848. catch(...)
  849. {
  850. if(size() != oldSize)
  851. {
  852. MFCSTL_ASSERT(size() == oldSize + n);
  853. get_CArray().RemoveAt(static_cast<int>(index), size() - oldSize);
  854. }
  855. throw;
  856. }
  857. }
  858. /// \brief Erases the element at the given position
  859. ///
  860. /// \param pos The position of the element to be removed
  861. ///
  862. /// \retval The position of the value immediately following the element erased
  863. ///
  864. /// \note Any iterators, pointers or references to elements at or after \c
  865. /// pos will be invalidated. Those before \c pos remain valid
  866. ///
  867. /// \note Any elements after the erasure position are moved using memmove,
  868. /// rather than by copy construction. If the element type maintains
  869. /// pointers to its internal members, or to its peer elements, then these
  870. /// relationships will be broked, and the subsequent behaviour of the
  871. /// program will be undefined
  872. iterator erase(iterator pos) stlsoft_throw_0()
  873. {
  874. // Precondition checks
  875. MFCSTL_ASSERT(pos == end() || (pos >= begin() && pos < end()));
  876. difference_type index = pos - begin();
  877. get_CArray().RemoveAt(static_cast<int>(index), 1);
  878. // Postcondition checks
  879. MFCSTL_ASSERT(pos == begin() + index);
  880. resize(size());
  881. return pos;
  882. }
  883. /// \brief Erases a range of elements from the array
  884. ///
  885. /// \param first The first element in the range to be removed
  886. /// \param last The (one past the) end element in the range to be removed
  887. ///
  888. /// \retval The position of the value immediately following the elements erased
  889. ///
  890. /// \note Any iterators, pointers or references to elements at or after \c
  891. /// first will be invalidated. Those before \c first remain valid
  892. ///
  893. /// \note Any elements after the erasure position are moved using memmove,
  894. /// rather than by copy construction. If the element type maintains
  895. /// pointers to its internal members, or to its peer elements, then these
  896. /// relationships will be broked, and the subsequent behaviour of the
  897. /// program will be undefined
  898. iterator erase(iterator first, iterator last) stlsoft_throw_0()
  899. {
  900. // Precondition checks
  901. MFCSTL_ASSERT(first <= last);
  902. MFCSTL_ASSERT(first == end() || (first >= begin() && first < end()));
  903. MFCSTL_ASSERT(last == end() || (last >= begin() && last < end()));
  904. difference_type index = first - begin();
  905. get_CArray().RemoveAt(static_cast<int>(index), mfcstl_ns_qual_std(distance)(first, last));
  906. // Postcondition checks
  907. MFCSTL_ASSERT(first == begin() + index);
  908. resize(size());
  909. return first;
  910. }
  911. /// \brief Removes all the elements from the array
  912. void clear() stlsoft_throw_0()
  913. {
  914. get_CArray().RemoveAll();
  915. resize(size());
  916. }
  917. #ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
  918. /// \brief Efficiently exchanges the contents with those of another array
  919. /// by swapping the internal structures
  920. ///
  921. /// \param rhs The instance whose contents will be exchanged with the callee
  922. ///
  923. /// \note This method is only defined if the preprocessor symbol
  924. /// MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT is defined
  925. void swap(class_type& rhs) stlsoft_throw_0()
  926. {
  927. mfcstl::CArray_swap(this->get_CArray(), rhs.get_CArray());
  928. }
  929. #endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  930. /// \brief Exchanges the contents with those of another array by copying
  931. /// each of the constituents, using a temporary array instance.
  932. ///
  933. /// \param rhs The instance whose contents will be exchanged with the callee
  934. void swap_by_copy(class_type& rhs)
  935. {
  936. class_type t = rhs;
  937. rhs = *this;
  938. *this = t;
  939. }
  940. /// @}
  941. /// \name Implementation
  942. /// @{
  943. private:
  944. template <ss_typename_param_k I2>
  945. # if defined(STLSOFT_COMPILER_IS_MWERKS)
  946. // 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
  947. void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag) const*)
  948. # else /* ? compiler */
  949. void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag))
  950. # endif /* compiler */
  951. {
  952. clear();
  953. mfcstl_ns_qual_std(copy)(first, last, mfcstl_ns_qual_std(back_inserter)<class_type>(*this));
  954. }
  955. template <ss_typename_param_k I2>
  956. # if defined(STLSOFT_COMPILER_IS_MWERKS)
  957. // 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
  958. void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(forward_iterator_tag) const*)
  959. # else /* ? compiler */
  960. void clear_and_assign_(I2 first, I2 last, stlsoft_ns_qual_std(forward_iterator_tag))
  961. # endif /* compiler */
  962. {
  963. resize(mfcstl_ns_qual_std(distance)(first, last));
  964. mfcstl_ns_qual_std(copy)(first, last, begin());
  965. }
  966. template <ss_typename_param_k I2>
  967. void clear_and_assign_(I2 first, I2 last)
  968. {
  969. # if defined(STLSOFT_COMPILER_IS_GCC) && \
  970. __GNUC__ < 3
  971. typedef ss_typename_type_k mfcstl_ns_qual_std(iterator_traits)<I2> traits_t;
  972. clear_and_assign_(first, last, traits_t::iterator_category());
  973. # elif defined(STLSOFT_COMPILER_IS_MWERKS)
  974. clear_and_assign_(first, last, stlsoft_iterator_query_category_ptr(I2, first));
  975. # else /* ? compiler */
  976. clear_and_assign_(first, last, stlsoft_iterator_query_category(I2, first));
  977. # endif /* compiler */
  978. }
  979. protected:
  980. #if ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
  981. _MSC_VER > 1200)
  982. template <ss_typename_param_k I2>
  983. # if defined(STLSOFT_COMPILER_IS_MWERKS)
  984. // 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
  985. static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag) const*)
  986. # else /* ? compiler */
  987. static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(input_iterator_tag))
  988. # endif /* compiler */
  989. {
  990. return true; // Can't test them, as that eats their state, so have to assume yes
  991. }
  992. #endif /* compiler */
  993. template< ss_typename_param_k I2
  994. , ss_typename_param_k T2
  995. >
  996. static ms_bool_t is_valid_source_range_(I2 first, I2 last, T2)
  997. {
  998. return true; // FI and BI don't have <=, so cannot test, so have to assume yes
  999. }
  1000. #if ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
  1001. _MSC_VER > 1200)
  1002. template <ss_typename_param_k I2>
  1003. # if defined(STLSOFT_COMPILER_IS_MWERKS)
  1004. // 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
  1005. static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(random_access_iterator_tag) const*)
  1006. # else /* ? compiler */
  1007. static ms_bool_t is_valid_source_range_(I2 first, I2 last, stlsoft_ns_qual_std(random_access_iterator_tag))
  1008. # endif /* compiler */
  1009. {
  1010. return first <= last;
  1011. }
  1012. #endif /* compiler */
  1013. template <ss_typename_param_k I2>
  1014. static ms_bool_t is_valid_source_range_(I2 first, I2 last)
  1015. {
  1016. # if defined(STLSOFT_COMPILER_IS_GCC) && \
  1017. __GNUC__ < 3
  1018. typedef ss_typename_type_k mfcstl_ns_qual_std(iterator_traits)<I2> traits_t;
  1019. return is_valid_source_range_(first, last, traits_t::iterator_category());
  1020. # elif defined(STLSOFT_COMPILER_IS_MWERKS)
  1021. return is_valid_source_range_(first, last, stlsoft_iterator_query_category_ptr(I2, first));
  1022. # elif defined(STLSOFT_COMPILER_IS_DMC)
  1023. return true;
  1024. # else /* ? compiler */
  1025. return is_valid_source_range_(first, last, stlsoft_iterator_query_category(I2, first));
  1026. # endif /* compiler */
  1027. }
  1028. #if 0
  1029. template <ss_typename_param_k T2>
  1030. static ms_bool_t is_valid_source_range_(T2* first, T2* last)
  1031. {
  1032. return first <= last;
  1033. }
  1034. #endif /* 0 */
  1035. #if 0
  1036. template <ss_typename_param_k T2>
  1037. static ms_bool_t is_valid_source_range_(T2 const* first, T2 const* last)
  1038. {
  1039. return first <= last;
  1040. }
  1041. #endif /* 0 */
  1042. /// @}
  1043. /// \name Not to be implemented
  1044. /// @{
  1045. private:
  1046. CArray_adaptor_base(class_type const& rhs);
  1047. class_type& operator =(class_type const& rhs);
  1048. /// @}
  1049. };
  1050. #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
  1051. /** \brief Adaptor class, representing a Class Adaptor over the CArray family
  1052. * of MFC containers
  1053. *
  1054. * \ingroup group__library__collections
  1055. *
  1056. * The adaptor, being a facade, is
  1057. *
  1058. * It is used as follows:
  1059. *
  1060. \code
  1061. mfcstl::CArray_cadaptor<CStringArray> ar;
  1062. // As an MFC CStringArray:
  1063. ar.Add("String 1");
  1064. ar.InsertAt(0, "String 0");
  1065. // As an STL container
  1066. ar.push_back("String 2");
  1067. std::list<CString> l;
  1068. l.push_back("String 3");
  1069. l.push_back("String 4");
  1070. ar.insert(ar.begin() + 2, l.begin(), l.end());
  1071. std::sort(ar.begin(), ar.end());
  1072. \endcode
  1073. *
  1074. * \param A The array class, e.g. CObArray, CArray<long>, etc.
  1075. *
  1076. * \note The elements in an adapted array are moved, during insertion / erasure, rather than copied. This
  1077. * means that if the elements in the container maintain pointers to their elements, or their peers, then
  1078. * they are not suitable for use.
  1079. */
  1080. #endif /* STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1081. template< ss_typename_param_k A
  1082. , ss_typename_param_k T = CArray_traits<A>
  1083. >
  1084. class CArray_cadaptor
  1085. : public A
  1086. , public CArray_adaptor_base<A, CArray_cadaptor<A, T>, T>
  1087. {
  1088. /// \name Member Types
  1089. /// @{
  1090. private:
  1091. typedef CArray_adaptor_base<A, CArray_cadaptor<A, T>, T> parent_class_type;
  1092. public:
  1093. /// The type of the underlying MFC array
  1094. typedef ss_typename_type_k parent_class_type::array_type array_type;
  1095. /// The value type
  1096. typedef ss_typename_type_k parent_class_type::value_type value_type;
  1097. /// The allocator type
  1098. typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
  1099. /// The mutating (non-const) reference type
  1100. typedef ss_typename_type_k parent_class_type::reference reference;
  1101. /// The non-mutating (const) reference type
  1102. typedef ss_typename_type_k parent_class_type::const_reference const_reference;
  1103. /// The mutating (non-const) pointer type
  1104. typedef ss_typename_type_k parent_class_type::pointer pointer;
  1105. /// The non-mutating (const) pointer type
  1106. typedef ss_typename_type_k parent_class_type::const_pointer const_pointer;
  1107. /// The mutating (non-const) iterator type
  1108. typedef ss_typename_type_k parent_class_type::iterator iterator;
  1109. /// The non-mutating (const) iterator type
  1110. typedef ss_typename_type_k parent_class_type::const_iterator const_iterator;
  1111. /// The size type
  1112. typedef ss_typename_type_k parent_class_type::size_type size_type;
  1113. /// The difference type
  1114. typedef ss_typename_type_k parent_class_type::difference_type difference_type;
  1115. /// The instantiation of the current type
  1116. typedef CArray_cadaptor<A, T> class_type;
  1117. /// @}
  1118. /// \name Identity
  1119. /// @{
  1120. private:
  1121. friend class CArray_adaptor_base<A, CArray_cadaptor<A, T>, T>;
  1122. array_type &get_actual_array()
  1123. {
  1124. return *this;
  1125. }
  1126. array_type const &get_actual_array() const
  1127. {
  1128. return *this;
  1129. }
  1130. /// @}
  1131. /// \name Construction
  1132. /// @{
  1133. public:
  1134. /// Default constructs an instance
  1135. ///
  1136. /// \note It takes a parameter of type <code>allocator_type</code>, but
  1137. /// ignores it. This facilitates adaptation by the standard adaptor
  1138. /// <code>std::stack</code>.
  1139. ss_explicit_k CArray_cadaptor(allocator_type const& = allocator_type())
  1140. {
  1141. parent_class_type::resize(0); // DMC++ needs it to be qualified. Go figure!
  1142. }
  1143. /// Constructs an instance with the given number of elements
  1144. ///
  1145. /// \param n The number of elements
  1146. explicit CArray_cadaptor(size_type n)
  1147. {
  1148. parent_class_type::resize(n);
  1149. }
  1150. /// Constructs an instance with the given number of elements
  1151. ///
  1152. /// \param n The number of elements
  1153. /// \param value The value of each element
  1154. CArray_cadaptor(size_type n, value_type const& value)
  1155. {
  1156. parent_class_type::assign(n, value);
  1157. }
  1158. /// Copy constructor
  1159. CArray_cadaptor(class_type const& rhs)
  1160. {
  1161. parent_class_type::assign(rhs.begin(), rhs.end());
  1162. }
  1163. /// Copy constructs an instance from the given underlying array
  1164. CArray_cadaptor(array_type const& rhs)
  1165. {
  1166. parent_class_type::assign(rhs.GetData(), rhs.GetData() + rhs.GetSize());
  1167. }
  1168. /// Constructs an instance from the given range
  1169. template <ss_typename_param_k I2>
  1170. CArray_cadaptor(I2 first, I2 last)
  1171. {
  1172. // Precondition checks
  1173. MFCSTL_ASSERT(parent_class_type::is_valid_source_range_(first, last));
  1174. parent_class_type::assign(first, last);
  1175. }
  1176. ~CArray_cadaptor() stlsoft_throw_0()
  1177. {
  1178. STLSOFT_STATIC_ASSERT(sizeof(A) == sizeof(ss_typename_type_k T::array_type));
  1179. }
  1180. /// @}
  1181. /// \name Assignment
  1182. /// @{
  1183. public:
  1184. class_type& operator =(class_type const& rhs)
  1185. {
  1186. #ifdef MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT
  1187. class_type t(rhs);
  1188. t.swap(*this);
  1189. #else /* ? MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  1190. parent_class_type::assign(rhs.begin(), rhs.end());
  1191. #endif /* MFCSTL_CARRAY_SWAP_MEMBERS_SUPPORT */
  1192. return *this;
  1193. }
  1194. /// @}
  1195. /// \name Element Access
  1196. /// @{
  1197. public:
  1198. #if defined(STLSOFT_COMPILER_IS_DMC)
  1199. reference operator [](size_type index)
  1200. {
  1201. return parent_class_type::operator [](index);
  1202. }
  1203. const_reference operator [](size_type index) const
  1204. {
  1205. return parent_class_type::operator [](index);
  1206. }
  1207. #else /* ? compiler */
  1208. using parent_class_type::operator [];
  1209. #endif /* compiler */
  1210. /// @}
  1211. };
  1212. #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
  1213. /** \brief Adaptor class, representing an Instance Adaptor over the CArray
  1214. * family of MFC containers
  1215. *
  1216. * \ingroup group__library__collections
  1217. *
  1218. * It is used as follows:
  1219. *
  1220. \code
  1221. CStringArray ar;
  1222. mfcstl::CArray_iadaptor<CStringArray> arp(ar);
  1223. // As an MFC CStringArray:
  1224. ar.Add("String 1");
  1225. ar.InsertAt(0, "String 0");
  1226. // As an STL container
  1227. arp.push_back("String 2");
  1228. std::list<CString> l;
  1229. l.push_back("String 3");
  1230. l.push_back("String 4");
  1231. arp.insert(arp.begin() + 2, l.begin(), l.end());
  1232. std::sort(arp.begin(), arp.end());
  1233. \endcode
  1234. *
  1235. * \param A The array class, e.g. CObArray, CArray<long>, etc.
  1236. *
  1237. * \note The elements in an adapted array are moved, during insertion / erasure, rather than copied. This
  1238. * means that if the elements in the container maintain pointers to their elements, or their peers, then
  1239. * they are not suitable for use.
  1240. */
  1241. #endif /* STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1242. template< ss_typename_param_k A
  1243. , ss_typename_param_k T = CArray_traits<A>
  1244. >
  1245. class CArray_iadaptor
  1246. : public CArray_adaptor_base<A, CArray_iadaptor<A, T>, T>
  1247. {
  1248. /// \name Member Types
  1249. /// @{
  1250. private:
  1251. typedef CArray_adaptor_base<A, CArray_iadaptor<A, T>, T> parent_class_type;
  1252. public:
  1253. /// The type of the underlying MFC array
  1254. typedef ss_typename_type_k parent_class_type::array_type array_type;
  1255. /// The value type
  1256. typedef ss_typename_type_k parent_class_type::value_type value_type;
  1257. /// The allocator type
  1258. typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
  1259. /// The mutating (non-const) reference type
  1260. typedef ss_typename_type_k parent_class_type::reference reference;
  1261. /// The non-mutating (const) reference type
  1262. typedef ss_typename_type_k parent_class_type::const_reference const_reference;
  1263. /// The mutating (non-const) pointer type
  1264. typedef ss_typename_type_k parent_class_type::pointer pointer;
  1265. /// The non-mutating (const) pointer type
  1266. typedef ss_typename_type_k parent_class_type::const_pointer const_pointer;
  1267. /// The mutating (non-const) iterator type
  1268. typedef ss_typename_type_k parent_class_type::iterator iterator;
  1269. /// The non-mutating (const) iterator type
  1270. typedef ss_typename_type_k parent_class_type::const_iterator const_iterator;
  1271. /// The size type
  1272. typedef ss_typename_type_k parent_class_type::size_type size_type;
  1273. /// The difference type
  1274. typedef ss_typename_type_k parent_class_type::difference_type difference_type;
  1275. /// The instantiation of the current type
  1276. typedef CArray_iadaptor<A, T> class_type;
  1277. /// @}
  1278. /// \name Identity
  1279. /// @{
  1280. private:
  1281. friend class CArray_adaptor_base<A, CArray_iadaptor<A, T>, T>;
  1282. array_type &get_actual_array()
  1283. {
  1284. MFCSTL_ASSERT(NULL != m_pArray);
  1285. return *m_pArray;
  1286. }
  1287. array_type const &get_actual_array() const
  1288. {
  1289. MFCSTL_ASSERT(NULL != m_pArray);
  1290. return *m_pArray;
  1291. }
  1292. /// @}
  1293. /// \name Construction
  1294. /// @{
  1295. public:
  1296. template <ss_typename_param_k A2>
  1297. CArray_iadaptor(A2 &array)
  1298. : m_pArray(&array)
  1299. {
  1300. STLSOFT_STATIC_ASSERT(sizeof(array_type) == sizeof(A2));
  1301. #ifdef STLSOFT_META_HAS_IS_SAME_TYPE
  1302. STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<array_type, A2>::value));
  1303. #else /* ? STLSOFT_META_HAS_IS_SAME_TYPE */
  1304. ASSERT(0 == ::lstrcmpA(array.GetRuntimeClass()->m_lpszClassName, array_type().GetRuntimeClass()->m_lpszClassName));
  1305. # ifdef _CPPRTTI
  1306. ASSERT(0 == ::lstrcmpA(typeid(A2).name(), typeid(array_type).name()));
  1307. # endif /* _CPPRTTI */
  1308. #endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
  1309. }
  1310. template <ss_typename_param_k A2>
  1311. CArray_iadaptor(A2 *pArray)
  1312. : m_pArray(pArray)
  1313. {
  1314. MFCSTL_MESSAGE_ASSERT("Cannot initialise a CArray_iadaptor with a NULL pointer", NULL != pArray);
  1315. STLSOFT_STATIC_ASSERT(sizeof(array_type) == sizeof(A2));
  1316. #ifdef STLSOFT_META_HAS_IS_SAME_TYPE
  1317. STLSOFT_STATIC_ASSERT((stlsoft::is_same_type<array_type, A2>::value));
  1318. #else /* ? STLSOFT_META_HAS_IS_SAME_TYPE */
  1319. ASSERT(0 == ::lstrcmpA(pArray->GetRuntimeClass()->m_lpszClassName, array_type().GetRuntimeClass()->m_lpszClassName));
  1320. # ifdef _CPPRTTI
  1321. ASSERT(0 == ::lstrcmpA(typeid(A2).name(), typeid(array_type).name()));
  1322. # endif /* _CPPRTTI */
  1323. #endif /* STLSOFT_META_HAS_IS_SAME_TYPE */
  1324. }
  1325. /// @}
  1326. /// \name Members
  1327. /// @{
  1328. private:
  1329. array_type *m_pArray;
  1330. /// @}
  1331. /// \name Not to be implemented
  1332. /// @{
  1333. private:
  1334. CArray_iadaptor(class_type const& rhs); // Only possible semantics for copy-ctor are share underlying array
  1335. class_type& operator =(class_type const& rhs); // Could either repoint, or could do deep copy.
  1336. /// @}
  1337. };
  1338. /* /////////////////////////////////////////////////////////////////////////
  1339. * Comparison
  1340. */
  1341. template< ss_typename_param_k A1
  1342. , ss_typename_param_k A2
  1343. , ss_typename_param_k I1
  1344. , ss_typename_param_k I2
  1345. , ss_typename_param_k T1
  1346. , ss_typename_param_k T2
  1347. >
  1348. inline ms_bool_t operator ==(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
  1349. {
  1350. return lhs.equal(rhs);
  1351. }
  1352. template< ss_typename_param_k A1
  1353. , ss_typename_param_k A2
  1354. , ss_typename_param_k I1
  1355. , ss_typename_param_k I2
  1356. , ss_typename_param_k T1
  1357. , ss_typename_param_k T2
  1358. >
  1359. inline ms_bool_t operator !=(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
  1360. {
  1361. return !lhs.equal(rhs);
  1362. }
  1363. template< ss_typename_param_k A1
  1364. , ss_typename_param_k A2
  1365. , ss_typename_param_k I1
  1366. , ss_typename_param_k I2
  1367. , ss_typename_param_k T1
  1368. , ss_typename_param_k T2
  1369. >
  1370. inline ms_bool_t operator <(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
  1371. {
  1372. return lhs.less_than(rhs);
  1373. }
  1374. template< ss_typename_param_k A1
  1375. , ss_typename_param_k A2
  1376. , ss_typename_param_k I1
  1377. , ss_typename_param_k I2
  1378. , ss_typename_param_k T1
  1379. , ss_typename_param_k T2
  1380. >
  1381. inline ms_bool_t operator <=(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
  1382. {
  1383. return !lhs.greater_than(rhs);
  1384. }
  1385. template< ss_typename_param_k A1
  1386. , ss_typename_param_k A2
  1387. , ss_typename_param_k I1
  1388. , ss_typename_param_k I2
  1389. , ss_typename_param_k T1
  1390. , ss_typename_param_k T2
  1391. >
  1392. inline ms_bool_t operator >(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
  1393. {
  1394. return lhs.greater_than(rhs);
  1395. }
  1396. template< ss_typename_param_k A1
  1397. , ss_typename_param_k A2
  1398. , ss_typename_param_k I1
  1399. , ss_typename_param_k I2
  1400. , ss_typename_param_k T1
  1401. , ss_typename_param_k T2
  1402. >
  1403. inline ms_bool_t operator >=(CArray_adaptor_base<A1, I1, T1> const& lhs, CArray_adaptor_base<A2, I2, T2> const& rhs)
  1404. {
  1405. return !lhs.less_than(rhs);
  1406. }
  1407. template< ss_typename_param_k A
  1408. , ss_typename_param_k I
  1409. , ss_typename_param_k T
  1410. >
  1411. inline ms_bool_t operator ==(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
  1412. {
  1413. return lhs.equal(rhs);
  1414. }
  1415. template< ss_typename_param_k A
  1416. , ss_typename_param_k I
  1417. , ss_typename_param_k T
  1418. >
  1419. inline ms_bool_t operator !=(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
  1420. {
  1421. return !lhs.equal(rhs);
  1422. }
  1423. template< ss_typename_param_k A
  1424. , ss_typename_param_k I
  1425. , ss_typename_param_k T
  1426. >
  1427. inline ms_bool_t operator <(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
  1428. {
  1429. return lhs.less_than(rhs);
  1430. }
  1431. template< ss_typename_param_k A
  1432. , ss_typename_param_k I
  1433. , ss_typename_param_k T
  1434. >
  1435. inline ms_bool_t operator <=(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
  1436. {
  1437. return !lhs.greater_than(rhs);
  1438. }
  1439. template< ss_typename_param_k A
  1440. , ss_typename_param_k I
  1441. , ss_typename_param_k T
  1442. >
  1443. inline ms_bool_t operator >(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
  1444. {
  1445. return lhs.greater_than(rhs);
  1446. }
  1447. template< ss_typename_param_k A
  1448. , ss_typename_param_k I
  1449. , ss_typename_param_k T
  1450. >
  1451. inline ms_bool_t operator >=(CArray_adaptor_base<A, I, T> const& lhs, A const& rhs)
  1452. {
  1453. return !lhs.less_than(rhs);
  1454. }
  1455. template< ss_typename_param_k A
  1456. , ss_typename_param_k I
  1457. , ss_typename_param_k T
  1458. >
  1459. inline ms_bool_t operator ==(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
  1460. {
  1461. return rhs.equal(lhs);
  1462. }
  1463. template< ss_typename_param_k A
  1464. , ss_typename_param_k I
  1465. , ss_typename_param_k T
  1466. >
  1467. inline ms_bool_t operator !=(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
  1468. {
  1469. return !rhs.equal(lhs);
  1470. }
  1471. template< ss_typename_param_k A
  1472. , ss_typename_param_k I
  1473. , ss_typename_param_k T
  1474. >
  1475. inline ms_bool_t operator <(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
  1476. {
  1477. return !(rhs.greater_than(lhs) || rhs == lhs);
  1478. }
  1479. template< ss_typename_param_k A
  1480. , ss_typename_param_k I
  1481. , ss_typename_param_k T
  1482. >
  1483. inline ms_bool_t operator <=(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
  1484. {
  1485. return !rhs.less_than(lhs);
  1486. }
  1487. template< ss_typename_param_k A
  1488. , ss_typename_param_k I
  1489. , ss_typename_param_k T
  1490. >
  1491. inline ms_bool_t operator >(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
  1492. {
  1493. return !(rhs.less_than(lhs) || rhs == lhs);
  1494. }
  1495. template< ss_typename_param_k A
  1496. , ss_typename_param_k I
  1497. , ss_typename_param_k T
  1498. >
  1499. inline ms_bool_t operator >=(A const& lhs, CArray_adaptor_base<A, I, T> const& rhs)
  1500. {
  1501. return !rhs.greater_than(lhs);
  1502. }
  1503. ////////////////////////////////////////////////////////////////////////////
  1504. // Unit-testing
  1505. #ifdef STLSOFT_UNITTEST
  1506. # include "./unittest/carray_adaptors_unittest_.h"
  1507. #endif /* STLSOFT_UNITTEST */
  1508. /* ////////////////////////////////////////////////////////////////////// */
  1509. #ifndef _MFCSTL_NO_NAMESPACE
  1510. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1511. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1512. } // namespace mfcstl
  1513. # else
  1514. } // namespace mfcstl_project
  1515. } // namespace stlsoft
  1516. # endif /* _STLSOFT_NO_NAMESPACE */
  1517. #endif /* !_MFCSTL_NO_NAMESPACE */
  1518. /* ////////////////////////////////////////////////////////////////////// */
  1519. #endif /* !MFCSTL_INCL_MFCSTL_COLLECTIONS_HPP_CARRAY_ADAPTORS */
  1520. /* ///////////////////////////// end of file //////////////////////////// */