closed_hash.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_CLOSED_HASH_HPP 00010 #define ADOBE_CLOSED_HASH_HPP 00011 00012 /*************************************************************************************************/ 00013 00014 #include <adobe/config.hpp> 00015 00016 #include <adobe/closed_hash_fwd.hpp> 00017 00018 #include <climits> 00019 #include <cstddef> 00020 #include <limits> 00021 00022 #include <boost/compressed_pair.hpp> 00023 #include <boost/functional/hash.hpp> 00024 #include <boost/iterator/iterator_adaptor.hpp> 00025 #include <boost/iterator/iterator_facade.hpp> 00026 #include <boost/static_assert.hpp> 00027 #include <boost/type_traits/has_nothrow_constructor.hpp> 00028 #include <boost/type_traits/remove_reference.hpp> 00029 #include <boost/operators.hpp> 00030 #include <boost/next_prior.hpp> 00031 00032 #include <adobe/algorithm/lower_bound.hpp> 00033 #include <adobe/conversion.hpp> 00034 #include <adobe/cstdint.hpp> 00035 #include <adobe/empty.hpp> 00036 #include <adobe/functional.hpp> 00037 #include <adobe/iterator/set_next.hpp> 00038 #include <adobe/memory.hpp> 00039 #include <adobe/move.hpp> 00040 #include <adobe/utility.hpp> 00041 00042 #include <adobe/implementation/swap.hpp> 00043 00044 /*************************************************************************************************/ 00045 00046 namespace adobe { 00047 00048 /*************************************************************************************************/ 00049 00050 namespace implementation { 00051 00052 /*************************************************************************************************/ 00053 00054 template <typename T, typename V> // V is value_type(T) const qualified 00055 class closed_hash_iterator : public boost::iterator_facade<closed_hash_iterator<T, V>, V, 00056 std::bidirectional_iterator_tag> 00057 { 00058 typedef boost::iterator_facade<closed_hash_iterator<T, V>, V, 00059 std::bidirectional_iterator_tag> inherited_t; 00060 00061 typedef typename T::node_t node_t; 00062 public: 00063 typedef typename inherited_t::reference reference; 00064 typedef typename inherited_t::difference_type difference_type; 00065 typedef typename inherited_t::value_type value_type; 00066 00067 closed_hash_iterator() : node_m(0) { } 00068 00069 template <typename O> 00070 closed_hash_iterator(const closed_hash_iterator<T, O>& x) : node_m(x.node_m) { } 00071 00072 public: 00073 /* 00074 REVISIT (sparent@adobe.com) : node_m should be private but 00075 "gcc version 4.0.1 (Apple Inc. build 5465)" doesn't like it. 00076 */ 00077 00078 node_t* node_m; 00079 00080 private: 00081 00082 reference dereference() const { return node_m->value_m; } 00083 void increment() { node_m = node_m->next(); } 00084 void decrement() { node_m = node_m->prior(); } 00085 00086 template< typename O> 00087 bool equal(const closed_hash_iterator<T, O>& y) const { return node_m == y.node_m; } 00088 00089 std::size_t state() const { return node_m->state(); } 00090 void set_state(std::size_t x) { return node_m->set_state(x); } 00091 00092 explicit closed_hash_iterator(node_t* node) : node_m(node) { } 00093 00094 friend class version_1::closed_hash_set<value_type, typename T::key_transform, typename T::hasher, 00095 typename T::key_equal, typename T::allocator_type>; 00096 friend class boost::iterator_core_access; 00097 friend struct unsafe::set_next_fn<closed_hash_iterator>; 00098 }; 00099 00100 /*************************************************************************************************/ 00101 00102 } // namespace implementation 00103 00104 /*************************************************************************************************/ 00105 00106 namespace unsafe { 00107 00108 template <typename T, typename V> 00109 struct set_next_fn<implementation::closed_hash_iterator<T, V> > 00110 { 00111 typedef typename implementation::closed_hash_iterator<T, V> iterator; 00112 00113 void operator()(iterator x, iterator y) const 00114 { set_next(*x.node_m, *y.node_m); } 00115 }; 00116 00117 } // namespace unsafe 00118 00119 /*************************************************************************************************/ 00120 00121 #ifndef ADOBE_NO_DOCUMENTATION 00122 00123 namespace version_1 { 00124 00125 #endif 00126 00127 /*************************************************************************************************/ 00128 00152 template< typename T, 00153 typename KeyTransform, 00154 typename Hash, 00155 typename Pred, 00156 typename A> 00157 class closed_hash_set : boost::equality_comparable<closed_hash_set<T, KeyTransform, Hash, Pred, A>, 00158 closed_hash_set<T, KeyTransform, Hash, Pred, A>, 00159 empty_base<closed_hash_set<T, KeyTransform, Hash, Pred, A> > > 00160 { 00161 public: 00162 typedef KeyTransform key_transform; 00163 00164 typedef typename boost::remove_reference<typename key_transform::result_type>::type 00165 key_type; 00166 00167 typedef T value_type; 00168 typedef Hash hasher; 00169 typedef Pred key_equal; 00170 typedef A allocator_type; 00171 typedef value_type* pointer; 00172 typedef const value_type* const_pointer; 00173 typedef value_type& reference; 00174 typedef const value_type& const_reference; 00175 typedef std::size_t size_type; 00176 typedef std::ptrdiff_t difference_type; 00177 00178 friend class implementation::closed_hash_iterator<closed_hash_set, value_type>; 00179 friend class implementation::closed_hash_iterator<closed_hash_set, const value_type>; 00180 00181 typedef implementation::closed_hash_iterator<closed_hash_set, value_type> iterator; 00182 typedef implementation::closed_hash_iterator<closed_hash_set, const value_type> const_iterator; 00183 00184 typedef std::reverse_iterator<iterator> reverse_iterator; 00185 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00186 00187 private: 00188 enum 00189 { 00190 state_free = 0, 00191 state_home = 1, 00192 state_misplaced = 2 00193 }; 00194 00195 template <typename U> // U is derived node 00196 struct list_node_base 00197 { 00198 list_node_base() { next_m = static_cast<U*>(this); prior_m = static_cast<U*>(this); } 00199 00200 U* address() { return static_cast<U*>(this); } 00201 const U* address() const { return static_cast<const U*>(this); } 00202 00203 operator U& () { return *static_cast<U*>(this); } 00204 operator const U& () const { return *static_cast<const U*>(this); } 00205 00206 friend inline void set_next(U& x, U& y) 00207 { x.next_m = reinterpret_cast<U*>(uintptr_t(&y) | uintptr_t(x.state())); y.prior_m = &x; } 00208 00209 friend inline void set_next_raw(U& x, U& y) 00210 { x.next_m = &y; y.prior_m = &x; } 00211 00212 std::size_t state() const { return std::size_t(uintptr_t(next_m) & uintptr_t(0x03UL)); } 00213 void set_state(std::size_t x) 00214 { 00215 assert(x < 0x04UL); 00216 next_m = reinterpret_cast<U*>(uintptr_t(next()) | uintptr_t(x)); 00217 } 00218 00219 U* next() const { return reinterpret_cast<U*>(reinterpret_cast<uintptr_t>(next_m) & ~uintptr_t(0x03UL)); } 00220 U* prior() const { return prior_m; } 00221 00222 private: 00223 U* next_m; 00224 U* prior_m; 00225 }; 00226 00227 struct node_t : list_node_base<node_t> 00228 { 00229 T value_m; 00230 }; 00231 00232 typedef list_node_base<node_t> node_base_t; 00233 00234 struct header_t 00235 { 00236 struct compact_header_t 00237 { 00238 boost::compressed_pair<allocator_type, node_base_t> alloc_free_tail_m; 00239 node_base_t used_tail_m; 00240 std::size_t capacity_m; 00241 std::size_t size_m; 00242 }; 00243 00244 /* 00245 NOTE (sparent) - the assumption is that the initial items are pointers and that size_t is 00246 either equal to the sizeof a pointer or a lower power of two so this packs tightly. 00247 */ 00248 00249 BOOST_STATIC_ASSERT(!(sizeof(A) == sizeof(void*) || sizeof(A) == 0) 00250 || (sizeof(compact_header_t) == (sizeof(allocator_type) + 2 * sizeof(node_base_t) + 2 * 00251 sizeof(std::size_t)))); 00252 00253 aligned_storage<compact_header_t> header_m; 00254 node_t storage_m[1]; 00255 00256 allocator_type& allocator() { return header_m.get().alloc_free_tail_m.first(); } 00257 const allocator_type& allocator() const { return header_m.get().alloc_free_tail_m.first(); } 00258 node_base_t& free_tail() { return header_m.get().alloc_free_tail_m.second(); } 00259 const node_base_t& free_tail() const { return header_m.get().alloc_free_tail_m.second(); } 00260 node_base_t& used_tail() { return header_m.get().used_tail_m; } 00261 const node_base_t& used_tail() const { return header_m.get().used_tail_m; } 00262 std::size_t& capacity() { return header_m.get().capacity_m; } 00263 const std::size_t& capacity() const { return header_m.get().capacity_m; } 00264 std::size_t& size() { return header_m.get().size_m; } 00265 const std::size_t& size() const { return header_m.get().size_m; } 00266 }; 00267 00268 typedef node_t* node_ptr; 00269 00270 typedef boost::compressed_pair< hasher, 00271 boost::compressed_pair< key_equal, 00272 boost::compressed_pair< key_transform, 00273 header_t* 00274 > 00275 > 00276 > data_t; 00277 00278 data_t data_m; 00279 00280 typedef header_t* header_pointer; 00281 00282 const header_pointer& header() const { return data_m.second().second().second(); } 00283 header_pointer& header() { return data_m.second().second().second(); } 00284 00285 public: 00286 // construct/destroy/copy 00287 00288 closed_hash_set() { header() = 0; } 00289 00290 explicit closed_hash_set(size_type n) 00291 { 00292 header() = 0; 00293 allocate(allocator_type(), n); 00294 } 00295 00296 closed_hash_set(size_type n, const hasher& hf, const key_equal& eq = key_equal(), 00297 const key_transform& kf = key_transform(), 00298 const allocator_type& a = allocator_type()) 00299 { 00300 header() = 0; 00301 data_m.first() = hf; 00302 data_m.second().first() = eq; 00303 data_m.second().second().first() = kf; 00304 allocate(a, n); 00305 } 00306 00307 template <typename I> // I models InputIterator 00308 closed_hash_set(I f, I l) { header() = 0; insert(f, l); } 00309 00310 template <typename I> // I models InputIterator 00311 closed_hash_set(I f, I l, size_type n, const hasher& hf = hasher(), 00312 const key_equal& eq = key_equal(), 00313 const key_transform& kf = key_transform(), 00314 const allocator_type& a = allocator_type()) 00315 { 00316 header() = 0; 00317 data_m.first() = hf; 00318 data_m.second().first() = eq; 00319 data_m.second().second().first() = kf; 00320 allocate(a, n); 00321 insert(f, l); 00322 } 00323 00324 closed_hash_set(const closed_hash_set& x) : data_m(x.data_m) 00325 { 00326 header() = 0; 00327 allocate(x.get_allocator(), x.size()); 00328 insert(x.begin(), x.end()); 00329 } 00330 closed_hash_set& operator=(closed_hash_set x) { swap(x, *this); return *this; } 00331 00332 allocator_type get_allocator() const 00333 { return header() ? header()->allocator() : allocator_type(); } 00334 00335 closed_hash_set(move_from<closed_hash_set> x) : data_m(x.source.data_m) { x.source.header() = 0; } 00336 00337 #if 0 00338 template <typename I> // I models ForwardIterator 00339 closed_hash_set(I f, I l, move_ctor) { header() = 0; move_insert(f, l); } 00340 #endif 00341 00342 // size and capacity 00343 00344 size_type size() const { return header() ? header()->size() : 0; } 00345 size_type max_size() const { return size_type(-1) / sizeof(node_t); } 00346 bool empty() const { return size() == 0; } 00347 size_type capacity() const { return header() ? header()->capacity() : 0; } 00348 00349 void reserve(size_type n) 00350 { 00351 if (n <= capacity()) return; 00352 00353 if (!header()) allocate(allocator_type(), n); 00354 else 00355 { 00356 closed_hash_set tmp(n, hash_function(), key_eq(), key_function(), get_allocator()); 00357 tmp.move_insert(begin(), end()); 00358 swap(*this, tmp); 00359 } 00360 } 00361 00362 key_transform key_function() const { return data_m.second().second().first(); } 00363 hasher hash_function() const { return data_m.first(); } 00364 key_equal key_eq() const { return data_m.second().first(); } 00365 00366 iterator begin() { return iterator(header() ? header()->used_tail().next() : 0); } 00367 iterator end() { return iterator(header() ? header()->used_tail().address() : 0); } 00368 00369 const_iterator begin() const { return iterator(header() ? header()->used_tail().next() : 0); } 00370 const_iterator end() const { return iterator(header() ? const_cast<node_t*>(header()->used_tail().address()) : 0); } 00371 00372 reverse_iterator rbegin() { return reverse_iterator(end()); } 00373 reverse_iterator rend() { return reverse_iterator(begin()); } 00374 00375 const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } 00376 const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } 00377 00378 iterator erase(iterator location) 00379 { 00380 iterator next(boost::next(location)); 00381 iterator result = next; 00382 00383 if ((location.state() == std::size_t(state_home)) && (next != end()) 00384 && (next.state() == std::size_t(state_misplaced))) 00385 { 00386 swap(*next, *location); 00387 result = location; 00388 location = next; 00389 } 00390 00391 unsafe::skip_node(location); 00392 erase_raw(location); 00393 00394 --header()->size(); 00395 00396 return result; 00397 } 00398 00399 std::size_t erase(const key_type& key) 00400 { 00401 iterator node(find(key)); 00402 if (node == end()) return 0; 00403 erase(node); 00404 return 1; 00405 } 00406 00407 void clear() 00408 { 00409 for(iterator first(begin()), last(end()); first != last; first = erase(first)) ; 00410 } 00411 00412 const_iterator find(const key_type& key) const 00413 { 00414 return adobe::remove_const(*this).find(key); 00415 } 00416 00417 iterator find(const key_type& key) 00418 { 00419 if (empty()) return end(); 00420 00421 iterator node(bucket(key)); 00422 00423 if (node.state() != std::size_t(state_home)) return end(); 00424 00425 return find(node, key); 00426 } 00427 00428 std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const 00429 { 00430 const_iterator result = find(key); 00431 if (result == end()) return std::make_pair(result, result); 00432 return std::make_pair(result, boost::next(result)); 00433 } 00434 00435 std::pair<iterator, iterator> equal_range(const key_type& key) 00436 { 00437 iterator result = find(key); 00438 if (result == end()) return std::make_pair(result, result); 00439 return std::make_pair(result, boost::next(result)); 00440 } 00441 00442 std::size_t count(const key_type& key) const 00443 { return std::size_t(find(key) != end()); } 00444 00445 template <typename I> // I models InputIterator 00446 void insert(I first, I last) 00447 { while (first != last) { insert(*first); ++first; } } 00448 00449 template <typename I> // I models ForwardIterator 00450 void move_insert(I first, I last) 00451 { while (first != last) { insert(adobe::move(*first)); ++first; } } 00452 00453 /* 00454 NOTE (sparent): If there is not enough space for one element we will reserve the space 00455 prior to attempting the insert even if the item is already in the hash table. Without 00456 recalculating the bucket (a potentially expensive operation) there is no other solution. 00457 */ 00458 00459 std::pair<iterator, bool> insert(value_type x) 00460 { 00461 if (capacity() == size()) reserve(size() ? 2 * size() : 3); 00462 00463 iterator node = bucket(key_function()(x)); 00464 00465 switch (node.state()) 00466 { 00467 case state_home: 00468 { 00469 iterator found = find(node, key_function()(x)); 00470 if (found != end()) { 00471 *found = adobe::move(x); 00472 return std::make_pair(found, false); 00473 } 00474 00475 iterator free(begin_free()); 00476 insert_raw(free, adobe::move(x), state_misplaced); 00477 unsafe::splice_node_range(node, free, free); 00478 node = free; 00479 } 00480 break; 00481 case state_misplaced: 00482 { 00483 iterator free(begin_free()); 00484 insert_raw(free, adobe::move(*node), state_misplaced); 00485 00486 unsafe::set_next(boost::prior(node), free); 00487 unsafe::set_next(free, boost::next(node)); 00488 00489 erase_raw(node); 00490 } 00491 // fall through 00492 default: // state_free 00493 { 00494 insert_raw(node, adobe::move(x), state_home); 00495 unsafe::splice_node_range(end(), node, node); 00496 } 00497 } 00498 header()->size() += 1; 00499 return std::make_pair(node, true); 00500 } 00501 00502 iterator insert(iterator, value_type x) 00503 { 00504 return insert(adobe::move(x)).first; 00505 } 00506 00507 ~closed_hash_set() 00508 { 00509 if (header()) 00510 { 00511 for(iterator first(begin()), last(end()); first != last; ++first) destroy(&*first); 00512 raw_allocator alloc(get_allocator()); 00513 alloc.deallocate(reinterpret_cast<char*>(header()), 0); 00514 } 00515 } 00516 00517 friend void swap(closed_hash_set& x, closed_hash_set& y) 00518 { 00519 std::swap(x.data_m, y.data_m); 00520 } 00521 00522 friend bool operator==(const closed_hash_set& x, const closed_hash_set& y) 00523 { 00524 if (x.size() != y.size()) return false; 00525 for (const_iterator first(x.begin()), last(x.end()); first != last; ++first) 00526 { 00527 const_iterator iter(y.find(y.key_function()(*first))); 00528 if (iter == y.end() || !(*first == *iter)) return false; 00529 } 00530 return true; 00531 } 00532 private: 00533 00534 typedef typename allocator_type::template rebind<char>::other raw_allocator; 00535 00536 00537 void allocate(const allocator_type& a, size_type n) 00538 { 00539 // table of primes such that p[n + 1] = next_prime(2 * p[n]) 00540 00541 static const std::size_t prime_table[] = { 3UL, 7UL, 17UL, 37UL, 79UL, 163UL, 331UL, 673UL, 00542 1361UL, 2729UL, 5471UL, 10949UL, 21911UL, 43853UL, 87719UL, 175447UL, 350899UL, 00543 701819UL, 1403641UL, 2807303UL, 5614657UL, 11229331UL, 22458671UL, 44917381UL, 00544 89834777UL, 179669557UL, 359339171UL, 718678369UL, 1437356741UL, 2874713497UL, 00545 ULONG_MAX 00546 }; 00547 00548 assert(!header() && "WARNING (sparent@adobe.com) : About to write over allocated header."); 00549 00550 if (n == 0 && a == allocator_type()) return; 00551 00552 n = *adobe::lower_bound(prime_table, n); 00553 00554 raw_allocator alloc(a); 00555 00556 header() = reinterpret_cast<header_t*>(alloc.allocate(sizeof(header_t) - sizeof(node_t) 00557 + sizeof(node_t) * n)); 00558 header()->capacity() = n; 00559 header()->size() = 0; 00560 construct(&header()->free_tail()); 00561 construct(&header()->used_tail()); 00562 construct(&header()->allocator(), a); 00563 00564 node_t* prior = header()->free_tail().address(); 00565 for (node_ptr first(&header()->storage_m[0]), last(&header()->storage_m[0]+ n); 00566 first != last; ++first) 00567 { 00568 set_next_raw(*prior, *first); 00569 prior = first; 00570 // first->set_state(state_free); 00571 } 00572 set_next_raw(*prior, header()->free_tail()); 00573 00574 } 00575 00576 iterator bucket(const key_type& key) 00577 { 00578 std::size_t slot(hash_function()(key) % capacity()); 00579 return iterator(&header()->storage_m[0] + slot); 00580 } 00581 00582 iterator find(iterator node, const key_type& key) 00583 { 00584 do 00585 { 00586 if (key_eq()(key, key_function()(*node))) return node; 00587 ++node; 00588 } while ((node != end()) && (node.state() != std::size_t(state_home))); 00589 00590 return end(); 00591 } 00592 00593 // location points to a free node 00594 static void insert_raw(iterator location, value_type x, std::size_t state) 00595 { 00596 construct<value_type>(&*location, adobe::move(x)); 00597 location.set_state(state); 00598 unsafe::skip_node(location); 00599 } 00600 00601 // location points to a used but detatched node 00602 void erase_raw(iterator location) 00603 { 00604 destroy(&*location); 00605 location.set_state(state_free); 00606 unsafe::splice_node_range(end_free(), location, location); 00607 } 00608 00609 iterator begin_free() { return iterator(header() ? header()->free_tail().next() : 0); } 00610 iterator end_free() { return iterator(header() ? header()->free_tail().address() : 0); } 00611 }; 00612 00613 /*************************************************************************************************/ 00614 00633 template<typename Key, 00634 typename T, 00635 typename Hash, 00636 typename Pred, 00637 typename A> 00638 class closed_hash_map : public closed_hash_set<pair<Key, T>, 00639 get_element<0, pair<Key, T> >, 00640 Hash, 00641 Pred, 00642 A> 00643 { 00644 typedef closed_hash_set<pair<Key, T>, 00645 get_element<0, pair<Key, T> >, 00646 Hash, 00647 Pred, 00648 A> set_type; 00649 public: 00650 typedef T mapped_type; 00651 00652 closed_hash_map() { } 00653 00654 template <typename I> // I models InputIterator 00655 closed_hash_map(I f, I l) : set_type(f, l) { } 00656 00657 #if 0 00658 template <typename I> // I models ForwardIterator 00659 closed_hash_map(I f, I l, move_ctor) : set_type(f, l, move_ctor()) { } 00660 #endif 00661 00662 closed_hash_map(const closed_hash_map& x) : set_type(x) { } 00663 closed_hash_map(move_from<closed_hash_map> x) : set_type(move_from<set_type>(x.source)) { } 00664 closed_hash_map& operator=(closed_hash_map x) 00665 { swap(x, *this); return *this; } 00666 00667 friend void swap(closed_hash_map& x, closed_hash_map& y) 00668 { swap(static_cast<set_type&>(x), static_cast<set_type&>(y)); } 00669 00670 00671 friend bool operator==(const closed_hash_map& x, const closed_hash_map& y) 00672 { return static_cast<const set_type&>(x) == static_cast<const set_type&>(y); } 00673 00674 /* 00675 NOTE (sparent) : Can't use boost::equality_comparable without introducing extra base class 00676 overhead. 00677 */ 00678 00679 friend bool operator!=(const closed_hash_map& x, const closed_hash_map& y) 00680 { return !(x == y); } 00681 00682 #ifndef ADOBE_CLOSED_HASH_MAP_INDEX 00683 #define ADOBE_CLOSED_HASH_MAP_INDEX 1 00684 #endif 00685 00686 #if ADOBE_CLOSED_HASH_MAP_INDEX 00687 00688 mapped_type& operator[](const Key& x) 00689 { 00690 typename set_type::iterator i = this->find(x); 00691 if (i == this->end()) return insert(adobe::make_pair(x, mapped_type())).first->second; 00692 return i->second; 00693 } 00694 00695 #endif 00696 }; 00697 00698 /*************************************************************************************************/ 00699 00700 BOOST_STATIC_ASSERT(sizeof(closed_hash_set<int>) == sizeof(void*)); 00701 00702 00703 #ifndef ADOBE_NO_DOCUMENTATION 00704 00705 } // namespace version_1 00706 00707 #endif 00708 00709 /*************************************************************************************************/ 00710 00711 } // namespace adobe 00712 00713 /*************************************************************************************************/ 00714 00715 ADOBE_NAME_TYPE_1("closed_hash_set:version_1:adobe", 00716 adobe::version_1::closed_hash_set<T0, adobe::identity<const T0>, boost::hash<T0>, std::equal_to<T0>, 00717 adobe::capture_allocator<T0> >); 00718 ADOBE_NAME_TYPE_2("closed_hash_map:version_1:adobe", 00719 adobe::version_1::closed_hash_map<T0, T1, boost::hash<T0>, std::equal_to<T0>, 00720 adobe::capture_allocator<adobe::pair<T0, T1> > >); 00721 00722 ADOBE_NAME_TYPE_5("closed_hash_set:version_1:adobe", 00723 adobe::version_1::closed_hash_set<T0, T1, T2, T3, T4 >); 00724 ADOBE_NAME_TYPE_5("closed_hash_map:version_1:adobe", 00725 adobe::version_1::closed_hash_map<T0, T1, T2, T3, T4 >); 00726 00727 /*************************************************************************************************/ 00728 00729 namespace boost { 00730 00731 template< typename T, 00732 typename KeyTransform, 00733 typename Hash, 00734 typename Pred, 00735 typename A> 00736 struct has_nothrow_constructor<adobe::version_1::closed_hash_set<T, KeyTransform, Hash, Pred, A> > 00737 : boost::mpl::true_ { }; 00738 00739 template<typename Key, 00740 typename T, 00741 typename Hash, 00742 typename Pred, 00743 typename A> 00744 struct has_nothrow_constructor<adobe::version_1::closed_hash_map<Key, T, Hash, Pred, A> > 00745 : boost::mpl::true_ { }; 00746 00747 } // namespace boost 00748 00749 /*************************************************************************************************/ 00750 00751 #endif 00752 00753 /*************************************************************************************************/ |