Commit 1474b109 authored by Andrei Alexandrescu's avatar Andrei Alexandrescu Committed by Sara Golemon

Add StringKeyed(Unordered){Set,Map} to folly

Summary: We're using StringKeyed* from common/datastruct to avoid unnecessary string creation whenever we're looking up string keys. C++14 does offer a solution, see e.g. http://stackoverflow.com/questions/10536788/avoiding-key-construction-for-stdmapfind. That is not supported by current compilers.

Test Plan: unittests

Reviewed By: pavlo@fb.com

Subscribers: trunkagent, net-systems@, folly-diffs@, yfeldblum

FB internal diff: D1825700

Signature: t1:1825700:1423086724:530550c3c80e33c80900f31c0ade05c66b22cbe8
parent 7eaace04
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
// Copyright 2013-present Facebook. All Rights Reserved.
// @author: Pavlo Kushnir (pavlo)
#ifndef FOLLY_EXPERIMENTAL_STRINGKEYEDCOMMON_H_
#define FOLLY_EXPERIMENTAL_STRINGKEYEDCOMMON_H_
#include <memory>
#include <folly/Range.h>
namespace folly {
template <class Alloc>
StringPiece stringPieceDup(StringPiece piece, const Alloc& alloc) {
auto size = piece.size();
auto keyDup = typename Alloc::template rebind<char>::other(alloc)
.allocate(size);
memcpy(keyDup, piece.data(), size * sizeof(typename StringPiece::value_type));
return StringPiece(keyDup, size);
}
template <class Alloc>
void stringPieceDel(StringPiece piece, const Alloc& alloc) {
typename Alloc::template rebind<char>::other(alloc)
.deallocate(const_cast<char*>(piece.data()), piece.size());
}
} // folly
#endif /* FOLLY_EXPERIMENTAL_STRINGKEYEDCOMMON_H_ */
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
// Copyright 2013-present Facebook. All Rights Reserved.
// @author: Pavlo Kushnir (pavlo)
#ifndef FOLLY_EXPERIMENTAL_STRINGKEYEDMAP_H_
#define FOLLY_EXPERIMENTAL_STRINGKEYEDMAP_H_
#include <initializer_list>
#include <memory>
#include <map>
#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::empty;
using Base::size;
using Base::max_size;
using Base::begin;
using Base::end;
using Base::rbegin;
using Base::rend;
using Base::cbegin;
using Base::cend;
using Base::crbegin;
using Base::crend;
// 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::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();
}
~StringKeyedMap() {
// Here we assume that map doesn't use keys in destructor
for (auto& it : *this) {
stringPieceDel(it.first, get_allocator());
}
}
};
} // folly
#endif /* FOLLY_EXPERIMENTAL_STRINGKEYEDMAP_H_ */
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
// Copyright 2013-present Facebook. All Rights Reserved.
// @author: Pavlo Kushnir (pavlo)
#ifndef FOLLY_EXPERIMENTAL_STRINGKEYEDSET_H_
#define FOLLY_EXPERIMENTAL_STRINGKEYEDSET_H_
#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::empty;
using Base::size;
using Base::max_size;
using Base::begin;
using Base::end;
using Base::cbegin;
using Base::cend;
using Base::find;
using Base::lower_bound;
using Base::upper_bound;
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;
~StringKeyedSetBase() {
// Here we assume that set doesn't use keys in destructor
for (auto it : *this) {
stringPieceDel(it, get_allocator());
}
}
};
using StringKeyedSet = StringKeyedSetBase<>;
} // folly
#endif /* FOLLY_EXPERIMENTAL_STRINGKEYEDSET_H_ */
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
// Copyright 2013-present Facebook. All Rights Reserved.
// @author: Pavlo Kushnir (pavlo)
#ifndef FOLLY_EXPERIMENTAL_STRINGKEYEDUNORDEREDMAP_H_
#define FOLLY_EXPERIMENTAL_STRINGKEYEDUNORDEREDMAP_H_
#include <initializer_list>
#include <memory>
#include <unordered_map>
#include <folly/Range.h>
#include <folly/experimental/StringKeyedCommon.h>
namespace folly {
/**
* Wrapper class for unordered_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 Hash = StringPieceHash,
class Eq = std::equal_to<StringPiece>,
class Alloc = std::allocator<std::pair<const StringPiece, Value>>>
class StringKeyedUnorderedMap
: private std::unordered_map<StringPiece, Value, Hash, Eq, Alloc> {
private:
using Base = std::unordered_map<StringPiece, Value, Hash, Eq, 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::hasher hasher;
typedef typename Base::key_equal key_equal;
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::size_type size_type;
typedef typename Base::difference_type difference_type;
explicit StringKeyedUnorderedMap() {}
explicit StringKeyedUnorderedMap(
size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: Base(n, hf, eql, alloc) {
}
explicit StringKeyedUnorderedMap(const allocator_type& a)
: Base(a) {
}
template <class InputIterator>
StringKeyedUnorderedMap(InputIterator b, InputIterator e) {
for (; b != e; ++b) {
// insert() will carry the duplication
emplace(b->first, b->second);
}
}
template <class InputIterator>
StringKeyedUnorderedMap(
InputIterator b, InputIterator e,
size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: Base(n, hf, eql, alloc) {
for (; b != e; ++b) {
// insert() will carry the duplication
emplace(b->first, b->second);
}
}
StringKeyedUnorderedMap(const StringKeyedUnorderedMap& rhs)
: StringKeyedUnorderedMap(rhs.begin(), rhs.end(),
rhs.bucket_count(),
rhs.hash_function(),
rhs.key_eq(),
rhs.get_allocator()) {
}
StringKeyedUnorderedMap(StringKeyedUnorderedMap&& rhs) noexcept
: StringKeyedUnorderedMap(std::move(rhs), rhs.get_allocator()) {
}
StringKeyedUnorderedMap(StringKeyedUnorderedMap&& other,
const allocator_type& a) noexcept
: Base(std::move(other)/*, a*/ /* not supported by gcc */) {
}
StringKeyedUnorderedMap(std::initializer_list<value_type> il)
: StringKeyedUnorderedMap(il.begin(), il.end()) {
}
StringKeyedUnorderedMap(
std::initializer_list<value_type> il,
size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: StringKeyedUnorderedMap(il.begin(), il.end(), n, hf, eql, alloc) {
}
StringKeyedUnorderedMap& operator=(const StringKeyedUnorderedMap& other) & {
if (this == &other) {
return *this;
}
return *this = StringKeyedUnorderedMap(other);
}
StringKeyedUnorderedMap&
operator=(StringKeyedUnorderedMap&& other) & noexcept {
assert(this != &other);
clear();
Base::operator=(std::move(other));
return *this;
}
using Base::empty;
using Base::size;
using Base::max_size;
using Base::begin;
using Base::end;
using Base::cbegin;
using Base::cend;
bool operator==(const StringKeyedUnorderedMap& rhs) {
const Base& lhs = *this;
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::find;
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};
}
auto valCopy = std::make_pair(stringPieceDup(val.first, get_allocator()),
std::move(val.second));
return Base::insert(valCopy);
}
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::reserve;
using Base::hash_function;
using Base::key_eq;
using Base::get_allocator;
using Base::bucket_count;
using Base::max_bucket_count;
using Base::bucket_size;
using Base::bucket;
~StringKeyedUnorderedMap() {
// Here we assume that unordered_map doesn't use keys in destructor
for (auto& it : *this) {
stringPieceDel(it.first, get_allocator());
}
}
};
} // folly
#endif /* FOLLY_EXPERIMENTAL_STRINGKEYEDUNORDEREDMAP_H_ */
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
// Copyright 2013-present Facebook. All Rights Reserved.
// @author: Pavlo Kushnir (pavlo)
#ifndef FOLLY_EXPERIMENTAL_STRINGKEYEDUNORDEREDSET_H_
#define FOLLY_EXPERIMENTAL_STRINGKEYEDUNORDEREDSET_H_
#include <initializer_list>
#include <memory>
#include <unordered_set>
#include <folly/Range.h>
#include <folly/experimental/StringKeyedCommon.h>
namespace folly {
/**
* Wrapper class for unordered_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 Hasher = StringPieceHash,
class Eq = std::equal_to<StringPiece>,
class Alloc = std::allocator<folly::StringPiece>>
class BasicStringKeyedUnorderedSet
: private std::unordered_set<StringPiece, Hasher, Eq, Alloc> {
using Base = std::unordered_set<StringPiece, Hasher, Eq, Alloc>;
public:
typedef typename Base::key_type key_type;
typedef typename Base::value_type value_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
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::size_type size_type;
typedef typename Base::difference_type difference_type;
// Constructors in the same order as in
// http://cplusplus.com/reference/unordered_set/unordered_set/unordered_set/
explicit BasicStringKeyedUnorderedSet() {
}
explicit BasicStringKeyedUnorderedSet(
size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: Base(n, hf, eql, alloc) {
}
explicit BasicStringKeyedUnorderedSet(const allocator_type& alloc)
: Base(alloc) {
}
template <class InputIterator>
BasicStringKeyedUnorderedSet(InputIterator b, InputIterator e) {
for (; b != e; ++b) {
emplace(*b);
}
}
template <class InputIterator>
BasicStringKeyedUnorderedSet(
InputIterator b, InputIterator e,
size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: Base(n, hf, eql, alloc) {
for (; b != e; ++b) {
emplace(*b);
}
}
BasicStringKeyedUnorderedSet(const BasicStringKeyedUnorderedSet& rhs)
: BasicStringKeyedUnorderedSet(rhs, rhs.get_allocator()) {
}
BasicStringKeyedUnorderedSet(const BasicStringKeyedUnorderedSet& rhs,
const allocator_type& a)
: BasicStringKeyedUnorderedSet(rhs.begin(),
rhs.end(),
rhs.bucket_count(),
rhs.hash_function(),
rhs.key_eq(),
a) {
}
BasicStringKeyedUnorderedSet(BasicStringKeyedUnorderedSet&& rhs) noexcept
: Base(std::move(rhs)) {
assert(rhs.empty());
}
BasicStringKeyedUnorderedSet(BasicStringKeyedUnorderedSet&& rhs,
const allocator_type& a) noexcept
: Base(std::move(rhs)/* , a */ /* not supported by gcc */) {
assert(rhs.empty());
}
BasicStringKeyedUnorderedSet(std::initializer_list<value_type> il)
: BasicStringKeyedUnorderedSet(il.begin(), il.end()) {
}
BasicStringKeyedUnorderedSet(
std::initializer_list<value_type> il,
size_type n,
const hasher& hf = hasher(),
const key_equal& eql = key_equal(),
const allocator_type& alloc = allocator_type())
: BasicStringKeyedUnorderedSet(il.begin(), il.end(), n, hf, eql, alloc) {
}
BasicStringKeyedUnorderedSet&
operator=(const BasicStringKeyedUnorderedSet& rhs) & {
if (this == &rhs) {
return *this;
}
// Cost is as bad as a full copy, so to it via copy + move
return *this = BasicStringKeyedUnorderedSet(rhs);
}
BasicStringKeyedUnorderedSet&
operator=(BasicStringKeyedUnorderedSet&& rhs) & noexcept {
assert(this != &rhs);
clear();
Base::operator=(std::move(rhs));
return *this;
}
using Base::empty;
using Base::size;
using Base::max_size;
using Base::begin;
using Base::end;
using Base::cbegin;
using Base::cend;
using Base::find;
bool operator==(const BasicStringKeyedUnorderedSet& rhs) const {
const Base& lhs = *this;
return lhs == rhs;
}
template <class... Args>
std::pair<iterator, bool> emplace(Args&&... args) {
auto key = StringPiece(std::forward<Args>(args)...);
auto it = find(key);
return it != end()
? std::make_pair(it, false)
: Base::emplace(stringPieceDup(key, get_allocator()));
}
std::pair<iterator, bool> insert(value_type val) {
auto it = find(val);
return it != end()
? std::make_pair(it, false)
: 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(folly::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::reserve;
using Base::hash_function;
using Base::key_eq;
using Base::get_allocator;
using Base::bucket_count;
using Base::max_bucket_count;
using Base::bucket_size;
using Base::bucket;
~BasicStringKeyedUnorderedSet() {
// Here we assume that unordered_set doesn't use keys in destructor
for (auto& it : *this) {
stringPieceDel(it, get_allocator());
}
}
};
typedef BasicStringKeyedUnorderedSet<> StringKeyedUnorderedSet;
} // folly
#endif /* FOLLY_EXPERIMENTAL_STRINGKEYEDUNORDEREDSET_H_ */
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
// Copyright 2013-present Facebook. All Rights Reserved.
#include <folly/Benchmark.h>
#include <folly/Range.h>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <folly/experimental/StringKeyedMap.h>
#include <folly/experimental/StringKeyedSet.h>
#include <folly/experimental/StringKeyedUnorderedMap.h>
#include <folly/experimental/StringKeyedUnorderedSet.h>
using folly::StringKeyedMap;
using folly::StringKeyedSet;
using folly::StringKeyedUnorderedMap;
using folly::StringKeyedUnorderedSet;
using folly::StringPiece;
using std::map;
using std::to_string;
using std::set;
using std::string;
using std::unordered_map;
using std::unordered_set;
static map<string, int> m;
static StringKeyedMap<int> skm;
static set<string> s;
static StringKeyedSet sks;
static unordered_map<string, int> um;
static StringKeyedUnorderedMap<int> skum;
static unordered_set<string> us;
static StringKeyedUnorderedSet skus;
static const string lookup("123");
static const folly::StringPiece lookupPiece(lookup);
static void initBenchmarks() {
for (int i = 0; i < 1000; ++i) {
auto iStr = to_string(i);
m[iStr] = i;
skm.insert(make_pair(iStr, i));
um[iStr] = i;
skum.insert(make_pair(iStr, i));
s.insert(iStr);
sks.insert(iStr);
us.insert(iStr);
skus.insert(iStr);
}
}
BENCHMARK(std_map_benchmark_find) {
folly::doNotOptimizeAway(m.find(lookupPiece.str())->second);
}
BENCHMARK_RELATIVE(sk_map_benchmark_find) {
folly::doNotOptimizeAway(skm.find(lookupPiece)->second);
}
BENCHMARK(std_map_benchmark_erase_emplace) {
m.erase(lookup);
m.emplace(lookup, 123);
}
BENCHMARK_RELATIVE(sk_map_benchmark_erase_emplace) {
skm.erase(lookup);
skm.emplace(lookup, 123);
}
BENCHMARK(std_unordered_map_benchmark_find) {
folly::doNotOptimizeAway(um.find(lookupPiece.str())->second);
}
BENCHMARK_RELATIVE(sk_unordered_map_benchmark_find) {
folly::doNotOptimizeAway(skum.find(lookupPiece)->second);
}
BENCHMARK(std_unordered_map_benchmark_erase_emplace) {
um.erase(lookup);
um.emplace(lookup, 123);
}
BENCHMARK_RELATIVE(sk_unordered_map_benchmark_erase_emplace) {
skum.erase(lookup);
skum.emplace(lookup, 123);
}
BENCHMARK(std_set_benchmark_find) {
folly::doNotOptimizeAway(s.find(lookupPiece.str()));
}
BENCHMARK_RELATIVE(sk_set_benchmark_find) {
folly::doNotOptimizeAway(sks.find(lookupPiece));
}
BENCHMARK(std_set_benchmark_erase_emplace) {
s.erase(lookup);
s.emplace(lookup);
}
BENCHMARK_RELATIVE(sk_set_benchmark_erase_emplace) {
sks.erase(lookup);
sks.emplace(lookup);
}
BENCHMARK(std_unordered_set_benchmark_find) {
folly::doNotOptimizeAway(us.find(lookupPiece.str()));
}
BENCHMARK_RELATIVE(sk_unordered_set_benchmark_find) {
folly::doNotOptimizeAway(skus.find(lookupPiece));
}
BENCHMARK(std_unordered_set_benchmark_erase_emplace) {
us.erase(lookup);
us.emplace(lookup);
}
BENCHMARK_RELATIVE(sk_unordered_set_benchmark_erase_emplace) {
skus.erase(lookup);
skus.emplace(lookup);
}
int main(int argc, char **argv) {
initBenchmarks();
folly::runBenchmarks();
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment