// map standard header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _MAP_
#define _MAP_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <tuple>
#include <xtree>

namespace std {

// TEMPLATE CLASS _Tmap_traits
template<class _Kty,    // key type
         class _Ty,      // mapped type
         class _Pr,      // comparator predicate type
         class _Alloc,   // actual allocator type (should be value allocator)
         bool _Mfl>      // true if multiple equivalent keys are permitted
class _Tmap_traits
{       // traits required to make _Tree behave like a map
public:
  typedef _Kty key_type;
  typedef pair<const _Kty, _Ty> value_type;
  typedef _Pr key_compare;
  typedef _Alloc allocator_type;

  enum
  {       // make multi parameter visible as an enum constant
    _Multi = _Mfl};

  class value_compare
  {       // functor for comparing two element values
    friend class _Tmap_traits<_Kty, _Ty, _Pr, _Alloc, _Mfl>;

  public:
    typedef value_type first_argument_type;
    typedef value_type second_argument_type;
    typedef bool result_type;

    bool operator()(const value_type& _Left,
                    const value_type& _Right) const
    {       // test if _Left precedes _Right by comparing just keys
      return comp(_Left.first, _Right.first);
    }

    value_compare(key_compare _Pred)
      : comp(_Pred)
    {       // construct with specified predicate
    }

  protected:
    key_compare comp;       // the comparator predicate for keys
  };

  template<class _Ty1,
           class _Ty2>
  static const _Kty& _Kfn(const pair<_Ty1, _Ty2>& _Val)
  {       // extract key from element value
    return _Val.first;
  }
};

// TEMPLATE CLASS map
template<class _Kty,
         class _Ty,
         class _Pr = less<_Kty>,
         class _Alloc = allocator<pair<const _Kty, _Ty> > >
class map
  : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false> >
{       // ordered red-black tree of {key, mapped} values, unique keys
public:
  typedef map<_Kty, _Ty, _Pr, _Alloc> _Myt;
  typedef _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false> > _Mybase;
  typedef _Kty key_type;
  typedef _Ty mapped_type;
  typedef _Pr key_compare;
  typedef typename _Mybase::value_compare value_compare;
  typedef typename _Mybase::allocator_type allocator_type;
  typedef typename _Mybase::size_type size_type;
  typedef typename _Mybase::difference_type difference_type;
  typedef typename _Mybase::pointer pointer;
  typedef typename _Mybase::const_pointer const_pointer;
  typedef typename _Mybase::reference reference;
  typedef typename _Mybase::const_reference const_reference;
  typedef typename _Mybase::iterator iterator;
  typedef typename _Mybase::const_iterator const_iterator;
  typedef typename _Mybase::reverse_iterator reverse_iterator;
  typedef typename _Mybase::const_reverse_iterator
  const_reverse_iterator;
  typedef typename _Mybase::value_type value_type;

  typedef typename _Mybase::_Alty _Alty;
  typedef typename _Mybase::_Pairib _Pairib;

  map()
    : _Mybase(key_compare(), allocator_type())
  {       // construct empty map from defaults
  }

  explicit map(const allocator_type& _Al)
    : _Mybase(key_compare(), _Al)
  {       // construct empty map from defaults, allocator
  }

  map(const _Myt& _Right)
    : _Mybase(_Right,
              _Right._Getal().select_on_container_copy_construction())
  {       // construct map by copying _Right
  }

  map(const _Myt& _Right, const allocator_type& _Al)
    : _Mybase(_Right, _Al)
  {       // construct map by copying _Right, allocator
  }

  explicit map(const key_compare& _Pred)
    : _Mybase(_Pred, allocator_type())
  {       // construct empty map from comparator
  }

  map(const key_compare& _Pred, const allocator_type& _Al)
    : _Mybase(_Pred, _Al)
  {       // construct empty map from comparator and allocator
  }

  template<class _Iter>
  map(_Iter _First, _Iter _Last)
    : _Mybase(key_compare(), allocator_type())
  {       // construct map from [_First, _Last), defaults
    _Mybase::insert(_First, _Last);
  }

  template<class _Iter>
  map(_Iter _First, _Iter _Last,
      const key_compare& _Pred)
    : _Mybase(_Pred, allocator_type())
  {       // construct map from [_First, _Last), comparator
    _Mybase::insert(_First, _Last);
  }

  template<class _Iter>
  map(_Iter _First, _Iter _Last,
      const allocator_type& _Al)
    : _Mybase(key_compare(), _Al)
  {       // construct map from [_First, _Last), comparator, and allocator
    _Mybase::insert(_First, _Last);
  }

  template<class _Iter>
  map(_Iter _First, _Iter _Last,
      const key_compare& _Pred, const allocator_type& _Al)
    : _Mybase(_Pred, _Al)
  {       // construct map from [_First, _Last), comparator, and allocator
    _Mybase::insert(_First, _Last);
  }

  _Myt& operator=(const _Myt& _Right)
  {       // assign by copying _Right
    _Mybase::operator=(_Right);
    return *this;
  }

  map(_Myt&& _Right)
    : _Mybase(std::move(_Right))
  {       // construct map by moving _Right
  }

  map(_Myt&& _Right, const allocator_type& _Al)
    : _Mybase(std::move(_Right), _Al)
  {       // construct map by moving _Right, allocator
  }

  _Myt& operator=(_Myt&& _Right)
    _NOEXCEPT_OP(   _Alty::is_always_equal::value
                 && is_nothrow_move_assignable<_Pr>::value)
  {       // assign by moving _Right
    _Mybase::operator=(std::move(_Right));
    return *this;
  }

  mapped_type& operator[](key_type&& _Keyval)
  {       // find element matching _Keyval or insert with default mapped
    iterator _Where = _Mybase::lower_bound(_Keyval);
    if (   _Where == _Mybase::end()
        || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode())))
      _Where = _Mybase::emplace_hint(_Where,
                                     piecewise_construct,
                                     std::forward_as_tuple(std::move(_Keyval)),
                                     tuple<>());

    return _Where->second;
  }

  void swap(_Myt& _Right)
    _NOEXCEPT_OP(   _Alty::is_always_equal::value
                 && _NOEXCEPT_OP(_Swap_adl(
                                   std::declval<_Pr&>(), std::declval<_Pr&>())))
  {       // exchange contents with non-movable _Right
    _Mybase::swap(_Right);
  }

  #if _HAS_CPP17
    template<class _Keyty, class... _Mappedty>
    _Pairib _Try_emplace(_Keyty&& _Keyval,
                         _Mappedty&&... _Mapval)
    {	// fail if _Keyval present, else emplace
      iterator _Where = _Mybase::lower_bound(_Keyval);
      if (   _Where == _Mybase::end()
          || _DEBUG_LT_PRED(_Mybase::_Getcomp(),
                            _Keyval, _Mybase::_Key(_Where._Mynode())))
        return _Pairib(_Mybase::emplace_hint(_Where,
                                             piecewise_construct,
                                             std::forward_as_tuple(
                                                std::forward<_Keyty>(_Keyval)),
                                              std::forward_as_tuple(
                                          std::forward<_Mappedty>(_Mapval)...)),
                       true);
      else
        return _Pairib(_Where, false);
    }

    template<class... _Mappedty>
    _Pairib try_emplace(const key_type& _Keyval,
                        _Mappedty&&... _Mapval)
    {	// fail if _Keyval present, else emplace
      return _Try_emplace(_Keyval, std::forward<_Mappedty>(_Mapval)...);
    }

    template<class... _Mappedty>
    iterator try_emplace(const_iterator, const key_type& _Keyval,
                         _Mappedty&&... _Mapval)
    {	// fail if _Keyval present, else emplace, ignore hint
      return _Try_emplace(_Keyval, std::forward<_Mappedty>(_Mapval)...).first;
    }

    template<class... _Mappedty>
    _Pairib try_emplace(key_type&& _Keyval,
                        _Mappedty&&... _Mapval)
    {	// fail if _Keyval present, else emplace
      return _Try_emplace(std::move(_Keyval),
                          std::forward<_Mappedty>(_Mapval)...);
    }

    template<class... _Mappedty>
    iterator try_emplace(const_iterator, key_type&& _Keyval,
                         _Mappedty&&... _Mapval)
    {	// fail if _Keyval present, else emplace, ignore hint
      return _Try_emplace(std::move(_Keyval),
                          std::forward<_Mappedty>(_Mapval)...).first;
    }

    template<class _Keyty,
             class _Mappedty>
    _Pairib _Insert_or_assign(_Keyty&& _Keyval,
                              _Mappedty&& _Mapval)
    {	// assign if _Keyval present, else insert
      iterator _Where = _Mybase::lower_bound(_Keyval);
      if (   _Where == _Mybase::end()
          || _DEBUG_LT_PRED(_Mybase::_Getcomp(),
                            _Keyval, _Mybase::_Key(_Where._Mynode())))
        return _Pairib(_Mybase::emplace_hint(_Where,
                                             std::forward<_Keyty>(_Keyval),
                                             std::forward<_Mappedty>(_Mapval)),
                       true);
      else
      {	// _Keyval present, assign new value
        _Where->second = std::forward<_Mappedty>(_Mapval);
        return _Pairib(_Where, false);
      }
    }

    template<class _Mappedty>
    _Pairib insert_or_assign(const key_type& _Keyval,
                             _Mappedty&& _Mapval)
    {	// assign if _Keyval present, else insert
      return _Insert_or_assign(_Keyval,
                               std::forward<_Mappedty>(_Mapval));
    }

    template<class _Mappedty>
    iterator insert_or_assign(const_iterator, const key_type& _Keyval,
                              _Mappedty&& _Mapval)
    {	// assign if _Keyval present, else insert, ignore hint
      return _Insert_or_assign(_Keyval,
                               std::forward<_Mappedty>(_Mapval)).first;
    }

    template<class _Mappedty>
    _Pairib insert_or_assign(key_type&& _Keyval,
                             _Mappedty&& _Mapval)
    {	// assign if _Keyval present, else insert
      return _Insert_or_assign(std::move(_Keyval),
                               std::forward<_Mappedty>(_Mapval));
    }

    template<class _Mappedty>
    iterator insert_or_assign(const_iterator, key_type&& _Keyval,
                              _Mappedty&& _Mapval)
    {	// assign if _Keyval present, else insert, ignore hint
      return _Insert_or_assign(std::move(_Keyval),
                               std::forward<_Mappedty>(_Mapval)).first;
    }
  #endif /* _HAS_CPP17 */

  map(::std::initializer_list<value_type> _Ilist)
    : _Mybase(key_compare(), allocator_type())
  {       // construct from initializer_list, defaults
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  map(::std::initializer_list<value_type> _Ilist,
      const key_compare& _Pred)
    : _Mybase(_Pred, allocator_type())
  {       // construct from initializer_list, comparator
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  map(::std::initializer_list<value_type> _Ilist,
      const key_compare& _Pred, const allocator_type& _Al)
    : _Mybase(_Pred, _Al)
  {       // construct from initializer_list, comparator, and allocator
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  _Myt& operator=(::std::initializer_list<value_type> _Ilist)
  {       // assign initializer_list
    _Mybase::clear();
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
    return *this;
  }

  // void insert(::std::initializer_list<value_type> _Ilist)
  // {       // insert initializer_list
  //   _Mybase::insert(_Ilist.begin(), _Ilist.end());
  // }

  mapped_type& operator[](const key_type& _Keyval)
  {       // find element matching _Keyval or insert with default mapped
    iterator _Where = _Mybase::lower_bound(_Keyval);
    if (   _Where == _Mybase::end()
        || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode())))
      _Where = _Mybase::emplace_hint(_Where,
                                     piecewise_construct,
                                     std::forward_as_tuple(_Keyval),
                                     tuple<>());

    return _Where->second;
  }

  mapped_type& at(const key_type& _Keyval)
  {       // find element matching _Keyval
    iterator _Where = _Mybase::lower_bound(_Keyval);
    if (   _Where == _Mybase::end()
        || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode())))
      __iar_Raise_key();
    return _Where->second;
  }

  const mapped_type& at(const key_type& _Keyval) const
  {       // find element matching _Keyval
    const_iterator _Where = this->lower_bound(_Keyval);
    if (   _Where == this->end()
        || this->_Getcomp()(_Keyval, this->_Key(_Where._Mynode())))
      __iar_Raise_key();
    return _Where->second;
  }
};

template<class _Kty,
         class _Ty,
         class _Pr,
         class _Alloc> inline
void swap(map<_Kty, _Ty, _Pr, _Alloc>& _Left,
          map<_Kty, _Ty, _Pr, _Alloc>& _Right)
  _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
{       // swap _Left and _Right maps
  _Left.swap(_Right);
}

// TEMPLATE CLASS multimap
template<class _Kty,
         class _Ty,
         class _Pr = less<_Kty>,
         class _Alloc = allocator<pair<const _Kty, _Ty> > >
class multimap
  : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, true> >
{       // ordered red-black tree of {key, mapped} values, non-unique keys
public:
  typedef multimap<_Kty, _Ty, _Pr, _Alloc> _Myt;
  typedef _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, true> > _Mybase;
  typedef _Kty key_type;
  typedef _Ty mapped_type;
  typedef _Pr key_compare;
  typedef typename _Mybase::value_compare value_compare;
  typedef typename _Mybase::allocator_type allocator_type;
  typedef typename _Mybase::size_type size_type;
  typedef typename _Mybase::difference_type difference_type;
  typedef typename _Mybase::pointer pointer;
  typedef typename _Mybase::const_pointer const_pointer;
  typedef typename _Mybase::reference reference;
  typedef typename _Mybase::const_reference const_reference;
  typedef typename _Mybase::iterator iterator;
  typedef typename _Mybase::const_iterator const_iterator;
  typedef typename _Mybase::reverse_iterator reverse_iterator;
  typedef typename _Mybase::const_reverse_iterator
  const_reverse_iterator;
  typedef typename _Mybase::value_type value_type;

  typedef typename _Mybase::_Alty _Alty;

  multimap()
    : _Mybase(key_compare(), allocator_type())
  {       // construct empty map from defaults
  }

  explicit multimap(const allocator_type& _Al)
    : _Mybase(key_compare(), _Al)
  {       // construct empty map from defaults, allocator
  }

  multimap(const _Myt& _Right)
    : _Mybase(_Right,
              _Right._Getal().select_on_container_copy_construction())
  {       // construct map by copying _Right
  }

  multimap(const _Myt& _Right, const allocator_type& _Al)
    : _Mybase(_Right, _Al)
  {       // construct map by copying _Right, allocator
  }

  explicit multimap(const key_compare& _Pred)
    : _Mybase(_Pred, allocator_type())
  {       // construct empty map from comparator
  }

  multimap(const key_compare& _Pred, const allocator_type& _Al)
    : _Mybase(_Pred, _Al)
  {       // construct empty map from comparator and allocator
  }

  template<class _Iter>
  multimap(_Iter _First, _Iter _Last)
    : _Mybase(key_compare(), allocator_type())
  {       // construct map from [_First, _Last), defaults
    _Mybase::insert(_First, _Last);
  }

  template<class _Iter>
  multimap(_Iter _First, _Iter _Last,
           const key_compare& _Pred)
    : _Mybase(_Pred, allocator_type())
  {       // construct map from [_First, _Last), comparator
    _Mybase::insert(_First, _Last);
  }

  template<class _Iter>
  multimap(_Iter _First, _Iter _Last,
           const allocator_type& _Al)
    : _Mybase(key_compare(), _Al)
  {       // construct map from [_First, _Last), comparator, and allocator
    _Mybase::insert(_First, _Last);
  }

  template<class _Iter>
  multimap(_Iter _First, _Iter _Last,
           const key_compare& _Pred, const allocator_type& _Al)
    : _Mybase(_Pred, _Al)
  {       // construct map from [_First, _Last), comparator, and allocator
    _Mybase::insert(_First, _Last);
  }

  _Myt& operator=(const _Myt& _Right)
  {       // assign by copying _Right
    _Mybase::operator=(_Right);
    return *this;
  }

  multimap(_Myt&& _Right)
    : _Mybase(std::move(_Right))
  {       // construct map by moving _Right
  }

  multimap(_Myt&& _Right, const allocator_type& _Al)
    : _Mybase(std::move(_Right), _Al)
  {       // construct map by moving _Right
  }

  _Myt& operator=(_Myt&& _Right)
    _NOEXCEPT_OP(   _Alty::is_always_equal::value
                 && is_nothrow_move_assignable<_Pr>::value)
  {       // assign by moving _Right
    _Mybase::operator=(std::move(_Right));
    return *this;
  }

  template<class _Valty>
  typename enable_if<is_convertible<_Valty, value_type>::value,
                     iterator>::type
  insert(_Valty&& _Val)
  {       // insert a {key, mapped} value
    return _Mybase::insert(std::forward<_Valty>(_Val)).first;
  }

  template<class _Valty>
  typename enable_if<is_convertible<_Valty, value_type>::value,
                     iterator>::type
  insert(const_iterator _Where, _Valty&& _Val)
  {       // insert a {key, mapped} value, with hint
    return _Mybase::insert(_Where, std::forward<_Valty>(_Val));
  }

  template<class... _Valty>
  iterator emplace(_Valty&&... _Val)
  {       // try to insert value_type(_Val...), favoring right side
    return _Mybase::emplace(std::forward<_Valty>(_Val)...).first;
  }

  void swap(_Myt& _Right)
    _NOEXCEPT_OP(   _Alty::is_always_equal::value
                 && _NOEXCEPT_OP(_Swap_adl(
                                   std::declval<_Pr&>(), std::declval<_Pr&>())))
  {       // exchange contents with non-movable _Right
    _Mybase::swap(_Right);
  }

  multimap(::std::initializer_list<value_type> _Ilist)
    : _Mybase(key_compare(), allocator_type())
  {       // construct from initializer_list, defaults
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  multimap(::std::initializer_list<value_type> _Ilist,
           const key_compare& _Pred)
    : _Mybase(_Pred, allocator_type())
  {       // construct from initializer_list, comparator
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  multimap(::std::initializer_list<value_type> _Ilist,
           const key_compare& _Pred, const allocator_type& _Al)
    : _Mybase(_Pred, _Al)
  {       // construct from initializer_list, comparator, and allocator
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  _Myt& operator=(::std::initializer_list<value_type> _Ilist)
  {       // assign initializer_list
    _Mybase::clear();
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
    return (*this);
  }

  void insert(::std::initializer_list<value_type> _Ilist)
  {       // insert initializer_list
    _Mybase::insert(_Ilist.begin(), _Ilist.end());
  }

  iterator insert(const value_type& _Val)
  {       // insert a {key, mapped} value
    return _Mybase::insert(_Val).first;
  }

  iterator insert(const_iterator _Where, const value_type& _Val)
  {       // insert a {key, mapped} value, with hint
    return _Mybase::insert(_Where, _Val);
  }

  template<class _Iter>
  void insert(_Iter _First, _Iter _Last)
  {       // insert [_First, _Last), arbitrary iterators
    _Mybase::insert(_First, _Last);
  }
};

template<class _Kty,
         class _Ty,
         class _Pr,
         class _Alloc> inline
void swap(multimap<_Kty, _Ty, _Pr, _Alloc>& _Left,
          multimap<_Kty, _Ty, _Pr, _Alloc>& _Right)
  _NOEXCEPT_OP(_NOEXCEPT_OP(_Left.swap(_Right)))
{       // swap _Left and _Right multimaps
  _Left.swap(_Right);
}

} /* namespace std */

#endif /* _MAP_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
