00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00052 #ifndef COMSTL_INCL_COMSTL_COLLECTIONS_HPP_ENUMERATOR_SEQUENCE
00053 #define COMSTL_INCL_COMSTL_COLLECTIONS_HPP_ENUMERATOR_SEQUENCE
00054
00055 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00056 # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATOR_SEQUENCE_MAJOR 6
00057 # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATOR_SEQUENCE_MINOR 1
00058 # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATOR_SEQUENCE_REVISION 4
00059 # define COMSTL_VER_COMSTL_COLLECTIONS_HPP_ENUMERATOR_SEQUENCE_EDIT 250
00060 #endif
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #ifndef COMSTL_INCL_COMSTL_H_COMSTL
00077 # include <comstl/comstl.h>
00078 #endif
00079 #ifndef COMSTL_INCL_COMSTL_COLLECTIONS_HPP_ENUMERATION_POLICIES
00080 # include <comstl/collections/enumeration_policies.hpp>
00081 #endif
00082 #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
00083 # include <stlsoft/util/std/iterator_helper.hpp>
00084 #endif
00085 #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
00086 # include <stlsoft/collections/util/collections.hpp>
00087 #endif
00088 #ifndef STLSOFT_INCL_STLSOFT_META_HPP_CAPABILITIES
00089 # include <stlsoft/meta/capabilities.hpp>
00090 #endif
00091 #ifdef STLSOFT_CF_TEMPLATE_PARTIAL_SPECIALISATION_SUPPORT
00092 # ifndef STLSOFT_INCL_STLSOFT_META_HPP_BASE_TYPE_TRAITS
00093 # include <stlsoft/meta/base_type_traits.hpp>
00094 # endif
00095 # ifndef STLSOFT_INCL_STLSOFT_META_HPP_SELECT_FIRST_TYPE_IF
00096 # include <stlsoft/meta/select_first_type_if.hpp>
00097 # endif
00098 #endif
00099
00100 #ifndef STLSOFT_INCL_ALGORITHM
00101 # define STLSOFT_INCL_ALGORITHM
00102 # include <algorithm>
00103 #endif
00104
00105 #ifdef STLSOFT_UNITTEST
00106 # include <comstl/util/value_policies.hpp>
00107 # if !defined(STLSOFT_COMPILER_IS_DMC)
00108 # include "./unittest/_recls_COM_decl_.h"
00109 # endif
00110 # if !defined(STLSOFT_COMPILER_IS_COMO)
00111 # include <winstl/dl/dl_call.hpp>
00112 # endif
00113 #endif
00114
00115
00116
00117
00118
00119 #ifndef _COMSTL_NO_NAMESPACE
00120 # if defined(_STLSOFT_NO_NAMESPACE) || \
00121 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00122
00123 namespace comstl
00124 {
00125 # else
00126
00127
00128 namespace stlsoft
00129 {
00130
00131 namespace comstl_project
00132 {
00133
00134 # endif
00135 #endif
00136
00137
00138
00139
00140
00208 template< ss_typename_param_k I
00209 , ss_typename_param_k V
00210 , ss_typename_param_k VP
00211 , ss_typename_param_k R = V const&
00212 , ss_typename_param_k CP = cloneable_cloning_policy<I>
00213 , cs_size_t Q = 10
00214 >
00215 class enumerator_sequence
00216 : public stlsoft_ns_qual(stl_collection_tag)
00217 {
00220 public:
00222 typedef I interface_type;
00224 typedef V value_type;
00226 typedef value_policy_adaptor<VP> value_policy_type;
00228 typedef R reference;
00229 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00230 typedef R reference_type;
00231 #endif
00233 #if defined(STLSOFT_META_HAS_SELECT_FIRST_TYPE_IF) && \
00234 !defined(STLSOFT_COMPILER_IS_BORLAND)
00235 typedef ss_typename_type_k stlsoft_ns_qual(select_first_type_if)< value_type const*
00236 , value_type*
00237 , stlsoft_ns_qual(base_type_traits)<R>::is_const
00238 >::type pointer;
00239 #else
00240 typedef value_type* pointer;
00241 #endif
00243 typedef value_type const* const_pointer;
00245 typedef CP cloning_policy_type;
00247 typedef ss_typename_type_k cloning_policy_type::iterator_tag_type iterator_tag_type;
00248 #ifdef STLSOFT_COMPILER_IS_BORLAND
00249 # define retrievalQuanta Q
00250 #else
00252 enum { retrievalQuanta = Q };
00253 #endif
00255 typedef enumerator_sequence<I, V, VP, R, CP, Q> class_type;
00257 typedef class_type sequence_type;
00259 typedef cs_size_t size_type;
00261 typedef cs_ptrdiff_t difference_type;
00263 typedef cs_bool_t bool_type;
00265
00266 public:
00281 enumerator_sequence(interface_type* i, bool_type bAddRef, size_type quanta = 0, bool_type bReset = true)
00282 : m_root(i)
00283 , m_enumerator(NULL)
00284 , m_quanta(validate_quanta_(quanta))
00285 , m_bFirst(true)
00286 {
00287 COMSTL_MESSAGE_ASSERT("Precondition violation: interface cannot be NULL!", NULL != i);
00288
00289 if(bAddRef)
00290 {
00291 m_root->AddRef();
00292 }
00293 if(bReset)
00294 {
00295 m_root->Reset();
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 m_enumerator = cloning_policy_type::get_working_instance(m_root);
00308
00309 if(NULL != m_enumerator)
00310 {
00311 m_bFirst = false;
00312 }
00313
00314 COMSTL_ASSERT(is_valid());
00315 }
00317 ~enumerator_sequence() stlsoft_throw_0()
00318 {
00319 COMSTL_ASSERT(is_valid());
00320
00321 m_root->Release();
00322 if(NULL != m_enumerator)
00323 {
00324 m_enumerator->Release();
00325 }
00326 }
00327
00330 public:
00332 class iterator
00333 : public stlsoft_ns_qual(iterator_base)<iterator_tag_type
00334 , value_type
00335 , difference_type
00336 , pointer
00337 , reference
00338 >
00339 {
00340 public:
00341 typedef iterator class_type;
00342 #if defined(STLSOFT_COMPILER_IS_GCC)
00343 typedef ss_typename_type_k sequence_type::cloning_policy_type cloning_policy_type;
00344 typedef ss_typename_type_k sequence_type::value_type value_type;
00345 #endif
00346
00347 private:
00348 struct enumeration_context
00349 {
00352 public:
00353 typedef enumeration_context class_type;
00354 typedef V value_type;
00355 typedef CP cloning_policy_type;
00357
00360 private:
00365 enumeration_context(interface_type* i, class_type const& rhs)
00366 : m_enumerator(i)
00367 , m_acquired(rhs.m_acquired)
00368 , m_current(rhs.m_current)
00369 , m_quanta(rhs.m_quanta)
00370 , m_refCount(1)
00371 , m_previousBlockTotal(rhs.m_previousBlockTotal)
00372 {
00373 COMSTL_ASSERT(rhs.m_acquired <= m_quanta);
00374
00375
00376
00377 init_elements_(m_quanta);
00378
00379 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00380 try
00381 #endif
00382 {
00383 value_type* begin = &m_values[0];
00384 value_type* end = &m_values[0] + m_quanta;
00385 value_type const* src_begin = &rhs.m_values[0];
00386 value_type const* src_end = &rhs.m_values[0] + rhs.m_acquired;
00387
00388
00389 for(; src_begin != src_end; ++begin, ++src_begin)
00390 {
00391 value_policy_type::copy(begin, src_begin);
00392 }
00393
00394 COMSTL_ASSERT(begin <= end);
00395 STLSOFT_SUPPRESS_UNUSED(end);
00396 }
00397 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00398 catch(...)
00399 {
00400
00401
00402 clear_elements_();
00403
00404 throw;
00405 }
00406 #endif
00407
00408 COMSTL_ASSERT(is_valid());
00409
00410 COMSTL_ASSERT(this->index() == rhs.index());
00411 }
00412 public:
00416 enumeration_context(interface_type* i, size_type quanta, bool_type bFirst)
00417 : m_enumerator(bFirst ? (i->AddRef(), i) : cloning_policy_type::share(i))
00418 , m_acquired(0)
00419 , m_current(0)
00420 , m_quanta(static_cast<ULONG>(quanta))
00421 , m_refCount(1)
00422 , m_previousBlockTotal(0)
00423 {
00424 COMSTL_ASSERT(quanta <= STLSOFT_NUM_ELEMENTS(m_values));
00425
00426 init_elements_(m_quanta);
00427
00428
00429
00430 acquire_next_();
00431
00432 COMSTL_ASSERT(is_valid());
00433 }
00434
00435 ~enumeration_context() stlsoft_throw_0()
00436 {
00437 ++m_refCount;
00438 COMSTL_ASSERT(is_valid());
00439 --m_refCount;
00440
00441 clear_elements_();
00442
00443 if(NULL != m_enumerator)
00444 {
00445 m_enumerator->Release();
00446 }
00447 }
00448
00449 void AddRef()
00450 {
00451 ++m_refCount;
00452 }
00453 void Release()
00454 {
00455 if(0 == --m_refCount)
00456 {
00457 delete this;
00458 }
00459 }
00460
00461 static class_type* make_clone(class_type* ctxt)
00462 {
00463 if(NULL == ctxt)
00464 {
00465 return NULL;
00466 }
00467 else
00468 {
00469 COMSTL_ASSERT(NULL != ctxt->m_enumerator);
00470
00471 interface_type* copy;
00472 const bool bTrueClone = cloning_policy_type::clone(ctxt->m_enumerator, ©);
00473
00474 if(!bTrueClone)
00475 {
00476 COMSTL_ASSERT(NULL == copy);
00477
00478
00479
00480
00481
00482
00483
00484 ctxt->AddRef();
00485
00486 return ctxt;
00487 }
00488 else
00489 {
00490 COMSTL_ASSERT(NULL != copy);
00491
00492
00493
00494
00495
00496 class_type* newCtxt;
00497
00498 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00499 try
00500 #endif
00501 {
00502 newCtxt = new class_type(copy, *ctxt);
00503
00504 if(NULL == newCtxt)
00505 {
00506 copy->Release();
00507 }
00508 }
00509 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00510 catch(...)
00511 {
00512 copy->Release();
00513
00514 throw;
00515 }
00516 #endif
00517
00518 return newCtxt;
00519 }
00520 }
00521 }
00523
00526 public:
00527 void advance() stlsoft_throw_0()
00528 {
00529 COMSTL_ASSERT(NULL != m_enumerator);
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 COMSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator: m_refCount < 1", 0 < m_refCount);
00542 COMSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator: 0 == m_acquired", 0 != m_acquired);
00543 COMSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator: m_current >= m_acquired", m_current < m_acquired);
00544 COMSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator: m_acquired > m_quanta", m_acquired <= m_quanta);
00545 COMSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator: m_quanta > dimensionof(m_values)", m_quanta <= STLSOFT_NUM_ELEMENTS(m_values));
00546
00547 if(++m_current < m_acquired)
00548 {
00549
00550
00551
00552 }
00553 else
00554 {
00555 COMSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator", NULL != m_enumerator);
00556
00557 clear_elements_();
00558
00559
00560 m_current = 0;
00561
00562 acquire_next_();
00563 }
00564 }
00565
00566 value_type ¤t() stlsoft_throw_0()
00567 {
00568 COMSTL_ASSERT(!empty());
00569
00570 return m_values[m_current];
00571 }
00572
00573 size_type index() const stlsoft_throw_0()
00574 {
00575 return m_previousBlockTotal + m_current;
00576 }
00577
00578 bool empty() const stlsoft_throw_0()
00579 {
00580 return 0 == m_acquired ;
00581 }
00583
00586 public:
00587 bool_type is_valid() const
00588 {
00589 if(m_refCount < 1)
00590 {
00591 #ifdef STLSOFT_UNITTEST
00592 fprintf(err, "invalid reference count (%ld) \n", m_refCount);
00593 #endif
00594 return false;
00595 }
00596
00597 if( NULL == m_enumerator &&
00598 0 == m_quanta)
00599 {
00600 if(0 != m_acquired)
00601 {
00602 #ifdef STLSOFT_UNITTEST
00603 fprintf(err, "m_acquired == %lu when m_quanta == 0\n", m_acquired);
00604 #endif
00605 return false;
00606 }
00607 if(0 != m_current)
00608 {
00609 #ifdef STLSOFT_UNITTEST
00610 fprintf(err, "m_current == %lu when m_quanta == 0\n", m_current);
00611 #endif
00612 return false;
00613 }
00614 if(0 != m_quanta)
00615 {
00616 return false;
00617 }
00618 }
00619 else
00620 {
00621 if(m_acquired < m_current)
00622 {
00623 #ifdef STLSOFT_UNITTEST
00624 fprintf(err, "m_acquired (%lu) not less than m_current (%lu)\n", m_acquired, m_current);
00625 #endif
00626 return false;
00627 }
00628 if(m_quanta < m_current)
00629 {
00630 #ifdef STLSOFT_UNITTEST
00631 fprintf(err, "m_quanta (%lu) not less than m_current (%lu)\n", m_quanta, m_current);
00632 #endif
00633 return false;
00634 }
00635 if(m_quanta < m_acquired)
00636 {
00637 #ifdef STLSOFT_UNITTEST
00638 fprintf(err, "m_quanta (%lu) not less than m_acquired (%lu)\n", m_quanta, m_acquired);
00639 #endif
00640 return false;
00641 }
00642 }
00643
00644 return true;
00645 }
00647
00650 private:
00651 void acquire_next_() stlsoft_throw_0()
00652 {
00653
00654 COMSTL_ASSERT(0 == m_current);
00655
00656 ULONG cFetched = 0;
00657
00658 m_enumerator->Next(m_quanta, &m_values[0], &cFetched);
00659
00660 m_acquired = cFetched;
00661 m_previousBlockTotal += cFetched;
00662
00663
00664
00665
00666 }
00667
00668 void clear_elements_() stlsoft_throw_0()
00669 {
00670 COMSTL_ASSERT(m_acquired <= STLSOFT_NUM_ELEMENTS(m_values));
00671
00672 typedef ss_typename_type_k value_policy_type::clear_element clear_t;
00673
00674 comstl_ns_qual_std(for_each)(&m_values[0], &m_values[0] + m_acquired, clear_t());
00675 }
00676
00677 void init_elements_(size_type n) stlsoft_throw_0()
00678 {
00679 COMSTL_ASSERT(n <= STLSOFT_NUM_ELEMENTS(m_values));
00680
00681 typedef ss_typename_type_k value_policy_type::init_element init_t;
00682
00683 comstl_ns_qual_std(for_each)(&m_values[0], &m_values[0] + n, init_t());
00684 }
00686
00689 private:
00690 interface_type* m_enumerator;
00691 size_type m_acquired;
00692 size_type m_current;
00693 ULONG const m_quanta;
00694 value_type m_values[retrievalQuanta];
00695 long m_refCount;
00696 size_type m_previousBlockTotal;
00698
00699
00700 private:
00701 enumeration_context(class_type const&);
00702 class_type& operator =(class_type const&);
00703 };
00704
00705
00708 private:
00709 friend class enumerator_sequence<I, V, VP, R, CP, Q>;
00710
00712 iterator(interface_type* i, size_type quanta, bool_type &bFirst)
00713 : m_ctxt(new enumeration_context(i, quanta, bFirst))
00714 {
00715 bFirst = false;
00716
00717 COMSTL_ASSERT(is_valid());
00718 }
00719 public:
00721 iterator()
00722 : m_ctxt(NULL)
00723 {
00724 COMSTL_ASSERT(is_valid());
00725 }
00727 iterator(class_type const& rhs)
00728 : m_ctxt(enumeration_context::make_clone(rhs.m_ctxt))
00729 {
00730 COMSTL_ASSERT(is_valid());
00731 }
00732
00734 ~iterator() stlsoft_throw_0()
00735 {
00736 COMSTL_ASSERT(is_valid());
00737
00738 if(NULL != m_ctxt)
00739 {
00740 m_ctxt->Release();
00741 }
00742 }
00743
00744 class_type& operator =(class_type const& rhs)
00745 {
00746 enumeration_context *newCtxt = enumeration_context::make_clone(rhs.m_ctxt);
00747
00748 if(NULL != m_ctxt)
00749 {
00750 m_ctxt->Release();
00751 }
00752
00753 m_ctxt = newCtxt;
00754
00755 return *this;
00756 }
00758
00761 public:
00763 class_type& operator ++()
00764 {
00765 COMSTL_ASSERT(is_valid());
00766
00767 m_ctxt->advance();
00768
00769 COMSTL_ASSERT(is_valid());
00770
00771 return *this;
00772 }
00773
00775 class_type operator ++(int)
00776 {
00777 COMSTL_ASSERT(is_valid());
00778
00779 class_type r(*this);
00780
00781 operator ++();
00782
00783 COMSTL_ASSERT(is_valid());
00784
00785 return r;
00786 }
00787
00789 reference operator *()
00790 {
00791 COMSTL_ASSERT(is_valid());
00792 COMSTL_MESSAGE_ASSERT("Attempting to dereference an invalid iterator", (NULL != m_ctxt && !m_ctxt->empty()));
00793
00794 return m_ctxt->current();
00795 }
00796
00798 pointer operator ->()
00799 {
00800 COMSTL_ASSERT(is_valid());
00801 COMSTL_MESSAGE_ASSERT("Attempting to dereference an invalid iterator", (NULL != m_ctxt && !m_ctxt->empty()));
00802
00803 return &m_ctxt->current();
00804 }
00805
00806 private:
00807 static bool_type equal_(class_type const& lhs, class_type const& rhs, stlsoft_ns_qual_std(input_iterator_tag))
00808 {
00809
00810 return lhs.is_end_point() && rhs.is_end_point();
00811 }
00812 static bool_type equal_(class_type const& lhs, class_type const& rhs, stlsoft_ns_qual_std(forward_iterator_tag))
00813 {
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823 if(lhs.is_end_point())
00824 {
00825 return rhs.is_end_point();
00826 }
00827 else
00828 {
00829 if(rhs.is_end_point())
00830 {
00831 return false;
00832 }
00833 else
00834 {
00835 COMSTL_ASSERT(NULL != lhs.m_ctxt);
00836 COMSTL_ASSERT(NULL != rhs.m_ctxt);
00837
00838 return lhs.m_ctxt->index() == rhs.m_ctxt->index();
00839 }
00840 }
00841 }
00842 public:
00843
00845 bool_type equal(class_type const& rhs) const
00846 {
00847 COMSTL_ASSERT(is_valid());
00848
00849 return class_type::equal_(*this, rhs, iterator_tag_type());
00850 }
00852 bool_type operator == (class_type const& rhs) const
00853 {
00854 COMSTL_ASSERT(is_valid());
00855
00856 return this->equal(rhs);
00857 }
00859 bool_type operator != (class_type const& rhs) const
00860 {
00861 COMSTL_ASSERT(is_valid());
00862
00863 return !this->equal(rhs);
00864 }
00866
00869 private:
00870 bool_type is_valid() const
00871 {
00872 return (NULL == m_ctxt) || m_ctxt->is_valid();
00873 }
00875
00878 private:
00879 bool_type is_end_point() const
00880 {
00881 return NULL == m_ctxt || m_ctxt->empty();
00882 }
00884
00887 private:
00888 enumeration_context *m_ctxt;
00890 };
00892 typedef iterator const_iterator;
00893
00894 public:
00905 iterator begin() const
00906 {
00907 COMSTL_ASSERT(is_valid());
00908
00909 interface_type* en = NULL;
00910
00911 if(NULL != m_enumerator)
00912 {
00913 en = m_enumerator;
00914 }
00915 else
00916 {
00917 if(!m_bFirst)
00918 {
00919 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00920 STLSOFT_THROW_X(clone_failure(E_NOTIMPL));
00921 #else
00922 return end();
00923 #endif
00924 }
00925 else
00926 {
00927 en = m_root;
00928 }
00929 }
00930
00931 COMSTL_ASSERT(NULL != en);
00932
00933 return iterator(en, m_quanta, m_bFirst);
00934 }
00938 iterator end() const
00939 {
00940 COMSTL_ASSERT(is_valid());
00941
00942 return iterator();
00943 }
00945
00948 public:
00949 static size_type quanta()
00950 {
00951 return retrievalQuanta;
00952 }
00954
00957 private:
00958 bool_type is_valid() const
00959 {
00960 if(NULL == m_root)
00961 {
00962 #ifdef STLSOFT_UNITTEST
00963 fprintf(err, "enumerator_sequence: m_root is NULL\n");
00964
00965 COMSTL_ASSERT(0);
00966 #endif
00967
00968 return false;
00969 }
00970
00971 return true;
00972 }
00974
00975
00976 private:
00977 static size_type validate_quanta_(size_type quanta)
00978 {
00979 COMSTL_MESSAGE_ASSERT("Cannot set a quantum that exceeds the value specified in the template specialisation", quanta <= retrievalQuanta);
00980
00981 if( 0 == quanta ||
00982 quanta > retrievalQuanta)
00983 {
00984 quanta = retrievalQuanta;
00985 }
00986
00987 return quanta;
00988 }
00989
00990
00991 private:
00992 interface_type* m_root;
00993 interface_type* m_enumerator;
00994 size_type const m_quanta;
00995 ss_mutable_k bool_type m_bFirst;
00996
00997
00998 private:
00999 enumerator_sequence(class_type const&);
01000 class_type const& operator =(class_type const&);
01001 };
01002
01004
01005
01006 #ifdef STLSOFT_COMPILER_IS_BORLAND
01007 # undef retrievalQuanta
01008 #endif
01009
01011
01012
01013 #ifdef STLSOFT_UNITTEST
01014 # include "./unittest/enumerator_sequence_unittest_.h"
01015 #endif
01016
01017
01018
01019 #ifndef _COMSTL_NO_NAMESPACE
01020 # if defined(_STLSOFT_NO_NAMESPACE) || \
01021 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
01022 }
01023 # else
01024 }
01025 }
01026 # endif
01027 #endif
01028
01029
01030
01031 #endif
01032
01033