/* * 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 #include #include #include #include namespace folly { /** * Wrapper class for set 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, class Alloc = std::allocator> class StringKeyedSetBase : private std::set { private: using Base = std::set; 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 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 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(other); return lhs == rhs; } template std::pair emplace(Args&&... args) { auto key = StringPiece(std::forward(args)...); auto it = find(key); if (it != end()) { return {it, false}; } return Base::emplace(stringPieceDup(key, get_allocator())); } std::pair 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