d8b822c74474365832b21c4ec421bc537019a9bf
[folly.git] / folly / experimental / StringKeyedMap.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 // Copyright 2013-present Facebook. All Rights Reserved.
17 // @author: Pavlo Kushnir (pavlo)
18
19 #pragma once
20
21 #include <initializer_list>
22 #include <memory>
23 #include <map>
24 #include <folly/Range.h>
25 #include <folly/experimental/StringKeyedCommon.h>
26
27 namespace folly {
28
29 /**
30  * Wrapper class for map<string, Value> that can
31  * perform lookup operations with StringPiece, not only string.
32  *
33  * It uses kind of hack: string pointed by StringPiece is copied when
34  * StringPiece is inserted into map
35  */
36 template <class Value,
37           class Compare = std::less<StringPiece>,
38           class Alloc = std::allocator<std::pair<const StringPiece, Value>>>
39 class StringKeyedMap
40     : private std::map<StringPiece, Value, Compare, Alloc> {
41 private:
42   using Base = std::map<StringPiece, Value, Compare, Alloc>;
43
44 public:
45   typedef typename Base::key_type key_type;
46   typedef typename Base::mapped_type mapped_type;
47   typedef typename Base::value_type value_type;
48   typedef typename Base::key_compare key_compare;
49   typedef typename Base::allocator_type allocator_type;
50   typedef typename Base::reference reference;
51   typedef typename Base::const_reference const_reference;
52   typedef typename Base::pointer pointer;
53   typedef typename Base::const_pointer const_pointer;
54   typedef typename Base::iterator iterator;
55   typedef typename Base::const_iterator const_iterator;
56   typedef typename Base::reverse_iterator reverse_iterator;
57   typedef typename Base::const_reverse_iterator const_reverse_iterator;
58   typedef typename Base::difference_type difference_type;
59   typedef typename Base::size_type size_type;
60
61   using Base::get_allocator;
62
63   // Ctors in the same order as
64   // http://cplusplus.com/reference/map/map/map/
65   explicit StringKeyedMap(
66     const key_compare& comp = key_compare(),
67     const allocator_type& alloc = allocator_type())
68       : Base(comp, alloc) {
69   }
70
71   explicit StringKeyedMap(const allocator_type& alloc)
72       : Base(alloc) {
73   }
74
75   template <class InputIterator>
76   explicit StringKeyedMap(
77     InputIterator b, InputIterator e,
78     const key_compare& comp = key_compare(),
79     const allocator_type& alloc = allocator_type())
80       : Base(comp, alloc) {
81     for (; b != e; ++b) {
82       // emplace() will carry the duplication
83       emplace(b->first, b->second);
84     }
85   }
86
87   StringKeyedMap(const StringKeyedMap& rhs)
88       : StringKeyedMap(rhs, rhs.get_allocator()) {
89   }
90
91   StringKeyedMap(const StringKeyedMap& rhs, const allocator_type& a)
92       : StringKeyedMap(rhs.begin(), rhs.end(), rhs.key_comp(), a) {
93   }
94
95   StringKeyedMap(StringKeyedMap&& other) noexcept
96     : Base(std::move(other)) {
97   }
98
99   StringKeyedMap(StringKeyedMap&& other, const allocator_type& /* a */) noexcept
100       : Base(std::move(other) /*, a*/ /* not supported by gcc */) {}
101
102   StringKeyedMap(std::initializer_list<value_type> il,
103      const key_compare& comp = key_compare(),
104      const allocator_type& alloc = allocator_type())
105       : StringKeyedMap(il.begin(), il.end(), comp, alloc) {
106   }
107
108   StringKeyedMap& operator=(const StringKeyedMap& other) & {
109     if (this == &other) {
110       return *this;
111     }
112     return *this = StringKeyedMap(other);
113   }
114
115   StringKeyedMap& operator=(StringKeyedMap&& other) & noexcept {
116     assert(this != &other);
117     clear();
118     Base::operator=(std::move(other));
119     return *this;
120   }
121
122   using Base::empty;
123   using Base::size;
124   using Base::max_size;
125   using Base::begin;
126   using Base::end;
127   using Base::rbegin;
128   using Base::rend;
129   using Base::cbegin;
130   using Base::cend;
131   using Base::crbegin;
132   using Base::crend;
133
134   bool operator==(StringKeyedMap const& other) const {
135     Base const& lhs = *this;
136     Base const& rhs = static_cast<Base const&>(other);
137     return lhs == rhs;
138   }
139
140   // no need for copy/move overload as StringPiece is small struct
141   mapped_type& operator[](StringPiece key) {
142     auto it = find(key);
143     if (it != end()) {
144       return it->second;
145     }
146     // operator[] will create new (key, value) pair
147     // we need to allocate memory for key
148     return Base::operator[](stringPieceDup(key, get_allocator()));
149   }
150
151   using Base::at;
152   using Base::find;
153   using Base::count;
154   using Base::lower_bound;
155   using Base::upper_bound;
156
157   template <class... Args>
158   std::pair<iterator, bool> emplace(StringPiece key, Args&&... args) {
159     auto it = find(key);
160     if (it != end()) {
161       return {it, false};
162     }
163     return Base::emplace(stringPieceDup(key, get_allocator()),
164                          std::forward<Args>(args)...);
165   }
166
167   std::pair<iterator, bool> insert(value_type val) {
168     auto it = find(val.first);
169     if (it != end()) {
170       return {it, false};
171     }
172     return Base::insert(
173       std::make_pair(stringPieceDup(val.first, get_allocator()),
174                      std::move(val.second)));
175   }
176
177   iterator erase(const_iterator position) {
178     auto key = position->first;
179     auto result = Base::erase(position);
180     stringPieceDel(key, get_allocator());
181     return result;
182   }
183
184   size_type erase(StringPiece key) {
185     auto it = find(key);
186     if (it == end()) {
187       return 0;
188     }
189     erase(it);
190     return 1;
191   }
192
193   void clear() noexcept {
194     for (auto& it : *this) {
195       stringPieceDel(it.first, get_allocator());
196     }
197     Base::clear();
198   }
199
200   void swap(StringKeyedMap& other) & {
201     return Base::swap(other);
202   }
203
204   ~StringKeyedMap() {
205     // Here we assume that map doesn't use keys in destructor
206     for (auto& it : *this) {
207       stringPieceDel(it.first, get_allocator());
208     }
209   }
210 };
211
212 } // folly