table_index.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt 00004 or a copy at http://stlab.adobe.com/licenses.html) 00005 */ 00006 00007 /*************************************************************************************************/ 00008 00009 #ifndef ADOBE_TABLE_INDEX_HPP 00010 #define ADOBE_TABLE_INDEX_HPP 00011 00012 /*************************************************************************************************/ 00013 00014 #include <adobe/config.hpp> 00015 00016 #include <functional> 00017 #include <stdexcept> 00018 #include <vector> 00019 00020 #include <boost/operators.hpp> 00021 #include <boost/iterator/indirect_iterator.hpp> 00022 #include <boost/iterator/transform_iterator.hpp> 00023 #include <boost/next_prior.hpp> 00024 #include <boost/type_traits/remove_reference.hpp> 00025 00026 #include <adobe/algorithm/count.hpp> 00027 #include <adobe/algorithm/equal_range.hpp> 00028 #include <adobe/algorithm/lower_bound.hpp> 00029 #include <adobe/algorithm/sort.hpp> 00030 #include <adobe/algorithm/unique.hpp> 00031 #include <adobe/algorithm/upper_bound.hpp> 00032 00033 #include <adobe/closed_hash.hpp> 00034 #include <adobe/functional.hpp> 00035 00036 /*************************************************************************************************/ 00037 00038 namespace adobe { 00039 00040 /*************************************************************************************************/ 00041 00531 template < typename T, // models Regular 00532 typename H = boost::hash<T>, // models UnaryFunction key_type -> size_t 00533 typename C = std::equal_to<T>, // models EqualityComparison(key_type, key_type) 00534 typename P = identity<T> > // models UnaryFunction T -> key_type 00535 class hash_index 00536 { 00537 public: 00538 typedef T value_type; 00539 typedef P key_function_type; 00540 00541 typedef typename boost::remove_reference<typename key_function_type::result_type>::type 00542 key_type; 00543 00544 typedef H hasher; 00545 typedef C key_equal; 00546 typedef value_type* pointer; 00547 typedef const value_type* const_pointer; 00548 typedef value_type& reference; 00549 typedef const value_type& const_reference; 00550 typedef std::size_t size_type; 00551 typedef std::ptrdiff_t difference_type; 00552 00553 typedef unary_compose< key_function_type, indirect<value_type> > indirect_key_function_type; 00554 00555 typedef closed_hash_set<pointer, indirect_key_function_type, hasher, key_equal> 00556 index_type; 00557 00558 typedef boost::indirect_iterator<typename index_type::iterator> iterator; 00559 typedef boost::indirect_iterator<typename index_type::const_iterator> const_iterator; 00560 typedef std::reverse_iterator<iterator> reverse_iterator; 00561 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00562 00563 /* 00564 REVISIT (sparent@adobe.com) : This is a very limited set of constructors - need to have a 00565 general strategy for which constructors to provide. 00566 */ 00567 00568 00569 hash_index() { } 00570 00571 /* 00572 NOTE: The constructor is templatized so things like mem_fun are not necessary. 00573 */ 00574 00575 template <typename F> // F is convertible to key_function_type 00576 hash_index(hasher hf, key_equal eq, F kf) : 00577 index_m(0, hf, eq, compose(key_function_type(kf), indirect<value_type>())) 00578 { } 00579 00580 //allocator_type get_allocator() const; 00581 size_type max_size() const { return index_m.max_size(); } 00582 00583 size_type size() const { return index_m.size(); } 00584 bool empty() const { return index_m.empty(); } 00585 size_type capacity() const { return index_m.capacity(); } 00586 00587 void reserve(size_type n) { index_m.reserve(); } 00588 00589 iterator begin() { return iterator(index_m.begin()); } 00590 iterator end() { return iterator(index_m.end()); } 00591 00592 const_iterator begin() const { return const_iterator(index_m.begin()); } 00593 const_iterator end() const { return const_iterator(index_m.end()); } 00594 00595 reverse_iterator rbegin() { return reverse_iterator(index_m.rbegin()); } 00596 reverse_iterator rend() { return reverse_iterator(index_m.rend()); } 00597 00598 const_reverse_iterator rbegin() const { return const_reverse_iterator(index_m.rbegin()); } 00599 const_reverse_iterator rend() const { return const_reverse_iterator(index_m.rend()); } 00600 00601 std::pair<iterator, bool> insert(value_type& x) 00602 { 00603 std::pair<typename index_type::iterator, bool> result = index_m.insert(&x); 00604 return std::make_pair(iterator(result.first), result.second); 00605 } 00606 00607 template <typename I> 00608 void insert(I f, I l) 00609 { 00610 index_m.insert( boost::make_transform_iterator(f, pointer_to<value_type>()), 00611 boost::make_transform_iterator(l, pointer_to<value_type>())); 00612 } 00613 00614 iterator insert(iterator i, value_type& x) 00615 { 00616 return iterator(index_m.insert(i, &x)); 00617 } 00618 00619 iterator erase(iterator i) { return index_m.erase(i.base()); } 00620 size_type erase(const key_type& x) { return index_m.erase(x); } 00621 00622 void clear() { index_m.clear(); } 00623 00624 index_type& index() { return index_m; } 00625 const index_type& index() const { return index_m; } 00626 00627 iterator find(const key_type& x) { return iterator(index_m.find(x)); } 00628 const_iterator find(const key_type& x) const { return const_iterator(index_m.find(x)); } 00629 size_type count(const key_type& x) const { return index_m.count(x); } 00630 00631 iterator lower_bound(const key_type& x) { return iterator(index_m.lower_bound()); } 00632 const_iterator lower_bound(const key_type& x) const 00633 { return const_iterator(index_m.lower_bound()); } 00634 iterator upper_bound(const key_type& x) { return iterator(index_m.upper_bound()); } 00635 const_iterator upper_bound(const key_type& x) const 00636 { return const_iterator(index_m.upper_bound()); } 00637 00638 std::pair<iterator, iterator> equal_range(const key_type& x) 00639 { 00640 std::pair<typename index_type::iterator, typename index_type::iterator> result = index_m.equal_range(x); 00641 return std::make_pair(iterator(result.first), iterator(result.second)); 00642 } 00643 std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const 00644 { 00645 std::pair<typename index_type::const_iterator, typename index_type::const_iterator> result 00646 = index_m.equal_range(x); 00647 00648 return std::make_pair(const_iterator(result.first), const_iterator(result.second)); 00649 } 00650 00651 key_function_type key_function() const { return index_m.key_function(); } 00652 hasher hash_function() const { return index_m.hash_function(); } 00653 key_equal key_eq() const { return index_m.key_eq(); } 00654 00655 friend void swap(hash_index& x, hash_index& y) 00656 { 00657 swap(x.index_m, y.index_m); 00658 } 00659 private: 00660 00661 index_type index_m; 00662 }; 00663 00664 /*************************************************************************************************/ 00665 00666 template < typename Key, // models Regular 00667 typename T, // models Regular 00668 typename Transform = mem_data_t<T, const Key>, // models UnaryFunction Key(T) 00669 typename Compare = std::less<Key> // models BinaryFunction bool(Key, Key) 00670 > 00671 class table_index 00672 { 00673 00674 public: 00675 typedef typename std::vector<T*> index_type; 00676 typedef Transform transform_type; 00677 00678 typedef Key key_type; 00679 typedef T value_type; 00680 typedef Compare key_compare; // Revisit? 00681 // typedef Allocator allocator_type; 00682 typedef T& reference; 00683 typedef const T& const_reference; 00684 typedef typename index_type::size_type size_type; 00685 typedef typename index_type::difference_type difference_type; 00686 typedef T* pointer; 00687 typedef const T* const_pointer; 00688 00689 typedef boost::indirect_iterator<typename index_type::iterator> iterator; 00690 typedef boost::indirect_iterator<typename index_type::const_iterator> const_iterator; 00691 typedef std::reverse_iterator<iterator> reverse_iterator; 00692 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00693 00694 template <class TransformPrimitive> 00695 explicit table_index(TransformPrimitive transform, const key_compare& compare = key_compare()) : 00696 transform_m(transform), 00697 compare_m(compare) 00698 { } 00699 explicit table_index(const transform_type&, const key_compare& = key_compare()); 00700 00701 template <typename InputIterator, typename TransformPrimitive> 00702 table_index( InputIterator first, 00703 InputIterator last, 00704 TransformPrimitive transform, 00705 const key_compare& compare = key_compare()) : 00706 transform_m(transform), 00707 compare_m(compare) 00708 { 00709 insert(begin(), first, last); 00710 } 00711 00712 //allocator_type get_allocator() const; 00713 size_type max_size() const; 00714 00715 size_type size() const; 00716 bool empty() const; 00717 00718 iterator begin(); 00719 const_iterator begin() const; 00720 iterator end(); 00721 const_iterator end() const; 00722 00723 reverse_iterator rbegin(); 00724 const_reverse_iterator rbegin() const; 00725 reverse_iterator rend(); 00726 const_reverse_iterator rend() const; 00727 00728 const_reference at(size_type n) const; 00729 reference at(size_type n); 00730 00731 reference front(); 00732 const_reference front() const; 00733 reference back(); 00734 const_reference back() const; 00735 00736 void push_back(value_type&); 00737 void pop_back(); 00738 00739 iterator insert(iterator, value_type&); 00740 template <class InputIterator> 00741 void insert(iterator position, InputIterator first, InputIterator last); 00742 00743 iterator erase(iterator location); 00744 iterator erase(iterator first, iterator last); 00745 void clear(); 00746 00747 index_type& index(); 00748 const index_type& index() const; 00749 00750 /* 00751 REVISIT (sparent) : If we wanted to allow sort() and unique() - and other algoriths to 00752 operate directly on the index rather than being built in, what would be required of the 00753 index interface? 00754 */ 00755 00756 void sort(); 00757 00758 // Operations on a sorted index. 00759 00760 void unique(); 00761 00762 reference operator[](const key_type&); 00763 const_reference operator[](const key_type&) const; 00764 00765 iterator find(const key_type& x); 00766 const_iterator find(const key_type& x) const; 00767 size_type count(const key_type& x) const; 00768 00769 iterator lower_bound(const key_type& x); 00770 const_iterator lower_bound(const key_type& x) const; 00771 iterator upper_bound(const key_type& x); 00772 const_iterator upper_bound(const key_type& x) const; 00773 00774 std::pair<iterator, iterator> equal_range(const key_type& x); 00775 std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const; 00776 00777 transform_type transform() const { return transform_m; } 00778 00779 friend void swap(table_index& x, table_index& y) 00780 { 00781 swap(x.transform_m, y.transform_m); 00782 swap(x.compare_m, y.compare_m); 00783 swap(x.index_m, y.index_m); 00784 } 00785 private: 00786 00787 #ifndef ADOBE_NO_DOCUMENTATION 00788 struct indirect_compare_t : std::binary_function<pointer, pointer, bool> 00789 { 00790 typedef bool result_type; 00791 00792 indirect_compare_t(transform_type& transform, const key_compare& compare) : 00793 transform_m(transform), 00794 compare_m(compare) 00795 { } 00796 00797 bool operator () (pointer x, pointer y) const 00798 { 00799 return compare_m(transform_m(*x), transform_m(*y)); 00800 } 00801 00802 private: 00803 transform_type transform_m; /* REVISIT (sparent) : want reference here? */ 00804 key_compare compare_m; 00805 }; 00806 00807 #endif 00808 00809 transform_type transform_m; 00810 key_compare compare_m; 00811 index_type index_m; 00812 }; 00813 00814 /*************************************************************************************************/ 00815 00816 template <class Key, class T, class Compare, class Transform> 00817 table_index<Key, T, Compare, Transform>::table_index( const transform_type& transform, 00818 const key_compare& compare) : 00819 transform_m(transform), 00820 compare_m(compare) 00821 { } 00822 00823 /*************************************************************************************************/ 00824 00825 template <class Key, class T, class Compare, class Transform> 00826 inline typename table_index<Key, T, Compare, Transform>::iterator 00827 table_index<Key, T, Compare, Transform>::begin() 00828 { 00829 return iterator(index_m.begin()); 00830 } 00831 00832 /*************************************************************************************************/ 00833 00834 template <class Key, class T, class Compare, class Transform> 00835 inline typename table_index<Key, T, Compare, Transform>::const_iterator 00836 table_index<Key, T, Compare, Transform>::begin() const 00837 { 00838 return const_iterator(index_m.begin()); 00839 } 00840 00841 /*************************************************************************************************/ 00842 00843 template <class Key, class T, class Compare, class Transform> 00844 inline typename table_index<Key, T, Compare, Transform>::iterator 00845 table_index<Key, T, Compare, Transform>::end() 00846 { 00847 return iterator(index_m.end()); 00848 } 00849 00850 /*************************************************************************************************/ 00851 00852 template <class Key, class T, class Compare, class Transform> 00853 inline typename table_index<Key, T, Compare, Transform>::const_iterator 00854 table_index<Key, T, Compare, Transform>::end() const 00855 { 00856 return const_iterator(index_m.end()); 00857 } 00858 00859 /*************************************************************************************************/ 00860 00861 template <class Key, class T, class Compare, class Transform> 00862 inline typename table_index<Key, T, Compare, Transform>::reverse_iterator 00863 table_index<Key, T, Compare, Transform>::rbegin() 00864 { 00865 return reverse_iterator(index_m.rbegin()); 00866 } 00867 00868 /*************************************************************************************************/ 00869 00870 template <class Key, class T, class Compare, class Transform> 00871 inline typename table_index<Key, T, Compare, Transform>::const_reverse_iterator 00872 table_index<Key, T, Compare, Transform>::rbegin() const 00873 { 00874 return const_reverse_iterator(index_m.rbegin()); 00875 } 00876 00877 /*************************************************************************************************/ 00878 00879 template <class Key, class T, class Compare, class Transform> 00880 inline typename table_index<Key, T, Compare, Transform>::reverse_iterator 00881 table_index<Key, T, Compare, Transform>::rend() 00882 { 00883 return reverse_iterator(index_m.rend()); 00884 } 00885 00886 /*************************************************************************************************/ 00887 00888 template <class Key, class T, class Compare, class Transform> 00889 inline typename table_index<Key, T, Compare, Transform>::const_reverse_iterator 00890 table_index<Key, T, Compare, Transform>::rend() const 00891 { 00892 return reverse_iterator(index_m.rend()); 00893 } 00894 00895 /*************************************************************************************************/ 00896 00897 template <class Key, class T, class Compare, class Transform> 00898 inline typename table_index<Key, T, Compare, Transform>::size_type 00899 table_index<Key, T, Compare, Transform>::max_size() const 00900 { 00901 return index_m.max_size(); 00902 } 00903 00904 /*************************************************************************************************/ 00905 00906 template <class Key, class T, class Compare, class Transform> 00907 inline typename table_index<Key, T, Compare, Transform>::size_type 00908 table_index<Key, T, Compare, Transform>::size() const 00909 { 00910 return index_m.size(); 00911 } 00912 00913 /*************************************************************************************************/ 00914 00915 template <class Key, class T, class Compare, class Transform> 00916 inline bool table_index<Key, T, Compare, Transform>::empty() const 00917 { 00918 return index_m.empty(); 00919 } 00920 00921 /*************************************************************************************************/ 00922 00923 template <class Key, class T, class Compare, class Transform> 00924 inline void table_index<Key, T, Compare, Transform>::push_back(value_type& x) 00925 { 00926 index_m.push_back(&x); 00927 } 00928 00929 /*************************************************************************************************/ 00930 00931 template <class Key, class T, class Compare, class Transform> 00932 inline void table_index<Key, T, Compare, Transform>::pop_back() 00933 { 00934 index_m.pop_back(); 00935 } 00936 00937 /*************************************************************************************************/ 00938 00939 template <class Key, class T, class Compare, class Transform> 00940 inline typename table_index<Key, T, Compare, Transform>::iterator 00941 table_index<Key, T, Compare, Transform>::insert(iterator position, value_type& x) 00942 { 00943 return index_m.insert(position, &x); 00944 } 00945 00946 /*************************************************************************************************/ 00947 00948 /* 00949 REVISIT (sparent) : We should be able to greatly improve the table_index class - this function 00950 in particular could be much more efficient. 00951 */ 00952 00953 template <class Key, class T, class Compare, class Transform> 00954 template <class InputIterator> 00955 inline void table_index<Key, T, Compare, Transform>::insert(iterator position, InputIterator first, InputIterator last) 00956 { 00957 typename index_type::iterator iter = position.base(); 00958 00959 while (first != last) { 00960 iter = index_m.insert(iter, &*first); 00961 ++iter; 00962 ++first; 00963 } 00964 } 00965 00966 /*************************************************************************************************/ 00967 00968 template <class Key, class T, class Compare, class Transform> 00969 inline typename table_index<Key, T, Compare, Transform>::iterator 00970 table_index<Key, T, Compare, Transform>::erase(iterator position) 00971 { 00972 return index_m.erase(position.base()); 00973 } 00974 00975 /*************************************************************************************************/ 00976 00977 template <class Key, class T, class Compare, class Transform> 00978 inline typename table_index<Key, T, Compare, Transform>::iterator 00979 table_index<Key, T, Compare, Transform>::erase(iterator first, iterator last) 00980 { 00981 return index_m.erase(first.base(), last.base()); 00982 } 00983 00984 /*************************************************************************************************/ 00985 00986 template <class Key, class T, class Compare, class Transform> 00987 inline void table_index<Key, T, Compare, Transform>::clear() 00988 { 00989 index_m.clear(); 00990 } 00991 00992 /*************************************************************************************************/ 00993 00994 template <class Key, class T, class Compare, class Transform> 00995 void table_index<Key, T, Compare, Transform>::sort() 00996 { 00997 adobe::sort(index_m, indirect_compare_t(transform_m, compare_m)); 00998 } 00999 01000 /*************************************************************************************************/ 01001 01002 template <class Key, class T, class Compare, class Transform> 01003 void table_index<Key, T, Compare, Transform>::unique() 01004 { 01005 typename index_type::iterator i (adobe::unique(index_m, indirect_compare_t(transform_m, compare_m))); 01006 index_m.erase(i, index_m.end()); 01007 } 01008 01009 /*************************************************************************************************/ 01010 01011 template <class Key, class T, class Compare, class Transform> 01012 inline typename table_index<Key, T, Compare, Transform>::reference 01013 table_index<Key, T, Compare, Transform>::at(const size_type n) 01014 { 01015 return *index_m.at(n); 01016 } 01017 01018 /*************************************************************************************************/ 01019 01020 template <class Key, class T, class Compare, class Transform> 01021 inline typename table_index<Key, T, Compare, Transform>::const_reference 01022 table_index<Key, T, Compare, Transform>::at(const size_type n) const 01023 { 01024 return *index_m.at(n); 01025 } 01026 01027 /*************************************************************************************************/ 01028 01029 template <class Key, class T, class Compare, class Transform> 01030 inline typename table_index<Key, T, Compare, Transform>::reference 01031 table_index<Key, T, Compare, Transform>::operator [] (const key_type& key) 01032 { 01033 iterator iter (find(key)); 01034 01035 if (iter == end()) 01036 throw std::range_error("Key not present in table."); 01037 01038 return *iter; 01039 } 01040 01041 /*************************************************************************************************/ 01042 01043 template <class Key, class T, class Compare, class Transform> 01044 inline typename table_index<Key, T, Compare, Transform>::const_reference 01045 table_index<Key, T, Compare, Transform>::operator [] (const key_type& key) const 01046 { 01047 const_iterator iter(find(key)); 01048 01049 if (iter == end()) 01050 throw std::range_error("Key not present in table."); 01051 01052 return *iter; 01053 } 01054 01055 /*************************************************************************************************/ 01056 01057 template <class Key, class T, class Compare, class Transform> 01058 inline typename table_index<Key, T, Compare, Transform>::iterator 01059 table_index<Key, T, Compare, Transform>::find(const key_type& key) 01060 { 01061 typename index_type::iterator iter = lower_bound(key).base(); 01062 01063 if (iter != index_m.end() && transform_m(**iter) != key) 01064 iter = index_m.end(); 01065 01066 return iter; 01067 } 01068 01069 /*************************************************************************************************/ 01070 01071 template <class Key, class T, class Compare, class Transform> 01072 inline typename table_index<Key, T, Compare, Transform>::const_iterator 01073 table_index<Key, T, Compare, Transform>::find(const key_type& key) const 01074 { 01075 typename index_type::const_iterator iter = lower_bound(key).base(); 01076 01077 if (iter != index_m.end() && transform_m(**iter) != key) 01078 iter = index_m.end(); 01079 01080 return iter; 01081 } 01082 01083 /*************************************************************************************************/ 01084 01085 template <class Key, class T, class Compare, class Transform> 01086 inline typename table_index<Key, T, Compare, Transform>::size_type 01087 table_index<Key, T, Compare, Transform>::count(const key_type& key) const 01088 { 01089 return adobe::count_if(index_m, bound_predicate_t(key, transform_m, compare_m)); 01090 } 01091 01092 /*************************************************************************************************/ 01093 01094 template <class Key, class T, class Compare, class Transform> 01095 inline typename table_index<Key, T, Compare, Transform>::iterator 01096 table_index<Key, T, Compare, Transform>::lower_bound(const key_type& key) 01097 { 01098 return adobe::lower_bound(index_m, key, compare_m, 01099 boost::bind(transform_m, bind(indirect<value_type>(), _1))); 01100 } 01101 01102 /*************************************************************************************************/ 01103 01104 template <class Key, class T, class Compare, class Transform> 01105 inline typename table_index<Key, T, Compare, Transform>::const_iterator 01106 table_index<Key, T, Compare, Transform>::lower_bound(const key_type& key) const 01107 { 01108 return adobe::lower_bound(index_m, key, compare_m, 01109 boost::bind(transform_m, bind(indirect<value_type>(), _1))); 01110 } 01111 01112 /*************************************************************************************************/ 01113 01114 template <class Key, class T, class Compare, class Transform> 01115 inline typename table_index<Key, T, Compare, Transform>::iterator 01116 table_index<Key, T, Compare, Transform>::upper_bound(const key_type& key) 01117 { 01118 return adobe::upper_bound(index_m, key, compare_m, 01119 boost::bind(transform_m, bind(indirect<value_type>(), _1))); 01120 } 01121 01122 /*************************************************************************************************/ 01123 01124 template <class Key, class T, class Compare, class Transform> 01125 inline typename table_index<Key, T, Compare, Transform>::const_iterator 01126 table_index<Key, T, Compare, Transform>::upper_bound(const key_type& key) const 01127 { 01128 return adobe::upper_bound(index_m, key, compare_m, 01129 boost::bind(transform_m, bind(indirect<value_type>(), _1))); 01130 } 01131 01132 /*************************************************************************************************/ 01133 01134 template <class Key, class T, class Compare, class Transform> 01135 inline std::pair< typename table_index<Key, T, Compare, Transform>::iterator, 01136 typename table_index<Key, T, Compare, Transform>::iterator> 01137 table_index<Key, T, Compare, Transform>::equal_range(const key_type& key) 01138 { 01139 return adobe::equal_range(index_m, key, compare_m, 01140 boost::bind(transform_m, bind(indirect<value_type>(), _1))); 01141 } 01142 01143 /*************************************************************************************************/ 01144 01145 template <class Key, class T, class Compare, class Transform> 01146 inline std::pair< typename table_index<Key, T, Compare, Transform>::const_iterator, 01147 typename table_index<Key, T, Compare, Transform>::const_iterator> 01148 table_index<Key, T, Compare, Transform>::equal_range(const key_type& key) const 01149 { 01150 return adobe::equal_range(index_m, key, compare_m, 01151 boost::bind(transform_m, bind(indirect<value_type>(), _1))); 01152 } 01153 01154 /*************************************************************************************************/ 01155 01156 template <class Key, class T, class Compare, class Transform> 01157 inline typename table_index<Key, T, Compare, Transform>::index_type& 01158 table_index<Key, T, Compare, Transform>::index() 01159 { 01160 return index_m; 01161 } 01162 01163 /*************************************************************************************************/ 01164 01165 template <class Key, class T, class Compare, class Transform> 01166 inline const typename table_index<Key, T, Compare, Transform>::index_type& 01167 table_index<Key, T, Compare, Transform>::index() const 01168 { 01169 return index_m; 01170 } 01171 01172 /*************************************************************************************************/ 01173 01174 } // namespace adobe 01175 01176 /*************************************************************************************************/ 01177 01178 #endif 01179 01180 /*************************************************************************************************/ |