• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 // Copyright 2006-2009 Daniel James.
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
7 #define BOOST_UNORDERED_TEST_OBJECTS_HEADER
8 
9 #include "../helpers/count.hpp"
10 #include "../helpers/fwd.hpp"
11 #include "../helpers/memory.hpp"
12 #include <boost/config.hpp>
13 #include <boost/limits.hpp>
14 #include <cstddef>
15 
16 namespace test {
17   // Note that the default hash function will work for any equal_to (but not
18   // very well).
19   class object;
20   class movable;
21   class implicitly_convertible;
22   class hash;
23   class less;
24   class equal_to;
25   template <class T> class allocator1;
26   template <class T> class allocator2;
27   object generate(object const*, random_generator);
28   movable generate(movable const*, random_generator);
29   implicitly_convertible generate(
30     implicitly_convertible const*, random_generator);
31 
ignore_variable(void const *)32   inline void ignore_variable(void const*) {}
33 
34   class object : private counted_object
35   {
36     friend class hash;
37     friend class equal_to;
38     friend class less;
39     int tag1_, tag2_;
40 
41   public:
object(int t1=0,int t2=0)42     explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
43 
~object()44     ~object()
45     {
46       tag1_ = -1;
47       tag2_ = -1;
48     }
49 
operator ==(object const & x1,object const & x2)50     friend bool operator==(object const& x1, object const& x2)
51     {
52       return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
53     }
54 
operator !=(object const & x1,object const & x2)55     friend bool operator!=(object const& x1, object const& x2)
56     {
57       return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
58     }
59 
operator <(object const & x1,object const & x2)60     friend bool operator<(object const& x1, object const& x2)
61     {
62       return x1.tag1_ < x2.tag1_ ||
63              (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
64     }
65 
generate(object const *,random_generator g)66     friend object generate(object const*, random_generator g)
67     {
68       int* x = 0;
69       return object(generate(x, g), generate(x, g));
70     }
71 
operator <<(std::ostream & out,object const & o)72     friend std::ostream& operator<<(std::ostream& out, object const& o)
73     {
74       return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
75     }
76   };
77 
78   class movable : private counted_object
79   {
80     friend class hash;
81     friend class equal_to;
82     friend class less;
83     int tag1_, tag2_;
84 
85     BOOST_COPYABLE_AND_MOVABLE(movable)
86   public:
movable(int t1=0,int t2=0)87     explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
88 
movable(movable const & x)89     movable(movable const& x)
90         : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
91     {
92       BOOST_TEST(x.tag1_ != -1);
93     }
94 
movable(BOOST_RV_REF (movable)x)95     movable(BOOST_RV_REF(movable) x)
96         : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
97     {
98       BOOST_TEST(x.tag1_ != -1);
99       x.tag1_ = -1;
100       x.tag2_ = -1;
101     }
102 
operator =(BOOST_COPY_ASSIGN_REF (movable)x)103     movable& operator=(BOOST_COPY_ASSIGN_REF(movable) x) // Copy assignment
104     {
105       BOOST_TEST(x.tag1_ != -1);
106       tag1_ = x.tag1_;
107       tag2_ = x.tag2_;
108       return *this;
109     }
110 
operator =(BOOST_RV_REF (movable)x)111     movable& operator=(BOOST_RV_REF(movable) x) // Move assignment
112     {
113       BOOST_TEST(x.tag1_ != -1);
114       tag1_ = x.tag1_;
115       tag2_ = x.tag2_;
116       x.tag1_ = -1;
117       x.tag2_ = -1;
118       return *this;
119     }
120 
~movable()121     ~movable()
122     {
123       tag1_ = -1;
124       tag2_ = -1;
125     }
126 
operator ==(movable const & x1,movable const & x2)127     friend bool operator==(movable const& x1, movable const& x2)
128     {
129       BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
130       return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
131     }
132 
operator !=(movable const & x1,movable const & x2)133     friend bool operator!=(movable const& x1, movable const& x2)
134     {
135       BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
136       return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
137     }
138 
operator <(movable const & x1,movable const & x2)139     friend bool operator<(movable const& x1, movable const& x2)
140     {
141       BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
142       return x1.tag1_ < x2.tag1_ ||
143              (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
144     }
145 
generate(movable const *,random_generator g)146     friend movable generate(movable const*, random_generator g)
147     {
148       int* x = 0;
149       return movable(generate(x, g), generate(x, g));
150     }
151 
operator <<(std::ostream & out,movable const & o)152     friend std::ostream& operator<<(std::ostream& out, movable const& o)
153     {
154       return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
155     }
156   };
157 
158   class implicitly_convertible : private counted_object
159   {
160     int tag1_, tag2_;
161 
162   public:
implicitly_convertible(int t1=0,int t2=0)163     explicit implicitly_convertible(int t1 = 0, int t2 = 0)
164         : tag1_(t1), tag2_(t2)
165     {
166     }
167 
operator object() const168     operator object() const { return object(tag1_, tag2_); }
169 
operator movable() const170     operator movable() const { return movable(tag1_, tag2_); }
171 
generate(implicitly_convertible const *,random_generator g)172     friend implicitly_convertible generate(
173       implicitly_convertible const*, random_generator g)
174     {
175       int* x = 0;
176       return implicitly_convertible(generate(x, g), generate(x, g));
177     }
178 
operator <<(std::ostream & out,implicitly_convertible const & o)179     friend std::ostream& operator<<(
180       std::ostream& out, implicitly_convertible const& o)
181     {
182       return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
183     }
184   };
185 
186   // Note: This is a deliberately bad hash function.
187   class hash
188   {
189     int type_;
190 
191   public:
hash()192     hash() : type_(0) {}
193 
hash(int t)194     explicit hash(int t) : type_(t) {}
195 
operator ()(object const & x) const196     std::size_t operator()(object const& x) const
197     {
198       int result;
199       switch (type_) {
200       case 1:
201         result = x.tag1_;
202         break;
203       case 2:
204         result = x.tag2_;
205         break;
206       default:
207         result = x.tag1_ + x.tag2_;
208       }
209       return static_cast<std::size_t>(result);
210     }
211 
operator ()(movable const & x) const212     std::size_t operator()(movable const& x) const
213     {
214       int result;
215       switch (type_) {
216       case 1:
217         result = x.tag1_;
218         break;
219       case 2:
220         result = x.tag2_;
221         break;
222       default:
223         result = x.tag1_ + x.tag2_;
224       }
225       return static_cast<std::size_t>(result);
226     }
227 
operator ()(int x) const228     std::size_t operator()(int x) const
229     {
230       int result;
231       switch (type_) {
232       case 1:
233         result = x;
234         break;
235       case 2:
236         result = x * 7;
237         break;
238       default:
239         result = x * 256;
240       }
241       return static_cast<std::size_t>(result);
242     }
243 
operator ==(hash const & x1,hash const & x2)244     friend bool operator==(hash const& x1, hash const& x2)
245     {
246       return x1.type_ == x2.type_;
247     }
248 
operator !=(hash const & x1,hash const & x2)249     friend bool operator!=(hash const& x1, hash const& x2)
250     {
251       return x1.type_ != x2.type_;
252     }
253   };
254 
hash_value(test::object const & x)255   std::size_t hash_value(test::object const& x) { return hash()(x); }
256 
hash_value(test::movable const & x)257   std::size_t hash_value(test::movable const& x) { return hash()(x); }
258 
259   class less
260   {
261     int type_;
262 
263   public:
less(int t=0)264     explicit less(int t = 0) : type_(t) {}
265 
operator ()(object const & x1,object const & x2) const266     bool operator()(object const& x1, object const& x2) const
267     {
268       switch (type_) {
269       case 1:
270         return x1.tag1_ < x2.tag1_;
271       case 2:
272         return x1.tag2_ < x2.tag2_;
273       default:
274         return x1 < x2;
275       }
276     }
277 
operator ()(movable const & x1,movable const & x2) const278     bool operator()(movable const& x1, movable const& x2) const
279     {
280       switch (type_) {
281       case 1:
282         return x1.tag1_ < x2.tag1_;
283       case 2:
284         return x1.tag2_ < x2.tag2_;
285       default:
286         return x1 < x2;
287       }
288     }
289 
operator ()(int x1,int x2) const290     std::size_t operator()(int x1, int x2) const { return x1 < x2; }
291 
operator ==(less const & x1,less const & x2)292     friend bool operator==(less const& x1, less const& x2)
293     {
294       return x1.type_ == x2.type_;
295     }
296   };
297 
298   class equal_to
299   {
300     int type_;
301 
302   public:
equal_to()303     equal_to() : type_(0) {}
304 
equal_to(int t)305     explicit equal_to(int t) : type_(t) {}
306 
operator ()(object const & x1,object const & x2) const307     bool operator()(object const& x1, object const& x2) const
308     {
309       switch (type_) {
310       case 1:
311         return x1.tag1_ == x2.tag1_;
312       case 2:
313         return x1.tag2_ == x2.tag2_;
314       default:
315         return x1 == x2;
316       }
317     }
318 
operator ()(movable const & x1,movable const & x2) const319     bool operator()(movable const& x1, movable const& x2) const
320     {
321       switch (type_) {
322       case 1:
323         return x1.tag1_ == x2.tag1_;
324       case 2:
325         return x1.tag2_ == x2.tag2_;
326       default:
327         return x1 == x2;
328       }
329     }
330 
operator ()(int x1,int x2) const331     std::size_t operator()(int x1, int x2) const { return x1 == x2; }
332 
operator ==(equal_to const & x1,equal_to const & x2)333     friend bool operator==(equal_to const& x1, equal_to const& x2)
334     {
335       return x1.type_ == x2.type_;
336     }
337 
operator !=(equal_to const & x1,equal_to const & x2)338     friend bool operator!=(equal_to const& x1, equal_to const& x2)
339     {
340       return x1.type_ != x2.type_;
341     }
342 
create_compare(equal_to x)343     friend less create_compare(equal_to x) { return less(x.type_); }
344   };
345 
346   // allocator1 only has the old fashioned 'construct' method and has
347   // a few less typedefs. allocator2 uses a custom pointer class.
348 
349   template <class T> class allocator1
350   {
351   public:
352     int tag_;
353 
354     typedef T value_type;
355 
356     template <class U> struct rebind
357     {
358       typedef allocator1<U> other;
359     };
360 
allocator1()361     allocator1() : tag_(0) { detail::tracker.allocator_ref(); }
362 
allocator1(int t)363     explicit allocator1(int t) : tag_(t) { detail::tracker.allocator_ref(); }
364 
allocator1(allocator1<Y> const & x)365     template <class Y> allocator1(allocator1<Y> const& x) : tag_(x.tag_)
366     {
367       detail::tracker.allocator_ref();
368     }
369 
allocator1(allocator1 const & x)370     allocator1(allocator1 const& x) : tag_(x.tag_)
371     {
372       detail::tracker.allocator_ref();
373     }
374 
~allocator1()375     ~allocator1() { detail::tracker.allocator_unref(); }
376 
allocate(std::size_t n)377     T* allocate(std::size_t n)
378     {
379       T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
380       detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
381       return ptr;
382     }
383 
allocate(std::size_t n,void const *)384     T* allocate(std::size_t n, void const*)
385     {
386       T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
387       detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
388       return ptr;
389     }
390 
deallocate(T * p,std::size_t n)391     void deallocate(T* p, std::size_t n)
392     {
393       detail::tracker.track_deallocate((void*)p, n, sizeof(T), tag_);
394       ::operator delete((void*)p);
395     }
396 
397 #if BOOST_UNORDERED_CXX11_CONSTRUCTION
construct(U * p,Args &&...args)398     template <typename U, typename... Args> void construct(U* p, Args&&... args)
399     {
400       detail::tracker.track_construct((void*)p, sizeof(U), tag_);
401       new (p) U(boost::forward<Args>(args)...);
402     }
403 
destroy(U * p)404     template <typename U> void destroy(U* p)
405     {
406       detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
407       p->~U();
408 
409       // Work around MSVC buggy unused parameter warning.
410       ignore_variable(&p);
411     }
412 #else
413   private:
414     // I'm going to claim in the documentation that construct/destroy
415     // is never used when C++11 support isn't available, so might as
416     // well check that in the text.
417     // TODO: Or maybe just disallow them for values?
418     template <typename U> void construct(U* p);
419     template <typename U, typename A0> void construct(U* p, A0 const&);
420     template <typename U, typename A0, typename A1>
421     void construct(U* p, A0 const&, A1 const&);
422     template <typename U, typename A0, typename A1, typename A2>
423     void construct(U* p, A0 const&, A1 const&, A2 const&);
424     template <typename U> void destroy(U* p);
425 
426   public:
427 #endif
428 
operator ==(allocator1 const & x) const429     bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }
430 
operator !=(allocator1 const & x) const431     bool operator!=(allocator1 const& x) const { return tag_ != x.tag_; }
432 
433     enum
434     {
435       is_select_on_copy = false,
436       is_propagate_on_swap = false,
437       is_propagate_on_assign = false,
438       is_propagate_on_move = false
439     };
440   };
441 
442   template <class T> class ptr;
443   template <class T> class const_ptr;
444 
445   struct void_ptr
446   {
447 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
448     template <typename T> friend class ptr;
449 
450   private:
451 #endif
452 
453     void* ptr_;
454 
455   public:
void_ptrtest::void_ptr456     void_ptr() : ptr_(0) {}
457 
void_ptrtest::void_ptr458     template <typename T> explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
459 
460     // I'm not using the safe bool idiom because the containers should be
461     // able to cope with bool conversions.
operator booltest::void_ptr462     operator bool() const { return !!ptr_; }
463 
operator ==test::void_ptr464     bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
operator !=test::void_ptr465     bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
466   };
467 
468   class void_const_ptr
469   {
470 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
471     template <typename T> friend class const_ptr;
472 
473   private:
474 #endif
475 
476     void* ptr_;
477 
478   public:
void_const_ptr()479     void_const_ptr() : ptr_(0) {}
480 
481     template <typename T>
void_const_ptr(const_ptr<T> const & x)482     explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_)
483     {
484     }
485 
486     // I'm not using the safe bool idiom because the containers should be
487     // able to cope with bool conversions.
operator bool() const488     operator bool() const { return !!ptr_; }
489 
operator ==(void_const_ptr const & x) const490     bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
operator !=(void_const_ptr const & x) const491     bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
492   };
493 
494   template <class T> class ptr
495   {
496     friend class allocator2<T>;
497     friend class const_ptr<T>;
498     friend struct void_ptr;
499 
500     T* ptr_;
501 
ptr(T * x)502     ptr(T* x) : ptr_(x) {}
503 
504   public:
ptr()505     ptr() : ptr_(0) {}
ptr(void_ptr const & x)506     explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
507 
operator *() const508     T& operator*() const { return *ptr_; }
operator ->() const509     T* operator->() const { return ptr_; }
operator ++()510     ptr& operator++()
511     {
512       ++ptr_;
513       return *this;
514     }
operator ++(int)515     ptr operator++(int)
516     {
517       ptr tmp(*this);
518       ++ptr_;
519       return tmp;
520     }
operator +(std::ptrdiff_t s) const521     ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
operator +(std::ptrdiff_t s,ptr p)522     friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
operator [](std::ptrdiff_t s) const523     T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
operator !() const524     bool operator!() const { return !ptr_; }
525 
526     // I'm not using the safe bool idiom because the containers should be
527     // able to cope with bool conversions.
operator bool() const528     operator bool() const { return !!ptr_; }
529 
operator ==(ptr const & x) const530     bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
operator !=(ptr const & x) const531     bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
operator <(ptr const & x) const532     bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
operator >(ptr const & x) const533     bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
operator <=(ptr const & x) const534     bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
operator >=(ptr const & x) const535     bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
536   };
537 
538   template <class T> class const_ptr
539   {
540     friend class allocator2<T>;
541     friend struct const_void_ptr;
542 
543     T const* ptr_;
544 
const_ptr(T const * ptr)545     const_ptr(T const* ptr) : ptr_(ptr) {}
546 
547   public:
const_ptr()548     const_ptr() : ptr_(0) {}
const_ptr(ptr<T> const & x)549     const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
const_ptr(void_const_ptr const & x)550     explicit const_ptr(void_const_ptr const& x) : ptr_((T const*)x.ptr_) {}
551 
operator *() const552     T const& operator*() const { return *ptr_; }
operator ->() const553     T const* operator->() const { return ptr_; }
operator ++()554     const_ptr& operator++()
555     {
556       ++ptr_;
557       return *this;
558     }
operator ++(int)559     const_ptr operator++(int)
560     {
561       const_ptr tmp(*this);
562       ++ptr_;
563       return tmp;
564     }
operator +(std::ptrdiff_t s) const565     const_ptr operator+(std::ptrdiff_t s) const { return const_ptr(ptr_ + s); }
operator +(std::ptrdiff_t s,const_ptr p)566     friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
567     {
568       return ptr<T>(s + p.ptr_);
569     }
operator [](int s) const570     T const& operator[](int s) const { return ptr_[s]; }
operator !() const571     bool operator!() const { return !ptr_; }
operator bool() const572     operator bool() const { return !!ptr_; }
573 
operator ==(const_ptr const & x) const574     bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
operator !=(const_ptr const & x) const575     bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
operator <(const_ptr const & x) const576     bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
operator >(const_ptr const & x) const577     bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
operator <=(const_ptr const & x) const578     bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
operator >=(const_ptr const & x) const579     bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
580   };
581 
582   template <class T> class allocator2
583   {
584 #ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
585   public:
586 #else
587     template <class> friend class allocator2;
588 #endif
589     int tag_;
590 
591   public:
592     typedef std::size_t size_type;
593     typedef std::ptrdiff_t difference_type;
594     typedef void_ptr void_pointer;
595     typedef void_const_ptr const_void_pointer;
596     typedef ptr<T> pointer;
597     typedef const_ptr<T> const_pointer;
598     typedef T& reference;
599     typedef T const& const_reference;
600     typedef T value_type;
601 
602     template <class U> struct rebind
603     {
604       typedef allocator2<U> other;
605     };
606 
allocator2()607     allocator2() : tag_(0) { detail::tracker.allocator_ref(); }
608 
allocator2(int t)609     explicit allocator2(int t) : tag_(t) { detail::tracker.allocator_ref(); }
610 
allocator2(allocator2<Y> const & x)611     template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
612     {
613       detail::tracker.allocator_ref();
614     }
615 
allocator2(allocator2 const & x)616     allocator2(allocator2 const& x) : tag_(x.tag_)
617     {
618       detail::tracker.allocator_ref();
619     }
620 
~allocator2()621     ~allocator2() { detail::tracker.allocator_unref(); }
622 
address(reference r)623     pointer address(reference r) { return pointer(&r); }
624 
address(const_reference r)625     const_pointer address(const_reference r) { return const_pointer(&r); }
626 
allocate(size_type n)627     pointer allocate(size_type n)
628     {
629       pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
630       detail::tracker.track_allocate((void*)p.ptr_, n, sizeof(T), tag_);
631       return p;
632     }
633 
allocate(size_type n,void const *)634     pointer allocate(size_type n, void const*)
635     {
636       pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
637       detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
638       return ptr;
639     }
640 
deallocate(pointer p,size_type n)641     void deallocate(pointer p, size_type n)
642     {
643       detail::tracker.track_deallocate((void*)p.ptr_, n, sizeof(T), tag_);
644       ::operator delete((void*)p.ptr_);
645     }
646 
construct(T * p,T const & t)647     void construct(T* p, T const& t)
648     {
649       detail::tracker.track_construct((void*)p, sizeof(T), tag_);
650       new (p) T(t);
651     }
652 
653 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
construct(T * p,BOOST_FWD_REF (Args)...args)654     template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
655     {
656       detail::tracker.track_construct((void*)p, sizeof(T), tag_);
657       new (p) T(boost::forward<Args>(args)...);
658     }
659 #endif
660 
destroy(T * p)661     void destroy(T* p)
662     {
663       detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
664       p->~T();
665     }
666 
max_size() const667     size_type max_size() const
668     {
669       return (std::numeric_limits<size_type>::max)();
670     }
671 
operator ==(allocator2 const & x) const672     bool operator==(allocator2 const& x) const { return tag_ == x.tag_; }
673 
operator !=(allocator2 const & x) const674     bool operator!=(allocator2 const& x) const { return tag_ != x.tag_; }
675 
676     enum
677     {
678       is_select_on_copy = false,
679       is_propagate_on_swap = false,
680       is_propagate_on_assign = false,
681       is_propagate_on_move = false
682     };
683   };
684 
685   template <class T>
equivalent_impl(allocator1<T> const & x,allocator1<T> const & y,test::derived_type)686   bool equivalent_impl(
687     allocator1<T> const& x, allocator1<T> const& y, test::derived_type)
688   {
689     return x == y;
690   }
691 
692   template <class T>
equivalent_impl(allocator2<T> const & x,allocator2<T> const & y,test::derived_type)693   bool equivalent_impl(
694     allocator2<T> const& x, allocator2<T> const& y, test::derived_type)
695   {
696     return x == y;
697   }
698 }
699 
700 #endif
701