OSDN Git Service

2010-03-25 Paolo Carlini <paolo.carlini@oracle.com>
authorpaolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 26 Mar 2010 02:19:10 +0000 (02:19 +0000)
committerpaolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 26 Mar 2010 02:19:10 +0000 (02:19 +0000)
* include/bits/unordered_map.h (operator==, operator!=): Add per N3068.
* include/bits/unordered_set.h (operator==, operator!=): Likewise.
* include/debug/unordered_map (operator==, operator!=): Likewise.
* include/debug/unordered_set: Likewise.
* include/profile/unordered_map: Likewise.
* include/profile/unordered_set: Likewise.
* testsuite/23_containers/unordered_map/operators/1.cc: New.
* testsuite/23_containers/unordered_multimap/operators/1.cc: Likewise.
* testsuite/23_containers/unordered_multimap/operators/2.cc: Likewise.
* testsuite/23_containers/unordered_set/operators/1.cc: Likewise.
* testsuite/23_containers/unordered_multiset/operators/1.cc: Likewise.

2010-03-25  John Lakos  <jlakos@bloomberg.net>
    Pablo Halpern  <phalpern@halpernwightsoftware.com>
    Paolo Carlini  <paolo.carlini@oracle.com>

* include/bits/hashtable_policy.h (struct _Equality_base): Add.
* include/bits/hashtable.h (_Hashtable<>): Derive from the latter.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@157736 138bc75d-0d04-0410-961f-82ee72b054a4

14 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/hashtable.h
libstdc++-v3/include/bits/hashtable_policy.h
libstdc++-v3/include/bits/unordered_map.h
libstdc++-v3/include/bits/unordered_set.h
libstdc++-v3/include/debug/unordered_map
libstdc++-v3/include/debug/unordered_set
libstdc++-v3/include/profile/unordered_map
libstdc++-v3/include/profile/unordered_set
libstdc++-v3/testsuite/23_containers/unordered_map/operators/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_multimap/operators/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_multimap/operators/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_multiset/operators/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_set/operators/1.cc [new file with mode: 0644]

index 7d898f6..5bd9f95 100644 (file)
@@ -1,3 +1,24 @@
+2010-03-25  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       * include/bits/unordered_map.h (operator==, operator!=): Add per N3068.
+       * include/bits/unordered_set.h (operator==, operator!=): Likewise.
+       * include/debug/unordered_map (operator==, operator!=): Likewise.
+       * include/debug/unordered_set: Likewise.
+       * include/profile/unordered_map: Likewise.
+       * include/profile/unordered_set: Likewise.
+       * testsuite/23_containers/unordered_map/operators/1.cc: New.
+       * testsuite/23_containers/unordered_multimap/operators/1.cc: Likewise.
+       * testsuite/23_containers/unordered_multimap/operators/2.cc: Likewise.
+       * testsuite/23_containers/unordered_set/operators/1.cc: Likewise.
+       * testsuite/23_containers/unordered_multiset/operators/1.cc: Likewise.
+
+2010-03-25  John Lakos  <jlakos@bloomberg.net>
+           Pablo Halpern  <phalpern@halpernwightsoftware.com>
+           Paolo Carlini  <paolo.carlini@oracle.com>
+
+       * include/bits/hashtable_policy.h (struct _Equality_base): Add.
+       * include/bits/hashtable.h (_Hashtable<>): Derive from the latter.
+
 2010-03-23  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * testsuite/util/testsuite_tr1.h (NType, TType, SLType, PODType): Add.
index cd7553d..c7aceb1 100644 (file)
@@ -118,7 +118,15 @@ namespace std
                                            _RehashPolicy,
                                            __cache_hash_code,
                                            __constant_iterators,
-                                           __unique_keys> >
+                                           __unique_keys> >,
+      public __detail::_Equality_base<_ExtractKey, __unique_keys,
+                                     _Hashtable<_Key, _Value, _Allocator,
+                                                _ExtractKey,
+                                                _Equal, _H1, _H2, _Hash,
+                                                _RehashPolicy,
+                                                __cache_hash_code,
+                                                __constant_iterators,
+                                                __unique_keys> >
     {
     public:
       typedef _Allocator                                  allocator_type;
index 142c57f..6e6a8fb 100644 (file)
@@ -484,24 +484,24 @@ namespace __detail
       return std::make_pair(false, 0);
   }
 
-  // Base classes for std::tr1::_Hashtable.  We define these base
-  // classes because in some cases we want to do different things
-  // depending on the value of a policy class.  In some cases the
-  // policy class affects which member functions and nested typedefs
-  // are defined; we handle that by specializing base class templates.
-  // Several of the base class templates need to access other members
-  // of class template _Hashtable, so we use the "curiously recurring
-  // template pattern" for them.
-
-  // class template _Map_base.  If the hashtable has a value type of the
-  // form pair<T1, T2> and a key extraction policy that returns the
+  // Base classes for std::_Hashtable.  We define these base classes
+  // because in some cases we want to do different things depending
+  // on the value of a policy class.  In some cases the policy class
+  // affects which member functions and nested typedefs are defined;
+  // we handle that by specializing base class templates.  Several of
+  // the base class templates need to access other members of class
+  // template _Hashtable, so we use the "curiously recurring template
+  // pattern" for them.
+
+  // class template _Map_base.  If the hashtable has a value type of
+  // the form pair<T1, T2> and a key extraction policy that returns the
   // first part of the pair, the hashtable gets a mapped_type typedef.
   // If it satisfies those criteria and also has unique keys, then it
   // also gets an operator[].  
   template<typename _Key, typename _Value, typename _Ex, bool __unique,
           typename _Hashtable>
     struct _Map_base { };
-         
+
   template<typename _Key, typename _Pair, typename _Hashtable>
     struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, false, _Hashtable>
     {
@@ -512,7 +512,7 @@ namespace __detail
     struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>
     {
       typedef typename _Pair::second_type mapped_type;
-      
+
       mapped_type&
       operator[](const _Key& __k);
 
@@ -832,6 +832,127 @@ namespace __detail
       _H1          _M_h1;
       _H2          _M_h2;
     };
+
+
+  // Class template _Equality_base.  This is for implementing equality
+  // comparison for unordered containers, per N3068, by John Lakos and
+  // Pablo Halpern.  Algorithmically, we follow closely the reference
+  // implementations therein.
+  template<typename _ExtractKey, bool __unique_keys,
+          typename _Hashtable>
+    struct _Equality_base;
+
+  template<typename _ExtractKey, typename _Hashtable>
+    struct _Equality_base<_ExtractKey, true, _Hashtable>
+    {
+      bool _M_equal(const _Hashtable&) const;
+    };
+
+  template<typename _ExtractKey, typename _Hashtable>
+    bool
+    _Equality_base<_ExtractKey, true, _Hashtable>::
+    _M_equal(const _Hashtable& __other) const
+    {
+      const _Hashtable* __this = static_cast<const _Hashtable*>(this);
+
+      if (__this->size() != __other.size())
+       return false;
+
+      for (auto __itx = __this->begin(); __itx != __this->end(); ++__itx)
+       {
+         const auto __ity = __other.find(_ExtractKey()(*__itx));
+         if (__ity == __other.end() || *__ity != *__itx)
+           return false;
+       }
+      return true;
+    }
+
+  template<typename _ExtractKey, typename _Hashtable>
+    struct _Equality_base<_ExtractKey, false, _Hashtable>
+    {
+      bool _M_equal(const _Hashtable&) const;
+
+    private:
+      template<typename _Uiterator>
+        static bool
+        _S_is_permutation(_Uiterator, _Uiterator, _Uiterator);
+    };
+
+  // See std::is_permutation in N3068.
+  template<typename _ExtractKey, typename _Hashtable>
+    template<typename _Uiterator>
+      bool
+      _Equality_base<_ExtractKey, false, _Hashtable>::
+      _S_is_permutation(_Uiterator __first1, _Uiterator __last1,
+                       _Uiterator __first2)
+      {
+       for (; __first1 != __last1; ++__first1, ++__first2)
+         if (!(*__first1 == *__first2))
+           break;
+
+       if (__first1 == __last1)
+         return true;
+
+       _Uiterator __last2 = __first2;
+       std::advance(__last2, std::distance(__first1, __last1));
+
+       for (_Uiterator __it1 = __first1; __it1 != __last1; ++__it1)
+         {
+           _Uiterator __tmp =  __first1;
+           while (__tmp != __it1 && !(*__tmp == *__it1))
+             ++__tmp;
+
+           // We've seen this one before.
+           if (__tmp != __it1)
+             continue;
+
+           std::ptrdiff_t __n2 = 0;
+           for (__tmp = __first2; __tmp != __last2; ++__tmp)
+             if (*__tmp == *__it1)
+               ++__n2;
+
+           if (!__n2)
+             return false;
+
+           std::ptrdiff_t __n1 = 0;
+           for (__tmp = __it1; __tmp != __last1; ++__tmp)
+             if (*__tmp == *__it1)
+               ++__n1;
+
+           if (__n1 != __n2)
+             return false;
+         }
+       return true;
+      }
+
+  template<typename _ExtractKey, typename _Hashtable>
+    bool
+    _Equality_base<_ExtractKey, false, _Hashtable>::
+    _M_equal(const _Hashtable& __other) const
+    {
+      const _Hashtable* __this = static_cast<const _Hashtable*>(this);
+
+      if (__this->size() != __other.size())
+       return false;
+
+      for (auto __itx = __this->begin(); __itx != __this->end();)
+       {
+         const auto __xrange = __this->equal_range(_ExtractKey()(*__itx));
+         const auto __yrange = __other.equal_range(_ExtractKey()(*__itx));
+
+         if (std::distance(__xrange.first, __xrange.second)
+             != std::distance(__yrange.first, __yrange.second))
+           return false;
+
+         if (!_S_is_permutation(__xrange.first,
+                                __xrange.second,
+                                __yrange.first))
+           return false;
+
+         __itx = __xrange.second;
+       }
+      return true;
+    }
 } // namespace __detail
 }
 
index 77236d3..74998ff 100644 (file)
@@ -159,6 +159,41 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
         _Alloc, __cache_hash_code>& __y)
     { __x.swap(__y); }
 
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator==(const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator!=(const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return !(__x == __y); }
+
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator==(const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator!=(const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return !(__x == __y); }
 
   /**
    *  @brief A standard container composed of unique keys (containing
@@ -335,6 +370,30 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
         unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator==(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator!=(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator==(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator!=(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 _GLIBCXX_END_NESTED_NAMESPACE
 
 #endif /* _UNORDERED_MAP_H */
index a20fbf4..50dee21 100644 (file)
@@ -155,6 +155,41 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
         _Alloc, __cache_hash_code>& __y)
     { __x.swap(__y); }
 
+  template<class _Value, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator==(const __unordered_set<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_set<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Value, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator!=(const __unordered_set<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_set<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return !(__x == __y); }
+
+  template<class _Value, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator==(const __unordered_multiset<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_multiset<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Value, class _Hash, class _Pred, class _Alloc,
+          bool __cache_hash_code>
+    inline bool
+    operator!=(const __unordered_multiset<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __x,
+              const __unordered_multiset<_Value, _Hash, _Pred, _Alloc,
+              __cache_hash_code>& __y)
+    { return !(__x == __y); }
 
   /**
    *  @brief A standard container composed of unique keys (containing
@@ -325,6 +360,30 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD_D)
         unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<class _Value, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator==(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Value, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator!=(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
+  template<class _Value, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator==(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<class _Value, class _Hash, class _Pred, class _Alloc>
+    inline bool
+    operator!=(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 _GLIBCXX_END_NESTED_NAMESPACE
 
 #endif /* _UNORDERED_SET_H */
index a5e6174..6fef1e9 100644 (file)
@@ -287,6 +287,20 @@ namespace __debug
         unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 
   /// Class std::unordered_multimap with safety/checking/debug instrumentation.
   template<typename _Key, typename _Tp,
@@ -524,6 +538,20 @@ namespace __debug
         unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 } // namespace __debug
 } // namespace std
 
index f851718..09329b0 100644 (file)
@@ -286,6 +286,18 @@ namespace __debug
         unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 
   /// Class std::unordered_multiset with safety/checking/debug instrumentation.
   template<typename _Value,
@@ -521,6 +533,18 @@ namespace __debug
         unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 } // namespace __debug
 } // namespace std
 
index b90d58b..b9e6787 100644 (file)
@@ -272,6 +272,20 @@ namespace __profile
         unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 #undef _GLIBCXX_BASE
 #undef _GLIBCXX_STD_BASE
 #define _GLIBCXX_BASE unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>
@@ -482,6 +496,20 @@ namespace __profile
         unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Key, typename _Tp, typename _Hash,
+          typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 } // namespace __profile
 } // namespace std
 
index 128cf60..6dcdc83 100644 (file)
@@ -262,6 +262,18 @@ namespace __profile
         unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 #undef _GLIBCXX_BASE
 #undef _GLIBCXX_STD_BASE
 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_PR::_GLIBCXX_BASE
@@ -474,6 +486,18 @@ namespace __profile
         unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
     { __x.swap(__y); }
 
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator==(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return __x._M_equal(__y); }
+
+  template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
+    inline bool
+    operator!=(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
+              const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
+    { return !(__x == __y); }
+
 } // namespace __profile
 } // namespace std
 
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/operators/1.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/operators/1.cc
new file mode 100644 (file)
index 0000000..f5e68de
--- /dev/null
@@ -0,0 +1,169 @@
+// { dg-options "-std=gnu++0x" }
+
+// 2010-03-25  Paolo Carlini  <paolo.carlini@oracle.com>
+
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  typedef std::pair<const int, int> Pair;
+  std::unordered_map<int, int> um1, um2;
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(2, -1));
+  um2.insert(Pair(2, -1));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(3, -3));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um2.insert(Pair(3, -3));
+  VERIFY( (um1 == um2) );
+  VERIFY( !(um1 != um2) );
+
+  um2.clear();
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.clear();
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(2, -2));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(2, -2));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(3, -3));
+  um2.insert(Pair(4, -4));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(4, -4));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um2.insert(Pair(3, -3));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(4, -4));
+  um2.insert(Pair(4, -4));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.clear();
+  um2.clear();
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -2));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.clear();
+  um2.clear();
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(2, -2));
+  um2.insert(Pair(2, -3));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(2, -3));
+  um2.insert(Pair(2, -2));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.clear();
+  um2.clear();
+  VERIFY( um1 == um2 );
+  VERIFY( !(um1 != um2) );
+
+  um1.insert(Pair(2, -2));
+  um2.insert(Pair(2, -3));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(2, -3));
+  um2.insert(Pair(2, -2));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -1));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  um1.insert(Pair(1, -1));
+  um2.insert(Pair(1, -2));
+  VERIFY( um1 != um2 );
+  VERIFY( !(um1 == um2) );
+
+  const std::unordered_map<int, int> cum1(um1), cum2(um2);
+  VERIFY( cum1 != cum2 );
+  VERIFY( !(cum1 == cum2) );
+  VERIFY( cum1 != um2 );
+  VERIFY( !(um1 == cum2) );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/operators/1.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/operators/1.cc
new file mode 100644 (file)
index 0000000..f6e21f8
--- /dev/null
@@ -0,0 +1,192 @@
+// { dg-options "-std=gnu++0x" }
+
+// 2010-03-25  Paolo Carlini  <paolo.carlini@oracle.com>
+
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  typedef std::pair<const int, int> Pair;
+  std::unordered_multimap<int, int> umm1, umm2;
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(2, -1));
+  umm2.insert(Pair(2, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(3, -3));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm2.insert(Pair(3, -3));
+  VERIFY( (umm1 == umm2) );
+  VERIFY( !(umm1 != umm2) );
+
+  umm2.clear();
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.clear();
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(2, -2));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(2, -2));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(3, -3));
+  umm2.insert(Pair(4, -4));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(4, -4));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm2.insert(Pair(3, -3));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(4, -4));
+  umm2.insert(Pair(4, -4));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.clear();
+  umm2.clear();
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -2));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.clear();
+  umm2.clear();
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(2, -2));
+  umm2.insert(Pair(2, -3));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(2, -3));
+  umm2.insert(Pair(2, -2));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.clear();
+  umm2.clear();
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(2, -2));
+  umm2.insert(Pair(2, -3));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(2, -3));
+  umm2.insert(Pair(2, -2));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  umm1.insert(Pair(1, -1));
+  umm2.insert(Pair(1, -2));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(3, -3));
+  umm2.insert(Pair(3, -3));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(3, -4));
+  umm2.insert(Pair(3, -3));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm1.insert(Pair(3, -3));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+  umm1.insert(Pair(1, -2));
+  umm2.insert(Pair(1, -1));
+  VERIFY( umm1 != umm2 );
+  VERIFY( !(umm1 == umm2) );
+
+  umm2.insert(Pair(3, -4));
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  const std::unordered_multimap<int, int> cumm1(umm1), cumm2(umm2);
+  VERIFY( cumm1 == cumm2 );
+  VERIFY( !(cumm1 != cumm2) );
+  VERIFY( cumm1 == umm2 );
+  VERIFY( !(umm1 != cumm2) );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/operators/2.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/operators/2.cc
new file mode 100644 (file)
index 0000000..1121dbc
--- /dev/null
@@ -0,0 +1,63 @@
+// { dg-options "-std=gnu++0x" }
+
+// 2010-03-25  Paolo Carlini  <paolo.carlini@oracle.com>
+
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  typedef std::pair<const int, int> Pair;
+  std::unordered_multimap<int, int> umm1, umm2;
+  VERIFY( umm1 == umm2 );
+  VERIFY( !(umm1 != umm2) );
+
+  int second1[] = { -1, -2, -3, -4, -5 };
+  int second2[] = { -1, -2, -3, -4, -5 };
+  const unsigned size = sizeof(second1) / sizeof(int);
+
+  for (unsigned perm1 = 0; perm1 < 120; ++perm1)
+    {
+      umm1.clear();
+      std::next_permutation(second1, second1 + size);
+      for (unsigned i1 = 0; i1 < size; ++i1)
+       umm1.insert(Pair(0, second1[i1]));
+
+      for (unsigned perm2 = 0; perm2 < 120; ++perm2)
+       {
+         umm2.clear();
+         std::next_permutation(second2, second2 + size);
+         for (unsigned i2 = 0; i2 < size; ++i2)
+           umm2.insert(Pair(0, second2[i2]));
+
+         VERIFY( umm1 == umm2 );
+         VERIFY( !(umm1 != umm2) );
+       }
+    }
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/operators/1.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/operators/1.cc
new file mode 100644 (file)
index 0000000..3e3b1c7
--- /dev/null
@@ -0,0 +1,108 @@
+// { dg-options "-std=gnu++0x" }
+
+// 2010-03-25  Paolo Carlini  <paolo.carlini@oracle.com>
+
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  std::unordered_multiset<int> ums1, ums2;
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(1);
+  ums2.insert(1);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(2);
+  ums2.insert(2);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(1);
+  ums2.insert(1);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(3);
+  VERIFY( ums1 != ums2 );
+  VERIFY( !(ums1 == ums2) );
+
+  ums2.insert(3);
+  VERIFY( (ums1 == ums2) );
+  VERIFY( !(ums1 != ums2) );
+
+  ums2.clear();
+  VERIFY( ums1 != ums2 );
+  VERIFY( !(ums1 == ums2) );
+
+  ums1.clear();
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(1);
+  ums2.insert(2);
+  VERIFY( ums1 != ums2 );
+  VERIFY( !(ums1 == ums2) );
+
+  ums1.insert(2);
+  ums2.insert(1);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(3);
+  ums2.insert(4);
+  VERIFY( ums1 != ums2 );
+  VERIFY( !(ums1 == ums2) );
+
+  ums1.insert(4);
+  VERIFY( ums1 != ums2 );
+  VERIFY( !(ums1 == ums2) );
+
+  ums2.insert(3);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(1);
+  ums2.insert(1);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  ums1.insert(4);
+  ums2.insert(4);
+  VERIFY( ums1 == ums2 );
+  VERIFY( !(ums1 != ums2) );
+
+  const std::unordered_multiset<int> cums1(ums1), cums2(ums2);
+  VERIFY( cums1 == cums2 );
+  VERIFY( !(cums1 != cums2) );
+  VERIFY( cums1 == ums2 );
+  VERIFY( !(ums1 != cums2) );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/operators/1.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/operators/1.cc
new file mode 100644 (file)
index 0000000..63e726d
--- /dev/null
@@ -0,0 +1,108 @@
+// { dg-options "-std=gnu++0x" }
+
+// 2010-03-25  Paolo Carlini  <paolo.carlini@oracle.com>
+
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  std::unordered_set<int> us1, us2;
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(1);
+  us2.insert(1);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(2);
+  us2.insert(2);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(1);
+  us2.insert(1);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(3);
+  VERIFY( us1 != us2 );
+  VERIFY( !(us1 == us2) );
+
+  us2.insert(3);
+  VERIFY( (us1 == us2) );
+  VERIFY( !(us1 != us2) );
+
+  us2.clear();
+  VERIFY( us1 != us2 );
+  VERIFY( !(us1 == us2) );
+
+  us1.clear();
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(1);
+  us2.insert(2);
+  VERIFY( us1 != us2 );
+  VERIFY( !(us1 == us2) );
+
+  us1.insert(2);
+  us2.insert(1);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(3);
+  us2.insert(4);
+  VERIFY( us1 != us2 );
+  VERIFY( !(us1 == us2) );
+
+  us1.insert(4);
+  VERIFY( us1 != us2 );
+  VERIFY( !(us1 == us2) );
+
+  us2.insert(3);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(1);
+  us2.insert(1);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  us1.insert(4);
+  us2.insert(4);
+  VERIFY( us1 == us2 );
+  VERIFY( !(us1 != us2) );
+
+  const std::unordered_set<int> cus1(us1), cus2(us2);
+  VERIFY( cus1 == cus2 );
+  VERIFY( !(cus1 != cus2) );
+  VERIFY( cus1 == us2 );
+  VERIFY( !(us1 != cus2) );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}