205 lines
5.8 KiB
C++
205 lines
5.8 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
// @author: Pavlo Kushnir (pavlo)
|
|
|
|
#pragma once
|
|
|
|
#include <initializer_list>
|
|
#include <map>
|
|
#include <memory>
|
|
|
|
#include <folly/Range.h>
|
|
#include <folly/experimental/StringKeyedCommon.h>
|
|
|
|
namespace folly {
|
|
|
|
/**
|
|
* Wrapper class for map<string, Value> that can
|
|
* perform lookup operations with StringPiece, not only string.
|
|
*
|
|
* It uses kind of hack: string pointed by StringPiece is copied when
|
|
* StringPiece is inserted into map
|
|
*/
|
|
template <
|
|
class Value,
|
|
class Compare = std::less<StringPiece>,
|
|
class Alloc = std::allocator<std::pair<const StringPiece, Value>>>
|
|
class StringKeyedMap : private std::map<StringPiece, Value, Compare, Alloc> {
|
|
private:
|
|
using Base = std::map<StringPiece, Value, Compare, Alloc>;
|
|
|
|
public:
|
|
typedef typename Base::key_type key_type;
|
|
typedef typename Base::mapped_type mapped_type;
|
|
typedef typename Base::value_type value_type;
|
|
typedef typename Base::key_compare key_compare;
|
|
typedef typename Base::allocator_type allocator_type;
|
|
typedef typename Base::reference reference;
|
|
typedef typename Base::const_reference const_reference;
|
|
typedef typename Base::pointer pointer;
|
|
typedef typename Base::const_pointer const_pointer;
|
|
typedef typename Base::iterator iterator;
|
|
typedef typename Base::const_iterator const_iterator;
|
|
typedef typename Base::reverse_iterator reverse_iterator;
|
|
typedef typename Base::const_reverse_iterator const_reverse_iterator;
|
|
typedef typename Base::difference_type difference_type;
|
|
typedef typename Base::size_type size_type;
|
|
|
|
using Base::get_allocator;
|
|
|
|
// Ctors in the same order as
|
|
// http://cplusplus.com/reference/map/map/map/
|
|
explicit StringKeyedMap(
|
|
const key_compare& comp = key_compare(),
|
|
const allocator_type& alloc = allocator_type())
|
|
: Base(comp, alloc) {}
|
|
|
|
explicit StringKeyedMap(const allocator_type& alloc) : Base(alloc) {}
|
|
|
|
template <class InputIterator>
|
|
explicit StringKeyedMap(
|
|
InputIterator b,
|
|
InputIterator e,
|
|
const key_compare& comp = key_compare(),
|
|
const allocator_type& alloc = allocator_type())
|
|
: Base(comp, alloc) {
|
|
for (; b != e; ++b) {
|
|
// emplace() will carry the duplication
|
|
emplace(b->first, b->second);
|
|
}
|
|
}
|
|
|
|
StringKeyedMap(const StringKeyedMap& rhs)
|
|
: StringKeyedMap(rhs, rhs.get_allocator()) {}
|
|
|
|
StringKeyedMap(const StringKeyedMap& rhs, const allocator_type& a)
|
|
: StringKeyedMap(rhs.begin(), rhs.end(), rhs.key_comp(), a) {}
|
|
|
|
StringKeyedMap(StringKeyedMap&& other) noexcept : Base(std::move(other)) {}
|
|
|
|
StringKeyedMap(StringKeyedMap&& other, const allocator_type& /* a */) noexcept
|
|
: Base(std::move(other) /*, a*/ /* not supported by gcc */) {}
|
|
|
|
StringKeyedMap(
|
|
std::initializer_list<value_type> il,
|
|
const key_compare& comp = key_compare(),
|
|
const allocator_type& alloc = allocator_type())
|
|
: StringKeyedMap(il.begin(), il.end(), comp, alloc) {}
|
|
|
|
StringKeyedMap& operator=(const StringKeyedMap& other) & {
|
|
if (this == &other) {
|
|
return *this;
|
|
}
|
|
return *this = StringKeyedMap(other);
|
|
}
|
|
|
|
StringKeyedMap& operator=(StringKeyedMap&& other) & noexcept {
|
|
assert(this != &other);
|
|
clear();
|
|
Base::operator=(std::move(other));
|
|
return *this;
|
|
}
|
|
|
|
using Base::begin;
|
|
using Base::cbegin;
|
|
using Base::cend;
|
|
using Base::crbegin;
|
|
using Base::crend;
|
|
using Base::empty;
|
|
using Base::end;
|
|
using Base::max_size;
|
|
using Base::rbegin;
|
|
using Base::rend;
|
|
using Base::size;
|
|
|
|
bool operator==(StringKeyedMap const& other) const {
|
|
Base const& lhs = *this;
|
|
Base const& rhs = static_cast<Base const&>(other);
|
|
return lhs == rhs;
|
|
}
|
|
|
|
// no need for copy/move overload as StringPiece is small struct
|
|
mapped_type& operator[](StringPiece key) {
|
|
auto it = find(key);
|
|
if (it != end()) {
|
|
return it->second;
|
|
}
|
|
// operator[] will create new (key, value) pair
|
|
// we need to allocate memory for key
|
|
return Base::operator[](stringPieceDup(key, get_allocator()));
|
|
}
|
|
|
|
using Base::at;
|
|
using Base::count;
|
|
using Base::find;
|
|
using Base::lower_bound;
|
|
using Base::upper_bound;
|
|
|
|
template <class... Args>
|
|
std::pair<iterator, bool> emplace(StringPiece key, Args&&... args) {
|
|
auto it = find(key);
|
|
if (it != end()) {
|
|
return {it, false};
|
|
}
|
|
return Base::emplace(
|
|
stringPieceDup(key, get_allocator()), std::forward<Args>(args)...);
|
|
}
|
|
|
|
std::pair<iterator, bool> insert(value_type val) {
|
|
auto it = find(val.first);
|
|
if (it != end()) {
|
|
return {it, false};
|
|
}
|
|
return Base::insert(std::make_pair(
|
|
stringPieceDup(val.first, get_allocator()), std::move(val.second)));
|
|
}
|
|
|
|
iterator erase(const_iterator position) {
|
|
auto key = position->first;
|
|
auto result = Base::erase(position);
|
|
stringPieceDel(key, get_allocator());
|
|
return result;
|
|
}
|
|
|
|
size_type erase(StringPiece key) {
|
|
auto it = find(key);
|
|
if (it == end()) {
|
|
return 0;
|
|
}
|
|
erase(it);
|
|
return 1;
|
|
}
|
|
|
|
void clear() noexcept {
|
|
for (auto& it : *this) {
|
|
stringPieceDel(it.first, get_allocator());
|
|
}
|
|
Base::clear();
|
|
}
|
|
|
|
using Base::swap;
|
|
|
|
~StringKeyedMap() {
|
|
// Here we assume that map doesn't use keys in destructor
|
|
for (auto& it : *this) {
|
|
stringPieceDel(it.first, get_allocator());
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace folly
|