194 lines
5.3 KiB
C++
194 lines
5.3 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 <memory>
|
|
#include <set>
|
|
|
|
#include <folly/Range.h>
|
|
#include <folly/experimental/StringKeyedCommon.h>
|
|
|
|
namespace folly {
|
|
|
|
/**
|
|
* Wrapper class for set<string> 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 set
|
|
*/
|
|
template <
|
|
class Compare = std::less<StringPiece>,
|
|
class Alloc = std::allocator<StringPiece>>
|
|
class StringKeyedSetBase : private std::set<StringPiece, Compare, Alloc> {
|
|
private:
|
|
using Base = std::set<StringPiece, Compare, Alloc>;
|
|
|
|
public:
|
|
typedef typename Base::key_type key_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::size_type size_type;
|
|
typedef typename Base::difference_type difference_type;
|
|
|
|
explicit StringKeyedSetBase(
|
|
const key_compare& comp = key_compare(),
|
|
const allocator_type& alloc = allocator_type())
|
|
: Base(comp, alloc) {}
|
|
|
|
explicit StringKeyedSetBase(const allocator_type& alloc) : Base(alloc) {}
|
|
|
|
template <class InputIterator>
|
|
StringKeyedSetBase(
|
|
InputIterator b,
|
|
InputIterator e,
|
|
const key_compare& comp = key_compare(),
|
|
const allocator_type& alloc = allocator_type())
|
|
: Base(comp, alloc) {
|
|
for (; b != e; ++b) {
|
|
emplace(*b);
|
|
}
|
|
}
|
|
|
|
StringKeyedSetBase(const StringKeyedSetBase& rhs)
|
|
: StringKeyedSetBase(rhs, rhs.get_allocator()) {}
|
|
|
|
StringKeyedSetBase(const StringKeyedSetBase& rhs, const allocator_type& a)
|
|
: StringKeyedSetBase(rhs.begin(), rhs.end(), rhs.key_comp(), a) {}
|
|
|
|
StringKeyedSetBase(StringKeyedSetBase&& other) noexcept
|
|
: Base(std::move(other)) {
|
|
assert(other.empty());
|
|
}
|
|
|
|
StringKeyedSetBase(
|
|
StringKeyedSetBase&& other,
|
|
const allocator_type& alloc) noexcept
|
|
: Base(std::move(other), alloc) {
|
|
assert(other.empty());
|
|
}
|
|
|
|
StringKeyedSetBase(
|
|
std::initializer_list<value_type> il,
|
|
const key_compare& comp = key_compare(),
|
|
const allocator_type& alloc = allocator_type())
|
|
: StringKeyedSetBase(il.begin(), il.end(), comp, alloc) {}
|
|
|
|
StringKeyedSetBase& operator=(const StringKeyedSetBase& other) {
|
|
if (this == &other) {
|
|
return *this;
|
|
}
|
|
return *this = StringKeyedSetBase(other);
|
|
}
|
|
|
|
StringKeyedSetBase& operator=(StringKeyedSetBase&& other) noexcept {
|
|
assert(this != &other);
|
|
clear();
|
|
Base::operator=(std::move(other));
|
|
assert(other.empty());
|
|
return *this;
|
|
}
|
|
|
|
using Base::begin;
|
|
using Base::cbegin;
|
|
using Base::cend;
|
|
using Base::count;
|
|
using Base::empty;
|
|
using Base::end;
|
|
using Base::find;
|
|
using Base::lower_bound;
|
|
using Base::max_size;
|
|
using Base::size;
|
|
using Base::upper_bound;
|
|
|
|
bool operator==(StringKeyedSetBase const& other) const {
|
|
Base const& lhs = *this;
|
|
Base const& rhs = static_cast<Base const&>(other);
|
|
return lhs == rhs;
|
|
}
|
|
|
|
template <class... Args>
|
|
std::pair<iterator, bool> emplace(Args&&... args) {
|
|
auto key = StringPiece(std::forward<Args>(args)...);
|
|
auto it = find(key);
|
|
if (it != end()) {
|
|
return {it, false};
|
|
}
|
|
return Base::emplace(stringPieceDup(key, get_allocator()));
|
|
}
|
|
|
|
std::pair<iterator, bool> insert(value_type val) {
|
|
auto it = find(val);
|
|
if (it != end()) {
|
|
return {it, false};
|
|
}
|
|
return Base::insert(stringPieceDup(val, get_allocator()));
|
|
}
|
|
|
|
iterator erase(const_iterator position) {
|
|
auto key = *position;
|
|
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, get_allocator());
|
|
}
|
|
Base::clear();
|
|
}
|
|
|
|
using Base::get_allocator;
|
|
|
|
void swap(StringKeyedSetBase& other) & {
|
|
return Base::swap(other);
|
|
}
|
|
|
|
~StringKeyedSetBase() {
|
|
// Here we assume that set doesn't use keys in destructor
|
|
for (auto it : *this) {
|
|
stringPieceDel(it, get_allocator());
|
|
}
|
|
}
|
|
};
|
|
|
|
using StringKeyedSet = StringKeyedSetBase<>;
|
|
|
|
} // namespace folly
|