Add StringKeyed(Unordered){Set,Map} to folly
[folly.git] / folly / experimental / StringKeyedMap.h
1 /*
2  * Copyright 2015 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 #ifndef FOLLY_EXPERIMENTAL_STRINGKEYEDMAP_H_
20 #define FOLLY_EXPERIMENTAL_STRINGKEYEDMAP_H_
21
22 #include <initializer_list>
23 #include <memory>
24 #include <map>
25 #include <folly/Range.h>
26 #include <folly/experimental/StringKeyedCommon.h>
27
28 namespace folly {
29
30 /**
31  * Wrapper class for map<string, Value> that can
32  * perform lookup operations with StringPiece, not only string.
33  *
34  * It uses kind of hack: string pointed by StringPiece is copied when
35  * StringPiece is inserted into map
36  */
37 template <class Value,
38           class Compare = std::less<StringPiece>,
39           class Alloc = std::allocator<std::pair<const StringPiece, Value>>>
40 class StringKeyedMap
41     : private std::map<StringPiece, Value, Compare, Alloc> {
42 private:
43   using Base = std::map<StringPiece, Value, Compare, Alloc>;
44
45 public:
46   typedef typename Base::key_type key_type;
47   typedef typename Base::mapped_type mapped_type;
48   typedef typename Base::value_type value_type;
49   typedef typename Base::key_compare key_compare;
50   typedef typename Base::allocator_type allocator_type;
51   typedef typename Base::reference reference;
52   typedef typename Base::const_reference const_reference;
53   typedef typename Base::pointer pointer;
54   typedef typename Base::const_pointer const_pointer;
55   typedef typename Base::iterator iterator;
56   typedef typename Base::const_iterator const_iterator;
57   typedef typename Base::reverse_iterator reverse_iterator;
58   typedef typename Base::const_reverse_iterator const_reverse_iterator;
59   typedef typename Base::difference_type difference_type;
60   typedef typename Base::size_type size_type;
61
62   using Base::get_allocator;
63
64   // Ctors in the same order as
65   // http://cplusplus.com/reference/map/map/map/
66   explicit StringKeyedMap(
67     const key_compare& comp = key_compare(),
68     const allocator_type& alloc = allocator_type())
69       : Base(comp, alloc) {
70   }
71
72   explicit StringKeyedMap(const allocator_type& alloc)
73       : Base(alloc) {
74   }
75
76   template <class InputIterator>
77   explicit StringKeyedMap(
78     InputIterator b, InputIterator e,
79     const key_compare& comp = key_compare(),
80     const allocator_type& alloc = allocator_type())
81       : Base(comp, alloc) {
82     for (; b != e; ++b) {
83       // emplace() will carry the duplication
84       emplace(b->first, b->second);
85     }
86   }
87
88   StringKeyedMap(const StringKeyedMap& rhs)
89       : StringKeyedMap(rhs, rhs.get_allocator()) {
90   }
91
92   StringKeyedMap(const StringKeyedMap& rhs, const allocator_type& a)
93       : StringKeyedMap(rhs.begin(), rhs.end(), rhs.key_comp(), a) {
94   }
95
96   StringKeyedMap(StringKeyedMap&& other) noexcept
97     : Base(std::move(other)) {
98   }
99
100   StringKeyedMap(StringKeyedMap&& other, const allocator_type& a) noexcept
101       : Base(std::move(other)/*, a*/ /* not supported by gcc */) {
102   }
103
104   StringKeyedMap(std::initializer_list<value_type> il,
105      const key_compare& comp = key_compare(),
106      const allocator_type& alloc = allocator_type())
107       : StringKeyedMap(il.begin(), il.end(), comp, alloc) {
108   }
109
110   StringKeyedMap& operator=(const StringKeyedMap& other) & {
111     if (this == &other) {
112       return *this;
113     }
114     return *this = StringKeyedMap(other);
115   }
116
117   StringKeyedMap& operator=(StringKeyedMap&& other) & noexcept {
118     assert(this != &other);
119     clear();
120     Base::operator=(std::move(other));
121     return *this;
122   }
123
124   using Base::empty;
125   using Base::size;
126   using Base::max_size;
127   using Base::begin;
128   using Base::end;
129   using Base::rbegin;
130   using Base::rend;
131   using Base::cbegin;
132   using Base::cend;
133   using Base::crbegin;
134   using Base::crend;
135
136   // no need for copy/move overload as StringPiece is small struct
137   mapped_type& operator[](StringPiece key) {
138     auto it = find(key);
139     if (it != end()) {
140       return it->second;
141     }
142     // operator[] will create new (key, value) pair
143     // we need to allocate memory for key
144     return Base::operator[](stringPieceDup(key, get_allocator()));
145   }
146
147   using Base::at;
148   using Base::find;
149   using Base::lower_bound;
150   using Base::upper_bound;
151
152   template <class... Args>
153   std::pair<iterator, bool> emplace(StringPiece key, Args&&... args) {
154     auto it = find(key);
155     if (it != end()) {
156       return {it, false};
157     }
158     return Base::emplace(stringPieceDup(key, get_allocator()),
159                          std::forward<Args>(args)...);
160   }
161
162   std::pair<iterator, bool> insert(value_type val) {
163     auto it = find(val.first);
164     if (it != end()) {
165       return {it, false};
166     }
167     return Base::insert(
168       std::make_pair(stringPieceDup(val.first, get_allocator()),
169                      std::move(val.second)));
170   }
171
172   iterator erase(const_iterator position) {
173     auto key = position->first;
174     auto result = Base::erase(position);
175     stringPieceDel(key, get_allocator());
176     return result;
177   }
178
179   size_type erase(StringPiece key) {
180     auto it = find(key);
181     if (it == end()) {
182       return 0;
183     }
184     erase(it);
185     return 1;
186   }
187
188   void clear() noexcept {
189     for (auto& it : *this) {
190       stringPieceDel(it.first, get_allocator());
191     }
192     Base::clear();
193   }
194
195   ~StringKeyedMap() {
196     // Here we assume that map doesn't use keys in destructor
197     for (auto& it : *this) {
198       stringPieceDel(it.first, get_allocator());
199     }
200   }
201 };
202
203 } // folly
204
205 #endif /* FOLLY_EXPERIMENTAL_STRINGKEYEDMAP_H_ */