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.

497 lines
15 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/collections/array_view.hpp (derived from array_proxy (stlsoft_array_proxy.h)
  3. *
  4. * Purpose: Definition of the array_view template, which provides managed
  5. * access to arrays, and can be used to avoid polymorphic array
  6. * problems.
  7. *
  8. * Created: 11th November 2002
  9. * Updated: 10th August 2009
  10. *
  11. * Home: http://stlsoft.org/
  12. *
  13. * Copyright (c) 2002-2009, Matthew Wilson and Synesis Software
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms, with or without
  17. * modification, are permitted provided that the following conditions are met:
  18. *
  19. * - Redistributions of source code must retain the above copyright notice, this
  20. * list of conditions and the following disclaimer.
  21. * - Redistributions in binary form must reproduce the above copyright notice,
  22. * this list of conditions and the following disclaimer in the documentation
  23. * and/or other materials provided with the distribution.
  24. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  25. * any contributors may be used to endorse or promote products derived from
  26. * this software without specific prior written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  29. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  34. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  35. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  37. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * ////////////////////////////////////////////////////////////////////// */
  41. /** \file stlsoft/collections/array_view.hpp
  42. *
  43. * \brief [C++ only] Definition of the stlsoft::array_view
  44. * class template
  45. * (\ref group__library__collections "Collections" Library).
  46. */
  47. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW
  48. #define STLSOFT_INCL_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define STLSOFT_VER_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW_MAJOR 4
  51. # define STLSOFT_VER_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW_MINOR 1
  52. # define STLSOFT_VER_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW_REVISION 1
  53. # define STLSOFT_VER_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW_EDIT 70
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Compatibility
  57. */
  58. /*
  59. [Incompatibilies-start]
  60. STLSOFT_COMPILER_IS_WATCOM:
  61. [Incompatibilies-end]
  62. */
  63. /* /////////////////////////////////////////////////////////////////////////
  64. * Includes
  65. */
  66. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  67. # include <stlsoft/stlsoft.h>
  68. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  69. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  70. # include <stlsoft/util/std/iterator_helper.hpp>
  71. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  72. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  73. # include <stlsoft/collections/util/collections.hpp>
  74. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  75. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP
  76. # include <stlsoft/util/std_swap.hpp>
  77. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP */
  78. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  79. # include <stdexcept> // for std::out_of_range
  80. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  81. /* /////////////////////////////////////////////////////////////////////////
  82. * Namespace
  83. */
  84. #ifndef _STLSOFT_NO_NAMESPACE
  85. namespace stlsoft
  86. {
  87. #endif /* _STLSOFT_NO_NAMESPACE */
  88. /* /////////////////////////////////////////////////////////////////////////
  89. * Classes
  90. */
  91. /** \brief Acts as a view for built-in arrays, ensuring functions passed
  92. * array proxies have safe access to both array pointer and length, to
  93. * avoid polymorphic array problems.
  94. *
  95. * \ingroup group__library__collections
  96. */
  97. template <ss_typename_param_k T>
  98. class array_view
  99. : public stl_collection_tag
  100. {
  101. /// \name Types
  102. /// @{
  103. public:
  104. typedef T value_type;
  105. typedef array_view<T> class_type;
  106. typedef value_type* pointer;
  107. typedef value_type const* const_pointer;
  108. typedef value_type& reference;
  109. typedef value_type const& const_reference;
  110. typedef ss_size_t size_type;
  111. typedef ss_ptrdiff_t difference_type;
  112. #if !defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  113. /// The iterator type
  114. typedef value_type* iterator;
  115. /// The non-mutable (const) iterator type
  116. typedef value_type const* const_iterator;
  117. #else /* ? !STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  118. /// The iterator type
  119. typedef
  120. # if !defined(STLSOFT_COMPILER_IS_BORLAND)
  121. ss_typename_type_k
  122. # endif /* compiler */
  123. pointer_iterator < value_type
  124. , pointer
  125. , reference
  126. >::type iterator;
  127. /// The non-mutating (const) iterator type
  128. typedef
  129. # if !defined(STLSOFT_COMPILER_IS_BORLAND)
  130. ss_typename_type_k
  131. # endif /* compiler */
  132. pointer_iterator < value_type const
  133. , const_pointer
  134. , const_reference
  135. >::type const_iterator;
  136. /// The mutating (non-const) reverse iterator type
  137. typedef reverse_iterator_base < iterator
  138. , value_type
  139. , reference
  140. , pointer
  141. , difference_type
  142. > reverse_iterator;
  143. /// The non-mutating (const) reverse iterator type
  144. typedef const_reverse_iterator_base < const_iterator
  145. , value_type const
  146. , const_reference
  147. , const_pointer
  148. , difference_type
  149. > const_reverse_iterator;
  150. #endif /* !STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  151. /// @}
  152. /// \name Construction
  153. /// @{
  154. public:
  155. /// Default constructor, creating a view of 0 size
  156. ///
  157. /// \note The base() method returns NULL
  158. array_view()
  159. : m_size(0)
  160. , m_base(NULL)
  161. {
  162. STLSOFT_ASSERT(is_valid());
  163. }
  164. #ifdef STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT
  165. /// Constructs an instance of the array view from the given array
  166. ///
  167. /// \param t The array
  168. template <size_type N>
  169. ss_explicit_k array_view(T (&t)[N])
  170. : m_size(N)
  171. , m_base(&t[0])
  172. {
  173. STLSOFT_ASSERT(is_valid());
  174. }
  175. #endif /* STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT */
  176. /// Constructs an instance of the array view from the given range
  177. ///
  178. /// \param begin The start point of the range [begin, end)
  179. /// \param end The end point of the range [begin, end)
  180. array_view(pointer begin, pointer end)
  181. : m_size(stlsoft_ns_qual_std(distance)(begin, end))
  182. , m_base(begin)
  183. {
  184. STLSOFT_ASSERT(is_valid());
  185. }
  186. /// Constructs an instance of the array view from the given pointer
  187. ///
  188. /// \param p Pointer to the first element in the range
  189. /// \param n The number of elements in the range
  190. array_view(pointer p, size_type n)
  191. : m_size(n)
  192. , m_base(p)
  193. {
  194. STLSOFT_ASSERT(is_valid());
  195. }
  196. /// Swaps the contents between \c this and \c rhs
  197. void swap(class_type& rhs) stlsoft_throw_0()
  198. {
  199. STLSOFT_ASSERT(is_valid());
  200. std_swap(m_size, rhs.m_size);
  201. std_swap(m_base, rhs.m_base);
  202. STLSOFT_ASSERT(is_valid());
  203. }
  204. /// \name Attributes
  205. /// @{
  206. public:
  207. /// Returns the base of the array
  208. ///
  209. pointer base()
  210. {
  211. STLSOFT_ASSERT(is_valid());
  212. return m_base;
  213. }
  214. /// Returns the base of the array
  215. ///
  216. pointer base() const
  217. {
  218. STLSOFT_ASSERT(is_valid());
  219. return m_base;
  220. }
  221. /// Returns the number of elements in the sequence
  222. size_type size() const
  223. {
  224. STLSOFT_ASSERT(is_valid());
  225. return m_size;
  226. }
  227. /// Indicates whether the search sequence is empty
  228. ss_bool_t empty() const
  229. {
  230. STLSOFT_ASSERT(is_valid());
  231. return 0 == m_size;
  232. }
  233. /// Returns the maximum number of elements in the sequence
  234. static size_type max_size()
  235. {
  236. return static_cast<size_type>(-1) / sizeof(value_type);
  237. }
  238. /// @}
  239. /// \name Subscripting
  240. /// @{
  241. public:
  242. /// Returns the element at the given index
  243. ///
  244. /// \param index The offset of the requested element
  245. /// \note No runtime checking of the validity of the index is provided in release builds, only a debug-time assert
  246. reference operator [](size_type index)
  247. {
  248. STLSOFT_MESSAGE_ASSERT("index out of bounds, in array_view", !(size() < index));
  249. STLSOFT_ASSERT(is_valid());
  250. return m_base[index];
  251. }
  252. /// Returns the element at the given index
  253. ///
  254. /// \param index The offset of the requested element
  255. /// \note No runtime checking of the validity of the index is provided in release builds, only a debug-time assert
  256. const_reference operator [](size_type index) const
  257. {
  258. STLSOFT_MESSAGE_ASSERT("index out of bounds, in array_view", !(size() < index));
  259. STLSOFT_ASSERT(is_valid());
  260. return const_cast<pointer>(m_base)[index];
  261. }
  262. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  263. /// Returns the element at the given index
  264. ///
  265. /// \param index The offset of the requested element
  266. ///
  267. /// \note Throws an instance of std::out_of_range if the index is not < size()
  268. reference at(size_type index)
  269. {
  270. STLSOFT_ASSERT(is_valid());
  271. range_check_(index);
  272. return m_base[index];
  273. }
  274. /// Returns the element at the given index
  275. ///
  276. /// \param index The offset of the requested element
  277. ///
  278. /// \note Throws an instance of std::out_of_range if the index is not < size()
  279. const_reference at(size_type index) const
  280. {
  281. STLSOFT_ASSERT(is_valid());
  282. range_check_(index);
  283. return const_cast<pointer>(m_base)[index];
  284. }
  285. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  286. /// @}
  287. /// \name Iteration
  288. /// @{
  289. public:
  290. /// Begins the iteration
  291. ///
  292. /// \return An iterator representing the start of the sequence
  293. iterator begin()
  294. {
  295. STLSOFT_ASSERT(is_valid());
  296. return m_base;
  297. }
  298. /// Ends the iteration
  299. ///
  300. /// \return An iterator representing the end of the sequence
  301. iterator end()
  302. {
  303. STLSOFT_ASSERT(is_valid());
  304. return begin() + size();
  305. }
  306. /// Begins the iteration
  307. ///
  308. /// \return An iterator representing the start of the sequence
  309. const_iterator begin() const
  310. {
  311. STLSOFT_ASSERT(is_valid());
  312. return m_base;
  313. }
  314. /// Ends the iteration
  315. ///
  316. /// \return An iterator representing the end of the sequence
  317. const_iterator end() const
  318. {
  319. STLSOFT_ASSERT(is_valid());
  320. return begin() + size();
  321. }
  322. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  323. /// Begins the reverse iteration
  324. ///
  325. /// \return An iterator representing the start of the reverse sequence
  326. const_reverse_iterator rbegin() const
  327. {
  328. return const_reverse_iterator(end());
  329. }
  330. /// Ends the reverse iteration
  331. ///
  332. /// \return An iterator representing the end of the reverse sequence
  333. const_reverse_iterator rend() const
  334. {
  335. return const_reverse_iterator(begin());
  336. }
  337. /// Begins the reverse iteration
  338. ///
  339. /// \return An iterator representing the start of the reverse sequence
  340. reverse_iterator rbegin()
  341. {
  342. return reverse_iterator(end());
  343. }
  344. /// Ends the reverse iteration
  345. ///
  346. /// \return An iterator representing the end of the reverse sequence
  347. reverse_iterator rend()
  348. {
  349. return reverse_iterator(begin());
  350. }
  351. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  352. /// @}
  353. /// \name Invariant
  354. /// @{
  355. #ifdef STLSOFT_UNITTEST
  356. public:
  357. #else /* ? STLSOFT_UNITTEST */
  358. private:
  359. #endif /* STLSOFT_UNITTEST */
  360. ss_bool_t is_valid() const
  361. {
  362. if( 0 != m_size &&
  363. NULL == m_base)
  364. {
  365. #ifdef STLSOFT_UNITTEST
  366. fprintf(err, "Cannot have non-empty array view with NULL base pointer\n");
  367. #endif /* STLSOFT_UNITTEST */
  368. return false;
  369. }
  370. return true;
  371. }
  372. /// @}
  373. /// \name Implementation
  374. /// @{
  375. private:
  376. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  377. void range_check_(size_type index) const
  378. {
  379. if(!(index < size()))
  380. {
  381. STLSOFT_THROW_X(stlsoft_ns_qual_std(out_of_range)("array view index out of range"));
  382. }
  383. }
  384. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  385. /// @}
  386. /// \name Members
  387. /// @{
  388. private:
  389. size_type m_size;
  390. pointer m_base;
  391. /// @}
  392. };
  393. /* /////////////////////////////////////////////////////////////////////////
  394. * Creator functions
  395. */
  396. #ifdef STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT
  397. template <ss_typename_param_k T, ss_size_t N>
  398. inline array_view<T> make_array_view(T (&t)[N])
  399. {
  400. return array_view<T>(&t[0], &t[N]);
  401. // return array_view<T>(t); // This one not used, because CodeWarrior gets confused
  402. }
  403. #endif /* STLSOFT_CF_STATIC_ARRAY_SIZE_DETERMINATION_SUPPORT */
  404. template <ss_typename_param_k T>
  405. inline array_view<T> make_array_view(T *begin, T *end)
  406. {
  407. return array_view<T>(begin, end);
  408. }
  409. template <ss_typename_param_k T>
  410. inline array_view<const T> make_array_view(T const* begin, T const* end)
  411. {
  412. return array_view<const T>(begin, end);
  413. }
  414. template <ss_typename_param_k T>
  415. inline array_view<T> make_array_view(T *p, ss_size_t n)
  416. {
  417. return array_view<T>(p, n);
  418. }
  419. #if 0
  420. template <ss_typename_param_k T>
  421. inline array_view<const T> make_array_view(T const* p, ss_size_t n)
  422. {
  423. return array_view<const T>(p, n);
  424. }
  425. #endif /* 0 */
  426. ////////////////////////////////////////////////////////////////////////////
  427. // Unit-testing
  428. #ifdef STLSOFT_UNITTEST
  429. # include "./unittest/array_view_unittest_.h"
  430. #endif /* STLSOFT_UNITTEST */
  431. /* ////////////////////////////////////////////////////////////////////// */
  432. #ifndef _STLSOFT_NO_NAMESPACE
  433. } // namespace stlsoft
  434. #endif /* _STLSOFT_NO_NAMESPACE */
  435. /* ////////////////////////////////////////////////////////////////////// */
  436. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_HPP_ARRAY_VIEW */
  437. /* ///////////////////////////// end of file //////////////////////////// */