/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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.
 */

#ifndef ART_RUNTIME_SAFE_MAP_H_
#define ART_RUNTIME_SAFE_MAP_H_

#include <map>
#include <memory>

#include "base/logging.h"

namespace art {

// Equivalent to std::map, but without operator[] and its bug-prone semantics (in particular,
// the implicit insertion of a default-constructed value on failed lookups).
template <typename K, typename V, typename Comparator = std::less<K>,
          typename Allocator = std::allocator<std::pair<const K, V>>>
class SafeMap {
 private:
  typedef SafeMap<K, V, Comparator, Allocator> Self;

 public:
  typedef typename ::std::map<K, V, Comparator, Allocator>::key_compare key_compare;
  typedef typename ::std::map<K, V, Comparator, Allocator>::allocator_type allocator_type;
  typedef typename ::std::map<K, V, Comparator, Allocator>::iterator iterator;
  typedef typename ::std::map<K, V, Comparator, Allocator>::const_iterator const_iterator;
  typedef typename ::std::map<K, V, Comparator, Allocator>::size_type size_type;
  typedef typename ::std::map<K, V, Comparator, Allocator>::value_type value_type;

  SafeMap() = default;
  explicit SafeMap(const key_compare& cmp, const allocator_type& allocator = allocator_type())
    : map_(cmp, allocator) {
  }

  Self& operator=(const Self& rhs) {
    map_ = rhs.map_;
    return *this;
  }

  iterator begin() { return map_.begin(); }
  const_iterator begin() const { return map_.begin(); }
  iterator end() { return map_.end(); }
  const_iterator end() const { return map_.end(); }

  bool empty() const { return map_.empty(); }
  size_type size() const { return map_.size(); }

  void clear() { map_.clear(); }
  void erase(iterator it) { map_.erase(it); }
  size_type erase(const K& k) { return map_.erase(k); }

  iterator find(const K& k) { return map_.find(k); }
  const_iterator find(const K& k) const { return map_.find(k); }

  iterator lower_bound(const K& k) { return map_.lower_bound(k); }
  const_iterator lower_bound(const K& k) const { return map_.lower_bound(k); }

  size_type count(const K& k) const { return map_.count(k); }

  // Note that unlike std::map's operator[], this doesn't return a reference to the value.
  V Get(const K& k) const {
    const_iterator it = map_.find(k);
    DCHECK(it != map_.end());
    return it->second;
  }

  // Used to insert a new mapping.
  void Put(const K& k, const V& v) {
    std::pair<iterator, bool> result = map_.insert(std::make_pair(k, v));
    DCHECK(result.second);  // Check we didn't accidentally overwrite an existing value.
  }

  // Used to insert a new mapping or overwrite an existing mapping. Note that if the value type
  // of this container is a pointer, any overwritten pointer will be lost and if this container
  // was the owner, you have a leak.
  void Overwrite(const K& k, const V& v) {
    std::pair<iterator, bool> result = map_.insert(std::make_pair(k, v));
    if (!result.second) {
      // Already there - update the value for the existing key
      result.first->second = v;
    }
  }

  bool Equals(const Self& rhs) const {
    return map_ == rhs.map_;
  }

 private:
  ::std::map<K, V, Comparator, Allocator> map_;
};

template <typename K, typename V, typename Comparator>
bool operator==(const SafeMap<K, V, Comparator>& lhs, const SafeMap<K, V, Comparator>& rhs) {
  return lhs.Equals(rhs);
}

template <typename K, typename V, typename Comparator>
bool operator!=(const SafeMap<K, V, Comparator>& lhs, const SafeMap<K, V, Comparator>& rhs) {
  return !(lhs == rhs);
}

}  // namespace art

#endif  // ART_RUNTIME_SAFE_MAP_H_
