Use std::string in folly::dynamic
[folly.git] / folly / experimental / StringKeyedUnorderedMap.h
1 /*
2  * Copyright 2016 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 <unordered_map>
24 #include <folly/Range.h>
25 #include <folly/experimental/StringKeyedCommon.h>
26
27 namespace folly {
28
29 /**
30  * Wrapper class for unordered_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 Hash = StringPieceHash,
38           class Eq = std::equal_to<StringPiece>,
39           class Alloc = std::allocator<std::pair<const StringPiece, Value>>>
40 class StringKeyedUnorderedMap
41     : private std::unordered_map<StringPiece, Value, Hash, Eq, Alloc> {
42 private:
43   using Base = std::unordered_map<StringPiece, Value, Hash, Eq, 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::hasher hasher;
50   typedef typename Base::key_equal key_equal;
51   typedef typename Base::allocator_type allocator_type;
52   typedef typename Base::reference reference;
53   typedef typename Base::const_reference const_reference;
54   typedef typename Base::pointer pointer;
55   typedef typename Base::const_pointer const_pointer;
56   typedef typename Base::iterator iterator;
57   typedef typename Base::const_iterator const_iterator;
58   typedef typename Base::size_type size_type;
59   typedef typename Base::difference_type difference_type;
60
61   explicit StringKeyedUnorderedMap() = default;
62
63   explicit StringKeyedUnorderedMap(
64     size_type n,
65     const hasher& hf = hasher(),
66     const key_equal& eql = key_equal(),
67     const allocator_type& alloc = allocator_type())
68       : Base(n, hf, eql, alloc) {
69   }
70
71   explicit StringKeyedUnorderedMap(const allocator_type& a)
72       : Base(a) {
73   }
74
75   template <class InputIterator>
76   StringKeyedUnorderedMap(InputIterator b, InputIterator e) {
77     for (; b != e; ++b) {
78       // insert() will carry the duplication
79       emplace(b->first, b->second);
80     }
81   }
82
83   template <class InputIterator>
84   StringKeyedUnorderedMap(
85     InputIterator b, InputIterator e,
86     size_type n,
87     const hasher& hf = hasher(),
88     const key_equal& eql = key_equal(),
89     const allocator_type& alloc = allocator_type())
90       : Base(n, hf, eql, alloc) {
91     for (; b != e; ++b) {
92       // insert() will carry the duplication
93       emplace(b->first, b->second);
94     }
95   }
96
97   StringKeyedUnorderedMap(const StringKeyedUnorderedMap& rhs)
98       : StringKeyedUnorderedMap(rhs.begin(), rhs.end(),
99              rhs.bucket_count(),
100              rhs.hash_function(),
101              rhs.key_eq(),
102              rhs.get_allocator()) {
103   }
104
105   StringKeyedUnorderedMap(StringKeyedUnorderedMap&& rhs) noexcept
106       : StringKeyedUnorderedMap(std::move(rhs), rhs.get_allocator()) {
107   }
108
109   StringKeyedUnorderedMap(StringKeyedUnorderedMap&& other,
110                           const allocator_type& /* a */) noexcept
111       : Base(std::move(other) /*, a*/ /* not supported by gcc */) {}
112
113   StringKeyedUnorderedMap(std::initializer_list<value_type> il)
114       : StringKeyedUnorderedMap(il.begin(), il.end()) {
115   }
116
117   StringKeyedUnorderedMap(
118     std::initializer_list<value_type> il,
119     size_type n,
120     const hasher& hf = hasher(),
121     const key_equal& eql = key_equal(),
122     const allocator_type& alloc = allocator_type())
123       : StringKeyedUnorderedMap(il.begin(), il.end(), n, hf, eql, alloc) {
124   }
125
126   StringKeyedUnorderedMap& operator=(const StringKeyedUnorderedMap& other) & {
127     if (this == &other) {
128       return *this;
129     }
130     return *this = StringKeyedUnorderedMap(other);
131   }
132
133   StringKeyedUnorderedMap&
134   operator=(StringKeyedUnorderedMap&& other) & noexcept {
135     assert(this != &other);
136     clear();
137     Base::operator=(std::move(other));
138     return *this;
139   }
140
141   using Base::empty;
142   using Base::size;
143   using Base::max_size;
144   using Base::begin;
145   using Base::end;
146   using Base::cbegin;
147   using Base::cend;
148
149   bool operator==(const StringKeyedUnorderedMap& rhs) {
150     const Base& lhs = *this;
151     return lhs == rhs;
152   }
153
154   // No need for copy/move overload as StringPiece is small struct.
155   mapped_type& operator[](StringPiece key) {
156     auto it = find(key);
157     if (it != end()) {
158       return it->second;
159     }
160     // operator[] will create new (key, value) pair
161     // we need to allocate memory for key
162     return Base::operator[](stringPieceDup(key, get_allocator()));
163   }
164
165   using Base::at;
166   using Base::find;
167   using Base::count;
168
169   template <class... Args>
170   std::pair<iterator, bool> emplace(StringPiece key, Args&&... args) {
171     auto it = find(key);
172     if (it != end()) {
173       return {it, false};
174     }
175     return Base::emplace(stringPieceDup(key, get_allocator()),
176                          std::forward<Args>(args)...);
177   }
178
179   std::pair<iterator, bool> insert(value_type val) {
180     auto it = find(val.first);
181     if (it != end()) {
182       return {it, false};
183     }
184     auto valCopy = std::make_pair(stringPieceDup(val.first, get_allocator()),
185                                   std::move(val.second));
186     return Base::insert(valCopy);
187   }
188
189   iterator erase(const_iterator position) {
190     auto key = position->first;
191     auto result = Base::erase(position);
192     stringPieceDel(key, get_allocator());
193     return result;
194   }
195
196   size_type erase(StringPiece key) {
197     auto it = find(key);
198     if (it == end()) {
199       return 0;
200     }
201     erase(it);
202     return 1;
203   }
204
205   void clear() noexcept {
206     for (auto& it : *this) {
207       stringPieceDel(it.first, get_allocator());
208     }
209     Base::clear();
210   }
211
212   using Base::reserve;
213   using Base::hash_function;
214   using Base::key_eq;
215   using Base::get_allocator;
216   using Base::bucket_count;
217   using Base::max_bucket_count;
218   using Base::bucket_size;
219   using Base::bucket;
220
221   ~StringKeyedUnorderedMap() {
222     // Here we assume that unordered_map doesn't use keys in destructor
223     for (auto& it : *this) {
224       stringPieceDel(it.first, get_allocator());
225     }
226   }
227 };
228
229 } // folly