summaryrefslogtreecommitdiff
path: root/base/containers/scoped_ptr_map.h
blob: 19a115316efb32dd1bd688ec70a899aae79699b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_CONTAINERS_SCOPED_PTR_MAP_H_
#define BASE_CONTAINERS_SCOPED_PTR_MAP_H_

#include <map>
#include <utility>

#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/move.h"
#include "base/stl_util.h"

// ScopedPtrMap provides a std::map that supports scoped_ptr values. It ensures
// that the map's values are properly deleted when removed from the map, or when
// the map is destroyed.
//
// |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
// std::map in C++11.
template <class Key, class ScopedPtr>
class ScopedPtrMap {
  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)

  using Container = std::map<Key, typename ScopedPtr::element_type*>;

 public:
  using allocator_type = typename Container::allocator_type;
  using size_type = typename Container::size_type;
  using difference_type = typename Container::difference_type;
  using reference = typename Container::reference;
  using const_reference = typename Container::const_reference;
  using key_type = typename Container::key_type;
  using const_iterator = typename Container::const_iterator;
  using const_reverse_iterator = typename Container::const_reverse_iterator;

  ScopedPtrMap() {}
  ~ScopedPtrMap() { clear(); }
  ScopedPtrMap(ScopedPtrMap<Key, ScopedPtr>&& other) { swap(other); }

  ScopedPtrMap& operator=(ScopedPtrMap<Key, ScopedPtr>&& rhs) {
    swap(rhs);
    return *this;
  }

  const_iterator find(const Key& k) const { return data_.find(k); }
  size_type count(const Key& k) const { return data_.count(k); }

  bool empty() const { return data_.empty(); }
  size_t size() const { return data_.size(); }

  const_reverse_iterator rbegin() const { return data_.rbegin(); }
  const_reverse_iterator rend() const { return data_.rend(); }

  const_iterator begin() const { return data_.begin(); }
  const_iterator end() const { return data_.end(); }

  void swap(ScopedPtrMap<Key, ScopedPtr>& other) { data_.swap(other.data_); }

  void clear() { STLDeleteValues(&data_); }

  // Inserts |val| into the map, associated with |key|.
  std::pair<const_iterator, bool> insert(const Key& key, ScopedPtr val) {
    auto result = data_.insert(std::make_pair(key, val.get()));
    if (result.second)
      ignore_result(val.release());
    return result;
  }

  // Inserts |val| into the map, associated with |key|. Overwrites any existing
  // element at |key|.
  void set(const Key& key, ScopedPtr val) {
    typename ScopedPtr::element_type*& val_ref = data_[key];
    delete val_ref;
    val_ref = val.release();
  }

  void erase(const_iterator position) {
    DCHECK(position != end());
    delete position->second;
    // Key-based lookup (cannot use const_iterator overload in C++03 library).
    data_.erase(position->first);
  }

  size_type erase(const Key& k) {
    typename Container::iterator it = data_.find(k);
    if (it == end())
      return 0;

    delete it->second;
    data_.erase(it);
    return 1;
  }

  void erase(const_iterator first, const_iterator last) {
    STLDeleteContainerPairSecondPointers(first, last);
    // Need non-const iterators as required by the C++03 library.
    data_.erase(ConstIteratorToIterator(first), ConstIteratorToIterator(last));
  }

  // Like |erase()|, but returns the element instead of deleting it.
  ScopedPtr take_and_erase(const_iterator position) {
    DCHECK(position != end());
    if (position == end())
      return ScopedPtr();

    ScopedPtr ret(position->second);
    // Key-based lookup (cannot use const_iterator overload in C++03 library).
    data_.erase(position->first);
    return ret.Pass();
  }

  // Like |erase()|, but returns the element instead of deleting it.
  ScopedPtr take_and_erase(const Key& k) {
    typename Container::iterator it = data_.find(k);
    if (it == end())
      return ScopedPtr();

    ScopedPtr ret(it->second);
    data_.erase(it);
    return ret.Pass();
  }

 private:
  Container data_;

  typename Container::iterator ConstIteratorToIterator(const_iterator it) {
    // This is the only way to convert a const iterator to a non-const iterator
    // in C++03 (get the key and do the lookup again).
    if (it == data_.end())
      return data_.end();
    return data_.find(it->first);
  };
};

#endif  // BASE_CONTAINERS_SCOPED_PTR_MAP_H_