// bslstl_unorderedmultiset_cpp03.h                                   -*-C++-*-

// Automatically generated file.  **DO NOT EDIT**

#ifndef INCLUDED_BSLSTL_UNORDEREDMULTISET_CPP03
#define INCLUDED_BSLSTL_UNORDEREDMULTISET_CPP03

//@PURPOSE: Provide C++03 implementation for bslstl_unorderedmultiset.h
//
//@CLASSES: See bslstl_unorderedmultiset.h for list of classes
//
//@SEE_ALSO: bslstl_unorderedmultiset
//
//@DESCRIPTION:  This component is the C++03 translation of a C++11 component,
// generated by the 'sim_cpp11_features.pl' program.  If the original header
// contains any specially delimited regions of C++11 code, then this generated
// file contains the C++03 equivalent, i.e., with variadic templates expanded
// and rvalue-references replaced by 'bslmf::MovableRef' objects.  The header
// code in this file is designed to be '#include'd into the original header
// when compiling with a C++03 compiler.  If there are no specially delimited
// regions of C++11 code, then this header contains no code and is not
// '#include'd in the original header.
//
// Generated on Wed Mar  8 08:55:14 2023
// Command line: sim_cpp11_features.pl bslstl_unorderedmultiset.h

#ifdef COMPILING_BSLSTL_UNORDEREDMULTISET_H

namespace bsl {

                        // ========================
                        // class unordered_multiset
                        // ========================

template <class KEY,
          class HASH      = bsl::hash<KEY>,
          class EQUAL     = bsl::equal_to<KEY>,
          class ALLOCATOR = bsl::allocator<KEY> >
class unordered_multiset
{
    // This class template implements a value-semantic container type holding
    // an unordered multiset of values (of template parameter type 'KEY').
    //
    // This class:
    //: o supports a complete set of *value-semantic* operations
    //:   o except for BDEX serialization
    //: o is *exception-neutral* (agnostic except for the 'at' method)
    //: o is *alias-safe*
    //: o is 'const' *thread-safe*
    // For terminology see {'bsldoc_glossary'}.

  private:

    // PRIVATE TYPE
    typedef bsl::allocator_traits<ALLOCATOR>                 AllocatorTraits;
        // This typedef is an alias for the allocator traits type associated
        // with this container.

    typedef KEY                                              ValueType;
        // This typedef is an alias for the type of values maintained by this
        // unordered multiset.

    typedef ::BloombergLP::bslstl::UnorderedSetKeyConfiguration<ValueType>
                                                             ListConfiguration;
        // This typedef is an alias for the policy used internally by this
        // container to extract the 'KEY' value from the values maintained by
        // this unordered multiset.

    typedef ::BloombergLP::bslstl::HashTable<ListConfiguration,
                                             HASH,
                                             EQUAL,
                                             ALLOCATOR>      HashTable;
        // This typedef is an alias for the template instantiation of the
        // underlying 'bslstl::HashTable' used to implement this unordered
        // multiset.

    typedef ::BloombergLP::bslalg::BidirectionalLink         HashTableLink;
        // This typedef is an alias for the type of links maintained by the
        // linked list of elements held by the underlying 'bslstl::HashTable'.

    typedef BloombergLP::bslmf::MovableRefUtil               MoveUtil;
        // This typedef is a convenient alias for the utility associated with
        // movable references.

    // FRIENDS
    template <class KEY2,
              class HASH2,
              class EQUAL2,
              class ALLOCATOR2>
    friend bool operator==(
                   const unordered_multiset<KEY2, HASH2, EQUAL2, ALLOCATOR2>&,
                   const unordered_multiset<KEY2, HASH2, EQUAL2, ALLOCATOR2>&);

  public:
    // PUBLIC TYPES
    typedef KEY                                        key_type;
    typedef KEY                                        value_type;
    typedef HASH                                       hasher;
    typedef EQUAL                                      key_equal;
    typedef ALLOCATOR                                  allocator_type;
    typedef value_type&                                reference;
    typedef const value_type&                          const_reference;

    typedef typename AllocatorTraits::size_type        size_type;
    typedef typename AllocatorTraits::difference_type  difference_type;
    typedef typename AllocatorTraits::pointer          pointer;
    typedef typename AllocatorTraits::const_pointer    const_pointer;

    typedef ::BloombergLP::bslstl::HashTableIterator<
                    const value_type, difference_type> iterator;

    typedef ::BloombergLP::bslstl::HashTableBucketIterator<
                    const value_type, difference_type> local_iterator;

    typedef iterator                                   const_iterator;
    typedef local_iterator                             const_local_iterator;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION_IF(
                    unordered_multiset,
                    ::BloombergLP::bslmf::IsBitwiseMoveable,
                    ::BloombergLP::bslmf::IsBitwiseMoveable<HashTable>::value);

  private:
    // DATA
    HashTable d_impl;

  public:
    // CREATORS
    unordered_multiset();
    explicit unordered_multiset(size_type        initialNumBuckets,
                                const HASH&      hashFunction = HASH(),
                                const EQUAL&     keyEqual = EQUAL(),
                                const ALLOCATOR& basicAllocator = ALLOCATOR());
    unordered_multiset(size_type        initialNumBuckets,
                       const HASH&      hashFunction,
                       const ALLOCATOR& basicAllocator);
    unordered_multiset(size_type        initialNumBuckets,
                       const ALLOCATOR& basicAllocator);
    explicit unordered_multiset(const ALLOCATOR& basicAllocator);
        // Create an empty unordered multiset.  Optionally specify an
        // 'initialNumBuckets' indicating the initial size of the array of
        // buckets of this container.  If 'initialNumBuckets' is not supplied,
        // a single bucket is used.  Optionally specify a 'hashFunction' used
        // to generate the hash values for the keys contained in this unordered
        // multiset.  If 'hashFunction' is not supplied, a default-constructed
        // object of the (template parameter) type 'HASH' is used.  Optionally
        // specify a key-equality functor 'keyEqual' used to verify that two
        // keys are equivalent.  If 'keyEqual' is not supplied, a
        // default-constructed object of the (template parameter) type 'EQUAL'
        // is used.  Optionally specify a 'basicAllocator' used to supply
        // memory.  If 'basicAllocator' is not supplied, a default-constructed
        // object of the (template parameter) type 'ALLOCATOR' is used.  If the
        // type 'ALLOCATOR' is 'bsl::allocator' (the default), then
        // 'basicAllocator', if supplied, shall be convertible to
        // 'bslma::Allocator *'.  If the type 'ALLOCATOR' is 'bsl::allocator'
        // and 'basicAllocator' is not supplied, the currently installed
        // default allocator is used.

    unordered_multiset(const unordered_multiset& original);
        // Create an unordered multiset having the same value as the specified
        // 'original' object.  Use a copy of 'original.hash_function()' to
        // generate hash values for the keys contained in this unordered
        // multiset.  Use a copy of 'original.key_eq()' to verify that two keys
        // are equivalent.  Use the allocator returned by
        // 'bsl::allocator_traits<ALLOCATOR>::
        // select_on_container_copy_construction(original.get_allocator())' to
        // allocate memory.  This method requires that the (template parameter)
        // type 'KEY' be 'copy-insertable' into this unordered multiset (see
        // {Requirements on 'KEY'}).

    unordered_multiset(
                  BloombergLP::bslmf::MovableRef<unordered_multiset> original);
        // Create an unordered multiset having the same value as the specified
        // 'original' object by moving (in constant time) the contents of
        // 'original' to the new unordered multiset.  Use a copy of
        // 'original.hash_function()' to generate hash values for the keys
        // contained in this unordered multiset.  Use a copy of
        // 'original.key_eq()' to verify that two keys are equivalent.  The
        // allocator associated with 'original' is propagated for use in the
        // newly-created unordered multiset.  'original' is left in a valid but
        // unspecified state.

    unordered_multiset(
                const unordered_multiset&                      original,
                const typename type_identity<ALLOCATOR>::type& basicAllocator);
        // Create an unordered multiset having the same value as the specified
        // 'original' object that uses the specified 'basicAllocator' to supply
        // memory.  Use a copy of 'original.hash_function()' to generate hash
        // values for the keys contained in this unordered multiset.  Use a
        // copy of 'original.key_eq()' to verify that two keys are equivalent.
        // This method requires that the (template parameter) type 'KEY' be
        // 'copy-insertable' into this unordered multiset (see {Requirements on
        // 'KEY'}).  Note that a 'bslma::Allocator *' can be supplied for
        // 'basicAllocator' if the (template parameter) type 'ALLOCATOR' is
        // 'bsl::allocator' (the default).

    unordered_multiset(
            BloombergLP::bslmf::MovableRef<unordered_multiset> original,
            const typename type_identity<ALLOCATOR>::type&     basicAllocator);
        // Create an unordered multiset having the same value as the specified
        // 'original' object that uses the specified 'basicAllocator' to supply
        // memory.  The contents of 'original' are moved (in constant time) to
        // the new unordered multiset if 'basicAllocator ==
        // original.get_allocator()', and are move-inserted (in linear time)
        // using 'basicAllocator' otherwise.  'original' is left in a valid but
        // unspecified state.  Use a copy of 'original.hash_function()' to
        // generate hash values for the keys contained in this unordered
        // multiset.  Use a copy of 'original.key_eq()' to verify that two keys
        // are equivalent.  This method requires that the (template parameter)
        // type 'KEY' be 'move-insertable' into this unordered multiset (see
        // {Requirements on 'KEY'}).  Note that a 'bslma::Allocator *' can be
        // supplied for 'basicAllocator' if the (template parameter) type
        // 'ALLOCATOR' is 'bsl::allocator' (the default).

    template <class INPUT_ITERATOR>
    unordered_multiset(INPUT_ITERATOR   first,
                       INPUT_ITERATOR   last,
                       size_type        initialNumBuckets = 0,
                       const HASH&      hashFunction = HASH(),
                       const EQUAL&     keyEqual = EQUAL(),
                       const ALLOCATOR& basicAllocator = ALLOCATOR());
    template <class INPUT_ITERATOR>
    unordered_multiset(INPUT_ITERATOR   first,
                       INPUT_ITERATOR   last,
                       size_type        initialNumBuckets,
                       const HASH&      hashFunction,
                       const ALLOCATOR& basicAllocator);
    template <class INPUT_ITERATOR>
    unordered_multiset(INPUT_ITERATOR   first,
                       INPUT_ITERATOR   last,
                       size_type        initialNumBuckets,
                       const ALLOCATOR& basicAllocator);
    template <class INPUT_ITERATOR>
    unordered_multiset(INPUT_ITERATOR   first,
                       INPUT_ITERATOR   last,
                       const ALLOCATOR& basicAllocator);
        // Create an unordered multiset, and insert each 'value_type' object in
        // the sequence starting at the specified 'first' element, and ending
        // immediately before the specified 'last' element.  Optionally specify
        // an 'initialNumBuckets' indicating the initial size of the array of
        // buckets of this container.  If 'initialNumBuckets' is not supplied,
        // a single bucket is used.  Optionally specify a 'hashFunction' used
        // to generate hash values for the keys contained in this unordered
        // multiset.  If 'hashFunction' is not supplied, a default-constructed
        // object of (template parameter) type 'HASH' is used.  Optionally
        // specify a key-equality functor 'keyEqual' used to verify that two
        // keys are equivalent.  If 'keyEqual' is not supplied, a
        // default-constructed object of (template parameter) type 'EQUAL' is
        // used.  Optionally specify a 'basicAllocator' used to supply memory.
        // If 'basicAllocator' is not supplied, a default-constructed object of
        // the (template parameter) type 'ALLOCATOR' is used.  If the type
        // 'ALLOCATOR' is 'bsl::allocator' and 'basicAllocator' is not
        // supplied, the currently installed default allocator is used to
        // supply memory.  The (template parameter) type 'INPUT_ITERATOR' shall
        // meet the requirements of an input iterator defined in the C++11
        // standard [24.2.3] providing access to values of a type convertible
        // to 'value_type', and 'value_type' must be 'emplace-constructible'
        // from '*i' into this unordered multiset, where 'i' is a
        // dereferenceable iterator in the range '[first .. last)' (see
        // {Requirements on 'KEY'}).  The behavior is undefined unless 'first'
        // and 'last' refer to a sequence of valid values where 'first' is at a
        // position at or before 'last'.  Note that a 'bslma::Allocator *' can
        // be supplied for 'basicAllocator' if the type 'ALLOCATOR' is
        // 'bsl::allocator' (the default).

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
# ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    template <
    class = bsl::enable_if_t<std::is_invocable_v<HASH, const KEY &>>,
    class = bsl::enable_if_t<
                         std::is_invocable_v<EQUAL, const KEY &, const KEY &>>,
    class = bsl::enable_if_t< bsl::IsStdAllocator_v<ALLOCATOR>>
    >
# endif
    unordered_multiset(
                      std::initializer_list<KEY> values,
                      size_type                  initialNumBuckets = 0,
                      const HASH&                hashFunction = HASH(),
                      const EQUAL&               keyEqual = EQUAL(),
                      const ALLOCATOR&           basicAllocator = ALLOCATOR());
# ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    template <
    class = bsl::enable_if_t<std::is_invocable_v<HASH, const KEY &>>,
    class = bsl::enable_if_t<bsl::IsStdAllocator<ALLOCATOR>::value>
    >
# endif
    unordered_multiset(std::initializer_list<KEY> values,
                       size_type                  initialNumBuckets,
                       const HASH&                hashFunction,
                       const ALLOCATOR&           basicAllocator);
# ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    template <class = bsl::enable_if_t<bsl::IsStdAllocator<ALLOCATOR>::value>>
# endif
    unordered_multiset(std::initializer_list<KEY> values,
                       size_type                  initialNumBuckets,
                       const ALLOCATOR&           basicAllocator);
# ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
    template <class = bsl::enable_if_t<bsl::IsStdAllocator<ALLOCATOR>::value>>
# endif
    unordered_multiset(std::initializer_list<KEY> values,
                       const ALLOCATOR&           basicAllocator);
        // Create an unordered multiset and insert each 'value_type' object in
        // the specified 'values' initializer list.  Optionally specify an
        // 'initialNumBuckets' indicating the initial size of the array of
        // buckets of this container.  If 'initialNumBuckets' is not supplied,
        // a single bucket is used.  Optionally specify a 'hashFunction' used
        // to generate the hash values for the keys contained in this unordered
        // multiset.  If 'hashFunction' is not supplied, a default-constructed
        // object of the (template parameter) type 'HASH' is used.  Optionally
        // specify a key-equality functor 'keyEqual' used to verify that two
        // keys are equivalent.  If 'keyEqual' is not supplied, a
        // default-constructed object of the (template parameter) type 'EQUAL'
        // is used.  Optionally specify a 'basicAllocator' used to supply
        // memory.  If 'basicAllocator' is not supplied, a default-constructed
        // object of the (template parameter) type 'ALLOCATOR' is used.  If the
        // type 'ALLOCATOR' is 'bsl::allocator' and 'basicAllocator' is not
        // supplied, the currently installed default allocator is used to
        // supply memory.  This method requires that the (template parameter)
        // type 'KEY' be 'copy-insertable' into this unordered multiset (see
        // {Requirements on 'KEY'}).  Note that a 'bslma::Allocator *' can be
        // supplied for 'basicAllocator' if the type 'ALLOCATOR' is
        // 'bsl::allocator' (the default).
#endif

    ~unordered_multiset();
        // Destroy this object.

    // MANIPULATORS
    unordered_multiset& operator=(const unordered_multiset& rhs);
        // Assign to this object the value, hash function, and equality
        // comparator of the specified 'rhs' object, propagate to this object
        // the allocator of 'rhs' if the 'ALLOCATOR' type has trait
        // 'propagate_on_container_copy_assignment', and return a reference
        // providing modifiable access to this object.  If an exception is
        // thrown, '*this' is left in a valid but unspecified state.  This
        // method requires that the (template parameter) type 'KEY' be both
        // 'copy-assignable' and 'copy-insertable" into this unordered multiset
        // (see {Requirements on 'KEY'}).

    unordered_multiset&
    operator=(BloombergLP::bslmf::MovableRef<unordered_multiset> rhs)
                            BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                AllocatorTraits::is_always_equal::value
                             && std::is_nothrow_move_assignable<HASH>::value
                             && std::is_nothrow_move_assignable<EQUAL>::value);
        // Assign to this object the value, hash function, and equality
        // comparator of the specified 'rhs' object, propagate to this object
        // the allocator of 'rhs' if the 'ALLOCATOR' type has trait
        // 'propagate_on_container_move_assignment', and return a reference
        // providing modifiable access to this object.  The contents of 'rhs'
        // are moved (in constant time) to this unordered multiset if
        // 'get_allocator() == rhs.get_allocator()' (after accounting for the
        // aforementioned trait); otherwise, all elements in this unordered
        // multiset are either destroyed or move-assigned to and each
        // additional element in 'rhs' is move-inserted into this unordered
        // multiset.  'rhs' is left in a valid but unspecified state, and if an
        // exception is thrown, '*this' is left in a valid but unspecified
        // state.  This method requires that the (template parameter) type
        // 'KEY' be both 'move-assignable' and 'move-insertable' into this
        // unordered multiset (see {Requirements on 'KEY'}).

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    unordered_multiset& operator=(std::initializer_list<KEY> values);
        // Assign to this object the value resulting from first clearing this
        // unordered multiset and then inserting each 'value_type' object in
        // the specified 'values' initializer list, and return a reference
        // providing modifiable access to this object.  This method requires
        // that the (template parameter) type 'KEY' be 'copy-insertable' into
        // this unordered multiset (see {Requirements on 'KEY'}).
#endif

    iterator begin() BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing modifiable access to the first
        // 'value_type' object (in the sequence of 'value_type' objects)
        // maintained by this unordered multiset, or the 'end' iterator if this
        // unordered multiset is empty.

    iterator end() BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing modifiable access to the past-the-end
        // element in the sequence of 'value_type' objects maintained by this
        // unordered multiset.

    local_iterator begin(size_type index);
        // Return a local iterator providing modifiable access to the first
        // 'value_type' object in the sequence of 'value_type' objects of the
        // bucket having the specified 'index', in the array of buckets
        // maintained by this unordered multiset, or the 'end(index)'
        // otherwise.

    local_iterator end(size_type index);
        // Return a local iterator providing modifiable access to the
        // past-the-end element in the sequence of 'value_type' objects of the
        // bucket having the specified 'index', in the array of buckets
        // maintained by this unordered multiset.

    void clear() BSLS_KEYWORD_NOEXCEPT;
        // Remove all entries from this unordered multiset.  Note that the
        // container is empty after this call, but allocated memory may be
        // retained for future use.

    template <class LOOKUP_KEY>
    typename enable_if<
           BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
        && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value,
                      pair<iterator, iterator> >::type
    equal_range(const LOOKUP_KEY& key)
        // Return a pair of iterators providing modifiable access to the
        // sequence of 'value_type' objects in this unordered multiset
        // equivalent to the specified 'key', where the first iterator is
        // positioned at the start of the sequence, and the second is
        // positioned one past the end of the sequence.  If this unordered
        // multiset contains no 'value_type' objects equivalent to the 'key',
        // then the two returned iterators will have the same value.  The
        // behavior is undefined unless 'key' is equivalent to the elements of
        // at most one equivalent-key group in this unordered multiset.
        //
        // Note: implemented inline due to Sun CC compilation error.
        {
            typedef bsl::pair<iterator, iterator> ResultType;
            HashTableLink *first;
            HashTableLink *last;
            d_impl.findRange(&first, &last, key);
            return ResultType(iterator(first), iterator(last));
        }

    pair<iterator, iterator> equal_range(const key_type& key);
        // Return a pair of iterators providing modifiable access to the
        // sequence of 'value_type' objects in this unordered multiset
        // equivalent to the specified 'key', where the first iterator is
        // positioned at the start of the sequence, and the second is
        // positioned one past the end of the sequence.  If this unordered
        // multiset contains no 'value_type' objects equivalent to the 'key',
        // then the two returned iterators will have the same value.

    size_type erase(const key_type& key);
        // Remove from this unordered multiset all 'value_type' objects that
        // are equivalent to the specified 'key', if they exist, and return the
        // number of object erased; otherwise, if there are no 'value_type'
        // objects equivalent to 'key', return 0 with no other effect.  This
        // method invalidates only iterators and references to the removed
        // element and previously saved values of the 'end()' iterator, and
        // preserves the relative order of the elements not removed.

    iterator erase(const_iterator position);
        // Remove from this unordered multiset the 'value_type' object at the
        // specified 'position', and return an iterator referring to the
        // element immediately following the removed element, or to the
        // past-the-end position if the removed element was the last element in
        // the sequence of elements maintained by this unordered multiset.
        // This method invalidates only iterators and references to the removed
        // element and previously saved values of the 'end()' iterator, and
        // preserves the relative order of the elements not removed.  The
        // behavior is undefined unless 'position' refers to a 'value_type'
        // object in this unordered multiset.

    iterator erase(const_iterator first, const_iterator last);
        // Remove from unordered multiset the 'value_type' objects starting at
        // the specified 'first' position up to, but not including the
        // specified 'last' position, and return 'last'.  This method
        // invalidates only iterators and references to the removed element and
        // previously saved values of the 'end()' iterator, and preserves the
        // relative order of the elements not removed.  The behavior is
        // undefined unless 'first' and 'last' either refer to elements in this
        // unordered multiset or are the 'end' iterator, and the 'first'
        // position is at or before the 'last' position in the sequence
        // provided by this container.

    template <class LOOKUP_KEY>
    typename enable_if<
           BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
        && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value,
                      iterator>::type
    find(const LOOKUP_KEY& key)
        // Return an iterator providing modifiable access to the first
        // 'value_type' object in the sequence of all the value elements of
        // this unordered multiset equivalent to the specified 'key', if such
        // entries exist, and the past-the-end ('end') iterator otherwise.  The
        // behavior is undefined unless 'key' is equivalent to the elements of
        // at most one equivalent-key group in this unordered multiset.
        //
        // Note: implemented inline due to Sun CC compilation error.
        {
            return iterator(d_impl.find(key));
        }

    iterator find(const key_type& key);
        // Return an iterator providing modifiable access to the first
        // 'value_type' object in the sequence of all the value elements of
        // this unordered multiset equivalent to the specified 'key', if such
        // entries exist, and the past-the-end ('end') iterator otherwise.

    iterator insert(const value_type& value);
        // Insert the specified 'value' into this unordered multiset.  If one
        // or more keys equivalent to 'value' already exist in this unordered
        // multiset, this method is guaranteed to insert 'value' in a position
        // contiguous to one of those equivalent keys.  Return an iterator
        // referring to the newly inserted 'value_type' object that is
        // equivalent to 'value.  Note that this method requires that the
        // (template parameter) type 'KEY' be 'copy-insertable' into this
        // unordered multiset (see {Requirements on 'KEY'}).

    iterator insert(BloombergLP::bslmf::MovableRef<value_type> value);
        // Insert the specified 'value' into this unordered multiset.  If one
        // or more keys equivalent to 'value' already exist in this unordered
        // multiset, this method is guaranteed to insert 'value' in a position
        // contiguous to one of those equivalent keys.  Return an iterator
        // referring to the newly inserted 'value_type' object that is
        // equivalent to 'value'.  This method requires that the (template
        // parameter) type 'KEY' be 'move-insertable' into this unordered
        // multiset (see {Requirements on 'KEY'}).

    iterator insert(const_iterator hint, const value_type& value);
        // Insert the specified 'value' into this unordered multiset (in
        // constant time if the specified 'hint' refers to an element in this
        // container equivalent to 'value').  If one or more keys equivalent to
        // 'value' already exist in this unordered multiset, this method is
        // guaranteed to insert 'value' in a position contiguous to one of
        // those equivalent keys.  Return an iterator referring to the newly
        // inserted 'value_type' object that is equivalent to 'value'.  If
        // 'hint' does not refer to an element in this container equivalent to
        // 'value', this operation has worst case 'O[N]' and average case
        // constant-time complexity, where 'N' is the size of this unordered
        // multiset.  This method requires that the (template parameter) type
        // 'KEY' be 'copy-insertable' into this unordered multiset (see
        // {Requirements on 'KEY'}).  The behavior is undefined unless 'hint'
        // is an iterator in the range '[begin() .. end()]' (both endpoints
        // included).

    iterator insert(const_iterator                             hint,
                    BloombergLP::bslmf::MovableRef<value_type> value);
        // Insert the specified 'value' into this unordered multiset (in
        // constant time if the specified 'hint' refers to an element in this
        // container equivalent to 'value').  If one or more keys equivalent to
        // 'value' already exist in this unordered multiset, this method is
        // guaranteed to insert 'value' in a position contiguous to one of
        // those equivalent keys.  Return an iterator referring to the newly
        // inserted 'value_type' object that is equivalent to 'value'.  If
        // 'hint' does not refer to an element in this container equivalent to
        // 'value', this operation has worst case 'O[N]' and average case
        // constant-time complexity, where 'N' is the size of this unordered
        // multiset.  This method requires that the (template parameter) type
        // 'KEY' be 'move-insertable' into this unordered multiset (see
        // {Requirements on 'KEY'}).  The behavior is undefined unless 'hint'
        // is an iterator in the range '[begin() .. end()]' (both endpoints
        // included).

    template <class INPUT_ITERATOR>
    void insert(INPUT_ITERATOR first, INPUT_ITERATOR last);
        // Insert into this unordered multiset the value of each 'value_type'
        // object in the range starting at the specified 'first' iterator and
        // ending immediately before the specified 'last' iterator.  The
        // (template parameter) type 'INPUT_ITERATOR' shall meet the
        // requirements of an input iterator defined in the C++11 standard
        // [24.2.3] providing access to values of a type convertible to
        // 'value_type', and 'value_type' must be 'emplace-constructible' from
        // '*i' into this unordered multiset, where 'i' is a dereferenceable
        // iterator in the range '[first .. last)' (see {Requirements on
        // 'KEY'}).  The behavior is undefined unless 'first' and 'last' refer
        // to a sequence of valid values where 'first' is at a position at or
        // before 'last'.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
    void insert(std::initializer_list<KEY> values);
        // Insert into this unordered multiset the value of each 'value_type'
        // object in the specified 'values' initializer list.  This method
        // requires that the (template parameter) type 'KEY' be
        // 'copy-insertable' into this unordered multiset (see {Requirements on
        // 'KEY'}).
#endif

#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bslstl_unorderedmultiset.h
#ifndef BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT
#define BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT 10
#endif
#ifndef BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A
#define BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT
#endif
#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 0
    iterator emplace();
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 0

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 1
    template <class Args_01>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 1

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 2
    template <class Args_01,
              class Args_02>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 2

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 3
    template <class Args_01,
              class Args_02,
              class Args_03>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 3

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 4
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 4

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 5
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 5

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 6
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 6

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 7
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 7

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 8
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07,
              class Args_08>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) args_08);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 8

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 9
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07,
              class Args_08,
              class Args_09>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) args_08,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) args_09);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 9

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 10
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07,
              class Args_08,
              class Args_09,
              class Args_10>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) args_08,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) args_09,
                     BSLS_COMPILERFEATURES_FORWARD_REF(Args_10) args_10);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 10


#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 0
    iterator emplace_hint(const_iterator hint);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 0

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 1
    template <class Args_01>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 1

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 2
    template <class Args_01,
              class Args_02>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 2

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 3
    template <class Args_01,
              class Args_02,
              class Args_03>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 3

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 4
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 4

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 5
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 5

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 6
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 6

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 7
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 7

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 8
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07,
              class Args_08>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) args_08);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 8

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 9
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07,
              class Args_08,
              class Args_09>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) args_08,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) args_09);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 9

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 10
    template <class Args_01,
              class Args_02,
              class Args_03,
              class Args_04,
              class Args_05,
              class Args_06,
              class Args_07,
              class Args_08,
              class Args_09,
              class Args_10>
    iterator emplace_hint(const_iterator hint,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) args_01,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) args_02,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) args_03,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) args_04,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) args_05,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) args_06,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) args_07,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) args_08,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) args_09,
                           BSLS_COMPILERFEATURES_FORWARD_REF(Args_10) args_10);
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_A >= 10

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.
    template <class... Args>
    iterator emplace(BSLS_COMPILERFEATURES_FORWARD_REF(Args)... args);

    template <class... Args>
    iterator emplace_hint(const_iterator hint,
                              BSLS_COMPILERFEATURES_FORWARD_REF(Args)... args);

// }}} END GENERATED CODE
#endif

    void max_load_factor(float newLoadFactor);
        // Set the maximum load factor of this container to the specified
        // 'newLoadFactor'.

    void rehash(size_type numBuckets);
        // Change the size of the array of buckets maintained by this container
        // to at least the specified 'numBuckets', and redistribute all the
        // contained elements into the new sequence of buckets, according to
        // their hash values.  Note that this operation has no effect if
        // rehashing the elements into 'numBuckets' would cause this unordered
        // multiset to exceed its 'max_load_factor'.

    void reserve(size_type numElements);
        // Increase the number of buckets of this unordered multiset to a
        // quantity such that the ratio between the specified 'numElements' and
        // this quantity does not exceed 'max_load_factor'.  Note that this
        // guarantees that, after the reserve, elements can be inserted to grow
        // the container to 'size() == numElements' without rehashing.  Also
        // note that memory allocations may still occur when growing the
        // container to 'size() == numElements'.  Also note that this operation
        // has no effect if 'numElements <= size()'.

    void swap(unordered_multiset& other)
                                 BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                      AllocatorTraits::is_always_equal::value
                                  &&  bsl::is_nothrow_swappable<HASH>::value
                                  &&  bsl::is_nothrow_swappable<EQUAL>::value);
        // Exchange the value, hasher, key-equality functor, and
        // 'max_load_factor' of this object with those of the specified 'other'
        // object; also exchange the allocator of this object with that of
        // 'other' if the (template parameter) type 'ALLOCATOR' has the
        // 'propagate_on_container_swap' trait, and do not modify either
        // allocator otherwise.  This method provides the no-throw
        // exception-safety guarantee if and only if both the (template
        // parameter) types 'HASH' and 'EQUAL' provide no-throw swap
        // operations; if an exception is thrown, both objects are left in
        // valid but unspecified states.  This operation guarantees 'O[1]'
        // complexity.  The behavior is undefined unless either this object was
        // created with the same allocator as 'other' or 'ALLOCATOR' has the
        // 'propagate_on_container_swap' trait.

    // ACCESSORS
    ALLOCATOR get_allocator() const BSLS_KEYWORD_NOEXCEPT;
        // Return (a copy of) the allocator used for memory allocation by this
        // unordered multiset.

    const_iterator  begin() const BSLS_KEYWORD_NOEXCEPT;
    const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing non-modifiable access to the first
        // 'value_type' object in the sequence of 'value_type' objects
        // maintained by this unordered multiset, or the 'end' iterator if this
        // unordered multiset is empty.

    const_iterator  end() const BSLS_KEYWORD_NOEXCEPT;
    const_iterator cend() const BSLS_KEYWORD_NOEXCEPT;
        // Return an iterator providing non-modifiable access to the
        // past-the-end element in the sequence of 'value_type' objects
        // maintained by this unordered multiset.

    bool contains(const key_type &key) const;
        // Return 'true' if this unordered multiset contains an element whose
        // key is equivalent to the specified 'key'.

    template <class LOOKUP_KEY>
    typename enable_if<
        BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value &&
            BloombergLP::bslmf::IsTransparentPredicate<EQUAL,
                                                       LOOKUP_KEY>::value,
        bool>::type
    contains(const LOOKUP_KEY& key) const
        // Return 'true' if this unordered multiset contains an element whose
        // key is equivalent to the specified 'key'.
        //
        // Note: implemented inline due to Sun CC compilation error
    {
        return find(key) != end();
    }

    bool empty() const BSLS_KEYWORD_NOEXCEPT;
        // Return 'true' if this unordered multiset contains no elements, and
        // 'false' otherwise.

    size_type size() const BSLS_KEYWORD_NOEXCEPT;
        // Return the number of elements in this unordered multiset.

    size_type max_size() const BSLS_KEYWORD_NOEXCEPT;
        // Return a theoretical upper bound on the largest number of elements
        // that this unordered multiset could possibly hold.  Note that there
        // is no guarantee that the unordered multiset can successfully grow to
        // the returned size, or even close to that size without running out of
        // resources.

    EQUAL key_eq() const;
        // Return (a copy of) the key-equality binary functor that returns
        // 'true' if the value of two 'key_type' objects are equivalent, and
        // 'false' otherwise.

    HASH hash_function() const;
        // Return (a copy of) the hash unary functor used by this unordered
        // multiset to generate a hash value (of type 'size_t') for a
        // 'key_type' object.

    template <class LOOKUP_KEY>
    typename enable_if<
           BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
        && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value,
                      const_iterator>::type
    find(const LOOKUP_KEY& key) const
        // Return an iterator providing non-modifiable access to the first
        // 'value_type' object in the sequence of all the value elements of
        // this unordered multiset equivalent to the specified 'key', if such
        // entries exist, and the past-the-end ('end') iterator otherwise.  The
        // behavior is undefined unless 'key' is equivalent to the elements of
        // at most one equivalent-key group in this unordered multiset.
        //
        // Note: implemented inline due to Sun CC compilation error.
        {
            return const_iterator(d_impl.find(key));
        }

    const_iterator find(const key_type& key) const;
        // Return an iterator providing non-modifiable access to the first
        // 'value_type' object in the sequence of all the value elements of
        // this unordered multiset equivalent to the specified 'key', if such
        // entries exist, and the past-the-end ('end') iterator otherwise.

    template <class LOOKUP_KEY>
    typename enable_if<
           BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
        && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value,
                      size_type>::type
    count(const LOOKUP_KEY& key) const
        // Return the number of 'value_type' objects within this unordered
        // multiset that are equivalent to the specified 'key'.  The behavior
        // is undefined unless 'key' is equivalent to the elements of at most
        // one equivalent-key group in this unordered multiset.
        //
        // Note: implemented inline due to Sun CC compilation error.
        {
            typedef ::BloombergLP::bslalg::BidirectionalNode<value_type> BNode;

            size_type result = 0;
            for (HashTableLink *cursor = d_impl.find(key);
                 cursor;
                 ++result, cursor = cursor->nextLink()) {

                BNode *cursorNode = static_cast<BNode *>(cursor);
                if (!this->key_eq()(
                         key,
                         ListConfiguration::extractKey(cursorNode->value()))) {
                    break;
                }
            }
            return result;
        }

    size_type count(const key_type& key) const;
        // Return the number of 'value_type' objects within this unordered
        // multiset that are equivalent to the specified 'key'.

    template <class LOOKUP_KEY>
    typename enable_if<
           BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
        && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value,
                      pair<const_iterator, const_iterator> >::type
    equal_range(const LOOKUP_KEY& key) const
        // Return a pair of iterators providing non-modifiable access to the
        // sequence of 'value_type' objects in this unordered multiset
        // equivalent to the specified 'key', where the first iterator is
        // positioned at the start of the sequence, and the second is
        // positioned one past the end of the sequence.  If this unordered
        // multiset contains no 'value_type' objects equivalent to the 'key',
        // then the two returned iterators will have the same value.  The
        // behavior is undefined unless 'key' is equivalent to the elements of
        // at most one equivalent-key group in this unordered multiset.
        //
        // Note: implemented inline due to Sun CC compilation error.
        {
            typedef bsl::pair<const_iterator, const_iterator> ResultType;
            HashTableLink *first;
            HashTableLink *last;
            d_impl.findRange(&first, &last, key);
            return ResultType(const_iterator(first), const_iterator(last));
        }


    pair<const_iterator, const_iterator> equal_range(
                                                    const key_type& key) const;
        // Return a pair of iterators providing non-modifiable access to the
        // sequence of 'value_type' objects in this unordered multiset
        // equivalent to the specified 'key', where the first iterator is
        // positioned at the start of the sequence, and the second is
        // positioned one past the end of the sequence.  If this unordered
        // multiset contains no 'value_type' objects equivalent to the 'key',
        // then the two returned iterators will have the same value.

    const_local_iterator begin(size_type index) const;
    const_local_iterator cbegin(size_type index) const;
        // Return a local iterator providing non-modifiable access to the first
        // 'value_type' object (in the sequence of 'value_type' objects) of the
        // bucket having the specified 'index' in the array of buckets
        // maintained by this unordered multiset, or the 'end(index)'
        // otherwise.  The behavior is undefined unless 'index <
        // bucket_count()'.

    const_local_iterator end(size_type index) const;
    const_local_iterator cend(size_type index) const;
        // Return a local iterator providing non-modifiable access to the
        // past-the-end element (in the sequence of 'value_type' objects) of
        // the bucket having the specified 'index' in the array of buckets
        // maintained by this unordered multiset.  The behavior is undefined
        // unless 'index < bucket_count()'.

    size_type bucket(const key_type& key) const;
        // Return the index of the bucket, in the array of buckets of this
        // container, where a value equivalent to the specified 'key' would be
        // inserted.

    size_type bucket_count() const BSLS_KEYWORD_NOEXCEPT;
        // Return the number of buckets in the array of buckets maintained by
        // this unordered multiset.

    size_type max_bucket_count() const BSLS_KEYWORD_NOEXCEPT;
        // Return a theoretical upper bound on the largest number of buckets
        // that this container could possibly manage.  Note that there is no
        // guarantee that the unordered multiset can successfully grow to the
        // returned size, or even close to that size without running out of
        // resources.

    size_type bucket_size(size_type index) const;
        // Return the number of elements contained in the bucket at the
        // specified 'index' in the array of buckets maintained by this
        // container.  The behavior is undefined unless 'index <
        // bucket_count()'.


    float load_factor() const BSLS_KEYWORD_NOEXCEPT;
        // Return the current ratio between the 'size' of this container and
        // the number of buckets.  The 'load_factor' is a measure of how full
        // the container is, and a higher load factor leads to an increased
        // number of collisions, thus resulting in a loss performance.

    float max_load_factor() const BSLS_KEYWORD_NOEXCEPT;
        // Return the maximum load factor allowed for this container.  If an
        // insert operation would cause 'load_factor' to exceed the
        // 'max_load_factor', that same insert operation will increase the
        // number of buckets and rehash the elements of the container into
        // those buckets the (see rehash).

};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

template <
    class INPUT_ITERATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class HASH = bsl::hash<KEY>,
    class EQUAL = bsl::equal_to<KEY>,
    class ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<std::is_invocable_v<HASH, const KEY&>>,
    class = bsl::enable_if_t<
                           std::is_invocable_v<EQUAL, const KEY&, const KEY&>>,
    class = bsl::enable_if_t< bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(INPUT_ITERATOR,
                   INPUT_ITERATOR,
                   typename bsl::allocator_traits<ALLOCATOR>::size_type = 0,
                   HASH      = HASH(),
                   EQUAL     = EQUAL(),
                   ALLOCATOR = ALLOCATOR())
-> unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.  Deduce
    // the template parameters 'HASH', 'EQUAL' and 'ALLOCATOR' from the other
    // parameters passed to the constructor.  This deduction guide does not
    // participate unless: (1) the supplied 'HASH' is invocable with a 'KEY',
    // (2) the supplied 'EQUAL' is invocable with two 'KEY's, and (3) the
    // supplied allocator meets the requirements of a standard allocator.

template <
    class INPUT_ITERATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class HASH,
    class EQUAL,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(
    INPUT_ITERATOR,
    INPUT_ITERATOR,
    typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
    HASH,
    EQUAL,
    ALLOC *)
-> unordered_multiset<KEY, HASH, EQUAL>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.  Deduce
    // the template parameters 'HASH' and 'EQUAL' from the other parameters
    // passed to the constructor.  This deduction guide does not participate
    // unless the supplied allocator is convertible to 'bsl::allocator<KEY>'.

template <
    class INPUT_ITERATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class HASH,
    class ALLOCATOR,
    class = bsl::enable_if_t<std::is_invocable_v<HASH, const KEY &>>,
    class = bsl::enable_if_t< bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(INPUT_ITERATOR,
                   INPUT_ITERATOR,
                   typename bsl::allocator_traits<ALLOCATOR>::size_type,
                   HASH,
                   ALLOCATOR)
-> unordered_multiset<KEY, HASH, bsl::equal_to<KEY>, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.  Deduce
    // the template parameters 'HASH' and 'ALLOCATOR' from the other parameters
    // passed to the constructor.  This deduction guide does not participate
    // unless the supplied 'HASH' is invocable with a 'KEY', and the supplied
    // allocator meets the requirements of a standard allocator.

template <
    class INPUT_ITERATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class HASH,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(
    INPUT_ITERATOR,
    INPUT_ITERATOR,
    typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
    HASH,
    ALLOC *)
-> unordered_multiset<KEY, HASH>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.  Deduce
    // the template parameter 'HASH' from the other parameters passed to the
    // constructor.  This deduction guide does not participate unless the
    // supplied allocator is convertible to 'bsl::allocator<KEY>'.

template <
    class INPUT_ITERATOR,
    class ALLOCATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(INPUT_ITERATOR,
                   INPUT_ITERATOR,
                   typename bsl::allocator_traits<ALLOCATOR>::size_type,
                   ALLOCATOR)
-> unordered_multiset<KEY, bsl::hash<KEY>, bsl::equal_to<KEY>, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.   This
    // deduction guide does not participate unless the supplied allocator meets
    // the requirements of a standard allocator.

template <
    class INPUT_ITERATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(
    INPUT_ITERATOR,
    INPUT_ITERATOR,
    typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
    ALLOC *)
-> unordered_multiset<KEY>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.  This
    // deduction guide does not participate unless the supplied allocator is
    // convertible to 'bsl::allocator<KEY>'.

template <
    class INPUT_ITERATOR,
    class ALLOCATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(INPUT_ITERATOR, INPUT_ITERATOR, ALLOCATOR)
-> unordered_multiset<KEY, bsl::hash<KEY>, bsl::equal_to<KEY>, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.   This
    // deduction guide does not participate unless the supplied allocator meets
    // the requirements of a standard allocator.

template <
    class INPUT_ITERATOR,
    class KEY = BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(INPUT_ITERATOR, INPUT_ITERATOR, ALLOC *)
-> unordered_multiset<KEY>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // iterators supplied to the constructor of 'unordered_multiset'.  This
    // deduction guide does not participate unless the supplied allocator is
    // convertible to 'bsl::allocator<KEY>'.

template <
    class KEY,
    class HASH = bsl::hash<KEY>,
    class EQUAL = bsl::equal_to<KEY>,
    class ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<std::is_invocable_v<HASH, const KEY&>>,
    class = bsl::enable_if_t<
                           std::is_invocable_v<EQUAL, const KEY&, const KEY&>>,
    class = bsl::enable_if_t< bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(std::initializer_list<KEY>,
                   typename bsl::allocator_traits<ALLOCATOR>::size_type = 0,
                   HASH      = HASH(),
                   EQUAL     = EQUAL(),
                   ALLOCATOR = ALLOCATOR())
-> unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // Deduce the template parameters 'HASH', EQUAL and 'ALLOCATOR' from the
    // other parameters passed to the constructor.  This deduction guide does
    // not participate unless: (1) the supplied 'HASH' is invocable with a
    // 'KEY', (2) the supplied 'EQUAL' is invocable with two 'KEY's, and (3)
    // the supplied allocator meets the requirements of a standard allocator.

template <
    class KEY,
    class HASH,
    class EQUAL,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(
                  std::initializer_list<KEY>,
                  typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
                  HASH,
                  EQUAL,
                  ALLOC *)
-> unordered_multiset<KEY, HASH, EQUAL>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // Deduce the template parameters 'HASH' and 'EQUAL' from the other
    // parameters passed to the constructor.  This deduction guide does not
    // participate unless the supplied allocator is convertible to
    // 'bsl::allocator<KEY>'.

template <
    class KEY,
    class HASH,
    class ALLOCATOR,
    class = bsl::enable_if_t<std::is_invocable_v<HASH, const KEY &>>,
    class = bsl::enable_if_t< bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(std::initializer_list<KEY>,
                   typename bsl::allocator_traits<ALLOCATOR>::size_type,
                   HASH,
                   ALLOCATOR)
-> unordered_multiset<KEY, HASH, bsl::equal_to<KEY>, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // Deduce the template parameters 'HASH' and 'ALLOCATOR' from the other
    // parameters passed to the constructor.  This deduction guide does not
    // participate unless the supplied 'HASH' is invocable with a 'KEY', and
    // the supplied allocator meets the requirements of a standard allocator.


template <
    class KEY,
    class HASH,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(
                  std::initializer_list<KEY>,
                  typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
                  HASH,
                  ALLOC *)
-> unordered_multiset<KEY, HASH>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // Deduce the template parameter 'HASH' from the other parameters passed to
    // the constructor.  This deduction guide does not participate unless the
    // supplied allocator is convertible to 'bsl::allocator<KEY>'.

template <
    class KEY,
    class ALLOCATOR,
    class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(std::initializer_list<KEY>,
                   typename bsl::allocator_traits<ALLOCATOR>::size_type,
                   ALLOCATOR)
-> unordered_multiset<KEY, bsl::hash<KEY>, bsl::equal_to<KEY>, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // This deduction guide does not participate unless the supplied allocator
    // meets the requirements of a standard allocator.

template <
    class KEY,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(
                  std::initializer_list<KEY>,
                  typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type,
                  ALLOC *)
-> unordered_multiset<KEY>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // This deduction guide does not participate unless the supplied allocator
    // is convertible to 'bsl::allocator<KEY>'.

template <
    class KEY,
    class ALLOCATOR,
    class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>
    >
unordered_multiset(std::initializer_list<KEY>, ALLOCATOR)
-> unordered_multiset<KEY, bsl::hash<KEY>, bsl::equal_to<KEY>, ALLOCATOR>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // This deduction guide does not participate unless the supplied allocator
    // meets the requirements of a standard allocator.

template <
    class KEY,
    class ALLOC,
    class DEFAULT_ALLOCATOR = bsl::allocator<KEY>,
    class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>>
    >
unordered_multiset(std::initializer_list<KEY>, ALLOC *)
-> unordered_multiset<KEY>;
    // Deduce the template parameter 'KEY' from the 'value_type' of the
    // initializer_list supplied to the constructor of 'unordered_multiset'.
    // This deduction guide does not participate unless the supplied allocator
    // is convertible to 'bsl::allocator<KEY>'.
#endif

// FREE OPERATORS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
bool operator==(const unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& lhs,
                const unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' objects have the same
    // value, and 'false' otherwise.  Two 'unordered_multiset' objects have the
    // same value if they have the same number of value elements, and for each
    // value-element that is contained in 'lhs' there is a value-element
    // contained in 'rhs' having the same value, and vice-versa.  Note that
    // this method requires that the (template parameter) type 'KEY' be
    // 'equality-comparable' (see {Requirements on 'KEY'}).

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
bool operator!=(const unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& lhs,
                const unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the
    // same value, and 'false' otherwise.  Two 'unordered_multiset' objects do
    // not have the same value if they do not have the same number of
    // value elements, or that for some value-element contained in 'lhs' there
    // is not a value-element in 'rhs' having the same value, and vice-versa.
    // Note that this method requires that the (template parameter) type 'KEY'
    // and be 'equality-comparable' (see {Requirements on 'KEY'}).

// FREE FUNCTIONS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR, class PREDICATE>
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
erase_if(unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& ms,
         PREDICATE                                        predicate);
    // Erase all the elements in the specified unordered_multiset 'ms' that
    // satisfy the specified predicate 'predicate'.  Return the number of
    // elements erased.

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
void swap(unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& a,
          unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& b)
                                BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                    BSLS_KEYWORD_NOEXCEPT_OPERATOR(a.swap(b)));
    // Exchange the value, hasher, key-equality functor, and 'max_load_factor'
    // of the specified 'a' object with those of the specified 'b' object; also
    // exchange the allocator of 'a' with that of 'b' if the (template
    // parameter) type 'ALLOCATOR' has the 'propagate_on_container_swap' trait,
    // and do not modify either allocator otherwise.  This function provides
    // the no-throw exception-safety guarantee if and only if both the
    // (template parameter) types 'HASH' and 'EQUAL' provide no-throw swap
    // operations; if an exception is thrown, both objects are left in valid
    // but unspecified states.  This operation guarantees 'O[1]' complexity.
    // The behavior is undefined unless either 'a' was created with the same
    // allocator as 'b' or 'ALLOCATOR' has the 'propagate_on_container_swap'
    // trait.

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

                        //-------------------------
                        // class unordered_multiset
                        //-------------------------

// CREATORS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset()
: d_impl(HASH(), EQUAL(), 0, 1.0f, ALLOCATOR())
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            size_type        initialNumBuckets,
                                            const HASH&      hashFunction,
                                            const EQUAL&     keyEqual,
                                            const ALLOCATOR& basicAllocator)
: d_impl(hashFunction, keyEqual, initialNumBuckets, 1.0f, basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            size_type        initialNumBuckets,
                                            const HASH&      hashFunction,
                                            const ALLOCATOR& basicAllocator)
: d_impl(hashFunction, EQUAL(), initialNumBuckets, 1.0f, basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            size_type        initialNumBuckets,
                                            const ALLOCATOR& basicAllocator)
: d_impl(HASH(), EQUAL(), initialNumBuckets, 1.0f, basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                               const ALLOCATOR& basicAllocator)
: d_impl(basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            const unordered_multiset& original)
: d_impl(original.d_impl,
         AllocatorTraits::select_on_container_copy_construction(
                                                     original.get_allocator()))
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                   BloombergLP::bslmf::MovableRef<unordered_multiset> original)
: d_impl(MoveUtil::move(MoveUtil::access(original).d_impl))
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                 const unordered_multiset&                      original,
                 const typename type_identity<ALLOCATOR>::type& basicAllocator)
: d_impl(original.d_impl, basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
             BloombergLP::bslmf::MovableRef<unordered_multiset> original,
             const typename type_identity<ALLOCATOR>::type&     basicAllocator)
: d_impl(MoveUtil::move(MoveUtil::access(original).d_impl), basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class INPUT_ITERATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            INPUT_ITERATOR   first,
                                            INPUT_ITERATOR   last,
                                            size_type        initialNumBuckets,
                                            const HASH&      hashFunction,
                                            const EQUAL&     keyEqual,
                                            const ALLOCATOR& basicAllocator)
: d_impl(hashFunction, keyEqual, initialNumBuckets, 1.0f, basicAllocator)
{
    this->insert(first, last);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class INPUT_ITERATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            INPUT_ITERATOR   first,
                                            INPUT_ITERATOR   last,
                                            size_type        initialNumBuckets,
                                            const HASH&      hashFunction,
                                            const ALLOCATOR& basicAllocator)
: d_impl(hashFunction, EQUAL(), initialNumBuckets, 1.0f, basicAllocator)
{
    this->insert(first, last);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class INPUT_ITERATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                            INPUT_ITERATOR   first,
                                            INPUT_ITERATOR   last,
                                            size_type        initialNumBuckets,
                                            const ALLOCATOR& basicAllocator)
: d_impl(HASH(), EQUAL(), initialNumBuckets, 1.0f, basicAllocator)
{
    this->insert(first, last);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class INPUT_ITERATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                               INPUT_ITERATOR   first,
                                               INPUT_ITERATOR   last,
                                               const ALLOCATOR& basicAllocator)
: d_impl(HASH(), EQUAL(), 0, 1.0f, basicAllocator)
{
    this->insert(first, last);
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
template <class, class, class>
#endif
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                  std::initializer_list<KEY> values,
                                  size_type                  initialNumBuckets,
                                  const hasher&              hashFunction,
                                  const key_equal&           keyEqual,
                                  const ALLOCATOR&           basicAllocator)
: unordered_multiset(values.begin(),
                     values.end(),
                     initialNumBuckets,
                     hashFunction,
                     keyEqual,
                     basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
template <class, class>
#endif
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                  std::initializer_list<KEY> values,
                                  size_type                  initialNumBuckets,
                                  const HASH&                hashFunction,
                                  const ALLOCATOR&           basicAllocator)
: unordered_multiset(values.begin(),
                     values.end(),
                     initialNumBuckets,
                     hashFunction,
                     EQUAL(),
                     basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
template <class>
#endif
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                  std::initializer_list<KEY> values,
                                  size_type                  initialNumBuckets,
                                  const ALLOCATOR&           basicAllocator)
: unordered_multiset(values.begin(),
                     values.end(),
                     initialNumBuckets,
                     HASH(),
                     EQUAL(),
                     basicAllocator)
{
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
template <class>
#endif
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::unordered_multiset(
                                     std::initializer_list<KEY> values,
                                     const ALLOCATOR&           basicAllocator)
: unordered_multiset(values.begin(),
                     values.end(),
                     0,
                     HASH(),
                     EQUAL(),
                     basicAllocator)
{
}
#endif  // defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::~unordered_multiset()
{
    // All memory management is handled by the base 'd_impl' member.
}

// MANIPULATORS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>&
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::operator=(
                                                 const unordered_multiset& rhs)
{
    // Note that we have delegated responsibility for correct handling of
    // allocator propagation to the 'HashTable' implementation.

    d_impl = rhs.d_impl;

    return *this;
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>&
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::operator=(
                        BloombergLP::bslmf::MovableRef<unordered_multiset> rhs)
                             BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                 AllocatorTraits::is_always_equal::value
                              && std::is_nothrow_move_assignable<HASH>::value
                              && std::is_nothrow_move_assignable<EQUAL>::value)
{
    // Note that we have delegated responsibility for correct handling of
    // allocator propagation to the 'HashTable' implementation.

    unordered_multiset& lvalue = rhs;

    d_impl = MoveUtil::move(lvalue.d_impl);

    return *this;
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>&
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::operator=(
                                             std::initializer_list<KEY> values)
{
    unordered_multiset tmp(values, d_impl.allocator());

    d_impl.swap(tmp.d_impl);

    return *this;
}
#endif

#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bslstl_unorderedmultiset.h
#ifndef BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT
#define BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT 10
#endif
#ifndef BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B
#define BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT
#endif
#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 0
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                          )
{
    return iterator(d_impl.emplace(
                           ));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 0

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 1
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 1

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 2
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 2

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 3
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 3

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 4
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 4

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 5
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 5

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 6
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 6

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 7
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 7

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 8
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07,
          class Args_08>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) arguments_08)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07),
                        BSLS_COMPILERFEATURES_FORWARD(Args_08, arguments_08)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 8

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 9
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07,
          class Args_08,
          class Args_09>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) arguments_09)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07),
                        BSLS_COMPILERFEATURES_FORWARD(Args_08, arguments_08),
                        BSLS_COMPILERFEATURES_FORWARD(Args_09, arguments_09)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 9

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 10
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07,
          class Args_08,
          class Args_09,
          class Args_10>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_10) arguments_10)
{
    return iterator(d_impl.emplace(
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07),
                        BSLS_COMPILERFEATURES_FORWARD(Args_08, arguments_08),
                        BSLS_COMPILERFEATURES_FORWARD(Args_09, arguments_09),
                        BSLS_COMPILERFEATURES_FORWARD(Args_10, arguments_10)));

}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 10


#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 0
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint)
{
    return iterator(d_impl.emplaceWithHint(hint.node()));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 0

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 1
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 1

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 2
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 2

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 3
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 3

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 4
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 4

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 5
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 5

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 6
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 6

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 7
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 7

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 8
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07,
          class Args_08>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) arguments_08)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07),
                        BSLS_COMPILERFEATURES_FORWARD(Args_08, arguments_08)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 8

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 9
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07,
          class Args_08,
          class Args_09>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) arguments_09)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07),
                        BSLS_COMPILERFEATURES_FORWARD(Args_08, arguments_08),
                        BSLS_COMPILERFEATURES_FORWARD(Args_09, arguments_09)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 9

#if BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 10
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class Args_01,
          class Args_02,
          class Args_03,
          class Args_04,
          class Args_05,
          class Args_06,
          class Args_07,
          class Args_08,
          class Args_09,
          class Args_10>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_01) arguments_01,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_02) arguments_02,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_03) arguments_03,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_04) arguments_04,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_05) arguments_05,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_06) arguments_06,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_07) arguments_07,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_08) arguments_08,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_09) arguments_09,
                       BSLS_COMPILERFEATURES_FORWARD_REF(Args_10) arguments_10)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                        BSLS_COMPILERFEATURES_FORWARD(Args_01, arguments_01),
                        BSLS_COMPILERFEATURES_FORWARD(Args_02, arguments_02),
                        BSLS_COMPILERFEATURES_FORWARD(Args_03, arguments_03),
                        BSLS_COMPILERFEATURES_FORWARD(Args_04, arguments_04),
                        BSLS_COMPILERFEATURES_FORWARD(Args_05, arguments_05),
                        BSLS_COMPILERFEATURES_FORWARD(Args_06, arguments_06),
                        BSLS_COMPILERFEATURES_FORWARD(Args_07, arguments_07),
                        BSLS_COMPILERFEATURES_FORWARD(Args_08, arguments_08),
                        BSLS_COMPILERFEATURES_FORWARD(Args_09, arguments_09),
                        BSLS_COMPILERFEATURES_FORWARD(Args_10, arguments_10)));
}
#endif  // BSLSTL_UNORDEREDMULTISET_VARIADIC_LIMIT_B >= 10

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class... Args>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace(
                          BSLS_COMPILERFEATURES_FORWARD_REF(Args)... arguments)
{
    return iterator(d_impl.emplace(
                           BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...));

}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class... Args>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::emplace_hint(
                                                      const_iterator hint,
                          BSLS_COMPILERFEATURES_FORWARD_REF(Args)... arguments)
{
    return iterator(d_impl.emplaceWithHint(hint.node(),
                           BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...));
}
// }}} END GENERATED CODE
#endif

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::begin() BSLS_KEYWORD_NOEXCEPT
{
    return iterator(d_impl.elementListRoot());
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::end() BSLS_KEYWORD_NOEXCEPT
{
    return iterator();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::local_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::begin(size_type index)
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return local_iterator(&d_impl.bucketAtIndex(index));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::local_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::end(size_type index)
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return local_iterator(0, &d_impl.bucketAtIndex(index));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::clear() BSLS_KEYWORD_NOEXCEPT
{
    d_impl.removeAll();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::find(const key_type& key)
{
    return iterator(d_impl.find(key));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
bsl::pair<typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator,
          typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator>
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::equal_range(
                                                           const key_type& key)
{
    HashTableLink *first;
    HashTableLink *last;
    d_impl.findRange(&first, &last, key);
    return bsl::pair<iterator, iterator>(iterator(first), iterator(last));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::erase(const_iterator position)
{
    BSLS_ASSERT(position != this->end());

    return iterator(d_impl.remove(position.node()));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::erase(const key_type& key)
{
    typedef ::BloombergLP::bslalg::BidirectionalNode<value_type> BNode;

    HashTableLink *target = d_impl.find(key);
    if (target) {
        target = d_impl.remove(target);
        size_type result = 1;
        while (target &&
               this->key_eq()(key, ListConfiguration::extractKey(
                                     static_cast<BNode *>(target)->value()))) {
            target = d_impl.remove(target);
            ++result;
        }
        return result;                                                // RETURN
    }

    return 0;
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::erase(const_iterator first,
                                                       const_iterator last)
{

#if defined BDE_BUILD_TARGET_SAFE_2
    if (first != last) {
        iterator it        = this->begin();
        const iterator end = this->end();
        for (; it != first; ++it) {
            BSLS_ASSERT(last != it);
            BSLS_ASSERT(end  != it);
        }
        for (; it != last; ++it) {
            BSLS_ASSERT(end  != it);
        }
    }
#endif

    while (first != last) {
        first = this->erase(first);
    }

    return iterator(first.node()); // convert from const_iterator
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::insert(
                                                       const value_type& value)
{
    return iterator(d_impl.insert(value));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::insert(
                              BloombergLP::bslmf::MovableRef<value_type> value)
{
    return iterator(d_impl.insert(MoveUtil::move(value)));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::insert(
                                                       const_iterator    hint,
                                                       const value_type& value)
{
    return iterator(d_impl.insert(value, hint.node()));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::insert(
                              const_iterator                             hint,
                              BloombergLP::bslmf::MovableRef<value_type> value)
{
    return iterator(d_impl.insert(MoveUtil::move(value), hint.node()));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
template <class INPUT_ITERATOR>
void
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::insert(INPUT_ITERATOR first,
                                                        INPUT_ITERATOR last)
{
    difference_type maxInsertions =
              ::BloombergLP::bslstl::IteratorUtil::insertDistance(first, last);
    if (maxInsertions) {
        this->reserve(this->size() + maxInsertions);
    }

    while (first != last) {
        d_impl.insert(*first);
        ++first;
    }
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS)
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::insert(
                                             std::initializer_list<KEY> values)
{
    insert(values.begin(), values.end());
}
#endif

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::max_load_factor(
                                                           float newLoadFactor)
{
    d_impl.setMaxLoadFactor(newLoadFactor);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::rehash(size_type numBuckets)
{
    d_impl.rehashForNumBuckets(numBuckets);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::reserve(size_type numElements)
{
    d_impl.reserveForNumElements(numElements);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::swap(
                                                     unordered_multiset& other)
                                   BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                       AllocatorTraits::is_always_equal::value
                                   &&  bsl::is_nothrow_swappable<HASH>::value
                                   &&  bsl::is_nothrow_swappable<EQUAL>::value)
{
    d_impl.swap(other.d_impl);
}

// ACCESSORS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
ALLOCATOR
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::get_allocator() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return d_impl.allocator();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::begin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_iterator(d_impl.elementListRoot());
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::end() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_iterator();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::cbegin() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_iterator(d_impl.elementListRoot());
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::cend() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return const_iterator();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_local_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::begin(size_type index) const
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return const_local_iterator(&d_impl.bucketAtIndex(index));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename
 unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_local_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::end(size_type index) const
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return const_local_iterator(0, &d_impl.bucketAtIndex(index));
}


template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename
 unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_local_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::cbegin(size_type index) const
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return const_local_iterator(&d_impl.bucketAtIndex(index));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_local_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::cend(size_type index) const
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return const_local_iterator(0, &d_impl.bucketAtIndex(index));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::bucket(
                                                     const key_type& key) const
{
    return d_impl.bucketIndexForKey(key);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::bucket_count() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return d_impl.numBuckets();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::bucket_size(
                                                         size_type index) const
{
    BSLS_ASSERT_SAFE(index < this->bucket_count());

    return d_impl.countElementsInBucket(index);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::count(
                                                     const key_type& key) const
{
    typedef ::BloombergLP::bslalg::BidirectionalNode<value_type> BNode;

    size_type result = 0;
    for (HashTableLink *cursor = d_impl.find(key);
         cursor;
         ++result, cursor = cursor->nextLink()) {

        BNode *cursorNode = static_cast<BNode *>(cursor);
        if (!this->key_eq()(
                         key,
                         ListConfiguration::extractKey(cursorNode->value()))) {
            break;
        }
    }
    return result;
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::find(
                                                     const key_type& key) const
{
    return const_iterator(d_impl.find(key));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
bool unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::contains(
                                                     const key_type& key) const
{
    return find(key) != end();
}


template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
bool
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::empty() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return 0 == d_impl.size();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return d_impl.size();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::max_size() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return AllocatorTraits::max_size(get_allocator());
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::hasher
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::hash_function() const
{
    return d_impl.hasher();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::key_equal
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::key_eq() const
{
    return d_impl.comparator();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
bsl::pair<
      typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator,
      typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::const_iterator>
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::equal_range(
                                                     const key_type& key) const
{
    HashTableLink *first;
    HashTableLink *last;
    d_impl.findRange(&first, &last, key);
    return bsl::pair<const_iterator, const_iterator>(const_iterator(first),
                                                     const_iterator(last));
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
typename unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::max_bucket_count() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return d_impl.maxNumBuckets();
}


template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
float unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::load_factor() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return d_impl.loadFactor();
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
float unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::max_load_factor() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return d_impl.maxLoadFactor();
}

}  // close namespace bsl

// FREE OPERATORS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
bool bsl::operator==(
               const bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& lhs,
               const bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& rhs)
{
    return lhs.d_impl == rhs.d_impl;
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
bool bsl::operator!=(
               const bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& lhs,
               const bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& rhs)
{
    return !(lhs == rhs);
}

// FREE FUNCTIONS
template <class KEY, class HASH, class EQUAL, class ALLOCATOR, class PREDICATE>
inline
typename bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>::size_type
bsl::erase_if(unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& ms,
              PREDICATE                                        predicate)
{
    return BloombergLP::bslstl::AlgorithmUtil::containerEraseIf(ms, predicate);
}

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
inline
void
bsl::swap(bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& a,
          bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR>& b)
                                 BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(
                                     BSLS_KEYWORD_NOEXCEPT_OPERATOR(a.swap(b)))
{
    a.swap(b);
}

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

// Type traits for STL *unordered* *associative* containers:
//: o An unordered associative container defines STL iterators.
//: o An unordered associative container is bitwise movable if both functors
//:   and the allocator are bitwise movable.
//: o An unordered associative container uses 'bslma' allocators if the
//:   (template parameter) type 'ALLOCATOR' is convertible from
//:   'bslma::Allocator *'.

namespace BloombergLP {

namespace bslalg {

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
struct HasStlIterators<bsl::unordered_multiset<KEY, HASH, EQUAL, ALLOCATOR> >
     : bsl::true_type
{};

}  // close namespace bslalg

namespace bslma {

template <class KEY, class HASH, class EQUAL, class ALLOCATOR>
struct UsesBslmaAllocator<bsl::unordered_multiset<KEY,
                                                  HASH,
                                                  EQUAL,
                                                  ALLOCATOR> >
    : bsl::is_convertible<Allocator*, ALLOCATOR>::type
{};

}  // close namespace bslma

}  // close enterprise namespace

#else // if ! defined(DEFINED_BSLSTL_UNORDEREDMULTISET_H)
# error Not valid except when included from bslstl_unorderedmultiset.h
#endif // ! defined(COMPILING_BSLSTL_UNORDEREDMULTISET_H)

#endif // ! defined(INCLUDED_BSLSTL_UNORDEREDMULTISET_CPP03)

// ----------------------------------------------------------------------------
// Copyright 2023 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------