Quick Links: |
Provide an open-addressed unordered set container. More...
Namespaces | |
namespace | bdlc |
bdlc::FlatHashSet | open-addressed unordered set container |
bdlc::FlatHashSet
, that implements an open-addressed unordered set of items with unique values. bdlc::FlatHashSet
generally exhibits better performance than bsl::unordered_set
. bdlc::FlatHashSet
is an allocator-aware, value-semantic type whose salient attributes are the set of values contained, without regard to order. An instantiation may be provided with custom hash and equality functors, but those are not salient attributes. In particular, when comparing element values for equality between two different bdlc::FlatHashSet
objects, the elements are compared using operator==
. flat_hash_map
CppCon presentations (available on YouTube). The implementation draws from Google's open source raw_hash_set.h
file at: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal. bdlc::FlatHashSet
is recommended for Intel platforms only (i.e., Linux and Windows, and pre-ARM Macs); on platforms using other processors (i.e., Sun and AIX), bdlc::FlatHashSet
may have slower performance than bsl::unordered_set
. However, note that bdlc::FlatHashSet
will use significantly less memory than bsl::unordered_set
on all platforms. Given the Intel-only performance caveat, it is recommended to benchmark before using bdlc::FlatHashSet
-- particularly on non-Intel production environments. bdlc::FlatHashSet
meets most of the requirements of an unordered associative container with forward iterators in the C++11 Standard [23.2.5]. It does not have the bucket interface, and locations of elements may change when the container is modified (and therefore iterators become invalid too). Allocator use follows BDE style, and the various allocator propagation attributes are not present (e.g., the allocator trait propagate_on_container_copy_assignment
). The maximum load factor of the container (the ratio of size to capacity) is maintained by the container itself and is not settable (the maximum load factor is implementation defined and fixed). bdlc::FlatHashSet
is that 0 <= load_factor() <= max_load_factor() <= 1.0
. Any operation that would result in load_factor() > max_load_factor()
for a bdlc::FlatHashSet
causes the capacity to increase. This resizing allocates new memory, copies or moves all elements to the new memory, and reclaims the original memory. The transfer of elements involves rehashing each element to determine its new location. As such, all iterators, pointers, and references to elements of the bdlc::FlatHashSet
are invalidated on a resize. KEY
must be copy or move constructible. The template parameter types HASH
and EQUAL
must be default and copy constructible function objects. HASH
must support a function-call operator compatible with the following statements for an object key
of type KEY
: HASH hash; bsl::size_t result = hash(key);
EQUAL
must support a function-call operator compatible with the following statements for objects key1
and key2
of type KEY
: EQUAL equal;
bool result = equal(key1, key2);
HASH
and EQUAL
function objects are further constrained: if the comparator determines that two values are equal, the hasher must produce the same hash value for each. bdlc::FlatHashSet
invalidates all pointers, references, and iterators. A bdlc::FlatHashSet
manipulator that erases an element invalidates all pointers, references, and iterators to the erased element. bdlc::FlatHashSet
is exception neutral, and all of the methods of bdlc::FlatHashSet
provide the basic exception safety guarantee (see bsldoc_glossary
|Basic Guarantee). bdlc::FlatHashSet
on C++11, and later, platforms only (where BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES
is defined), and are not supported on C++03 platforms. Unfortunately, in C++03, there are user-defined types where a bslmf::MovableRef
will not safely degrade to an lvalue reference when a move constructor is not available (types providing a constructor template taking any type), so bslmf::MovableRefUtil::move
cannot be used directly on a user-supplied template parameter type. typedef enum { e_REPEAT , e_DISCOUNT , e_IMPULSE , e_NEED_BASED , e_BUSINESS , e_NON_PROFIT , e_INSTITUTE // ... } CustomerCode; typedef enum { e_USA_EAST , e_USA_WEST , e_CANADA , e_MEXICO , e_ENGLAND , e_SCOTLAND , e_FRANCE , e_GERMANY , e_RUSSIA // ... } LocationCode; typedef enum { e_TOAST , e_GREEN , e_FAST , e_TIDY , e_PEARL , e_SMITH // ... } ProjectCode;
static const struct CustomerProfile { CustomerCode d_customer; LocationCode d_location; ProjectCode d_project; } customerProfiles[] = { { e_IMPULSE , e_CANADA , e_SMITH }, { e_NON_PROFIT, e_USA_EAST, e_GREEN }, { e_INSTITUTE , e_USA_EAST, e_TOAST }, { e_NON_PROFIT, e_CANADA , e_PEARL }, { e_NEED_BASED, e_CANADA , e_FAST }, { e_BUSINESS , e_ENGLAND , e_PEARL }, { e_REPEAT , e_SCOTLAND, e_TIDY }, { e_INSTITUTE , e_MEXICO , e_PEARL }, { e_DISCOUNT , e_USA_EAST, e_GREEN }, { e_BUSINESS , e_USA_EAST, e_GREEN }, { e_IMPULSE , e_MEXICO , e_TOAST }, { e_DISCOUNT , e_GERMANY , e_FAST }, { e_INSTITUTE , e_FRANCE , e_FAST }, { e_NON_PROFIT, e_ENGLAND , e_PEARL }, { e_BUSINESS , e_ENGLAND , e_TIDY }, { e_BUSINESS , e_CANADA , e_GREEN }, { e_INSTITUTE , e_FRANCE , e_FAST }, { e_IMPULSE , e_RUSSIA , e_TOAST }, { e_REPEAT , e_USA_WEST, e_TOAST }, { e_IMPULSE , e_CANADA , e_TIDY }, { e_NON_PROFIT, e_GERMANY , e_GREEN }, { e_INSTITUTE , e_USA_EAST, e_TOAST }, { e_INSTITUTE , e_FRANCE , e_FAST }, { e_IMPULSE , e_SCOTLAND, e_SMITH }, { e_INSTITUTE , e_USA_EAST, e_PEARL }, { e_INSTITUTE , e_USA_EAST, e_TOAST }, { e_NON_PROFIT, e_ENGLAND , e_PEARL }, { e_IMPULSE , e_GERMANY , e_FAST }, { e_REPEAT , e_GERMANY , e_FAST }, { e_REPEAT , e_MEXICO , e_PEARL }, { e_IMPULSE , e_GERMANY , e_TIDY }, { e_IMPULSE , e_MEXICO , e_TOAST }, { e_NON_PROFIT, e_SCOTLAND, e_SMITH }, { e_NEED_BASED, e_MEXICO , e_TOAST }, { e_NON_PROFIT, e_FRANCE , e_SMITH }, { e_INSTITUTE , e_MEXICO , e_TIDY }, { e_NON_PROFIT, e_FRANCE , e_TIDY }, { e_IMPULSE , e_FRANCE , e_FAST }, { e_DISCOUNT , e_RUSSIA , e_TIDY }, { e_IMPULSE , e_USA_EAST, e_TIDY }, { e_IMPULSE , e_USA_WEST, e_FAST }, { e_NON_PROFIT, e_FRANCE , e_TIDY }, { e_BUSINESS , e_ENGLAND , e_GREEN }, { e_REPEAT , e_FRANCE , e_TOAST }, { e_REPEAT , e_RUSSIA , e_SMITH }, { e_REPEAT , e_RUSSIA , e_GREEN }, { e_IMPULSE , e_CANADA , e_FAST }, { e_NON_PROFIT, e_USA_EAST, e_FAST }, { e_NEED_BASED, e_USA_WEST, e_TOAST }, { e_NON_PROFIT, e_GERMANY , e_TIDY }, { e_NON_PROFIT, e_ENGLAND , e_GREEN }, { e_REPEAT , e_GERMANY , e_PEARL }, { e_NEED_BASED, e_USA_EAST, e_PEARL }, { e_NON_PROFIT, e_RUSSIA , e_PEARL }, { e_NEED_BASED, e_ENGLAND , e_SMITH }, { e_INSTITUTE , e_CANADA , e_SMITH }, { e_NEED_BASED, e_ENGLAND , e_TOAST }, { e_NON_PROFIT, e_MEXICO , e_TIDY }, { e_BUSINESS , e_GERMANY , e_FAST }, { e_NEED_BASED, e_SCOTLAND, e_PEARL }, { e_NON_PROFIT, e_USA_WEST, e_TIDY }, { e_NON_PROFIT, e_USA_WEST, e_TOAST }, { e_IMPULSE , e_FRANCE , e_PEARL }, { e_IMPULSE , e_ENGLAND , e_FAST }, { e_IMPULSE , e_USA_WEST, e_GREEN }, { e_DISCOUNT , e_MEXICO , e_SMITH }, { e_INSTITUTE , e_GERMANY , e_TOAST }, { e_NEED_BASED, e_CANADA , e_PEARL }, { e_NON_PROFIT, e_USA_WEST, e_FAST }, { e_DISCOUNT , e_RUSSIA , e_SMITH }, { e_INSTITUTE , e_USA_WEST, e_GREEN }, { e_INSTITUTE , e_RUSSIA , e_TOAST }, { e_INSTITUTE , e_FRANCE , e_SMITH }, { e_INSTITUTE , e_SCOTLAND, e_SMITH }, { e_NON_PROFIT, e_ENGLAND , e_PEARL }, { e_NON_PROFIT, e_CANADA , e_SMITH }, { e_NON_PROFIT, e_USA_EAST, e_TOAST }, { e_REPEAT , e_FRANCE , e_TOAST }, { e_NEED_BASED, e_FRANCE , e_FAST }, { e_DISCOUNT , e_MEXICO , e_TOAST }, { e_DISCOUNT , e_FRANCE , e_GREEN }, { e_IMPULSE , e_USA_EAST, e_FAST }, { e_REPEAT , e_USA_EAST, e_GREEN }, { e_NON_PROFIT, e_GERMANY , e_GREEN }, { e_INSTITUTE , e_CANADA , e_SMITH }, { e_NEED_BASED, e_SCOTLAND, e_TOAST }, { e_NEED_BASED, e_GERMANY , e_FAST }, { e_NON_PROFIT, e_RUSSIA , e_TOAST }, { e_BUSINESS , e_ENGLAND , e_PEARL }, { e_NEED_BASED, e_USA_EAST, e_TOAST }, { e_INSTITUTE , e_USA_EAST, e_SMITH }, { e_DISCOUNT , e_USA_EAST, e_PEARL }, { e_REPEAT , e_SCOTLAND, e_FAST }, { e_IMPULSE , e_GERMANY , e_TIDY }, { e_DISCOUNT , e_CANADA , e_TIDY }, { e_IMPULSE , e_USA_EAST, e_TIDY }, { e_IMPULSE , e_GERMANY , e_TIDY }, { e_NON_PROFIT, e_ENGLAND , e_FAST }, { e_NON_PROFIT, e_USA_WEST, e_TIDY }, { e_REPEAT , e_MEXICO , e_TOAST }, }; const bsl::size_t numCustomerProfiles = sizeof customerProfiles / sizeof *customerProfiles;
CustomerProfileHash
and CustomerProfileEqual
classes, each a stateless functor. Note that there is no meaningful ordering of the attribute values, they are merely arbitrary code numbers; nothing is lost by using an unordered set instead of an ordered set: class CustomerProfileHash { public: // CREATORS // Create a 'CustomerProfileHash' object. // Create a 'CustomerProfileHash' object. Note that as // 'CustomerProfileHash' is an empty (stateless) type, this // operation has no observable effect. // Destroy this object. // ACCESSORS bsl::size_t operator()(const CustomerProfile& x) const; // Return a hash value for the specified 'x'. };
int
value) into a single, unique int
value, and then applies the default hash function for int
. // ACCESSORS bsl::size_t CustomerProfileHash::operator()(const CustomerProfile& x) const { return bsl::hash<int>()( x.d_location * 100 * 100 + x.d_customer * 100 + x.d_project); } class CustomerProfileEqual { public: // CREATORS // Create a 'CustomerProfileEqual' object. // Create a 'CustomerProfileEqual' object. Note that as // 'CustomerProfileEqual' is an empty (stateless) type, this // operation has no observable effect. // Destroy this object. // ACCESSORS bool operator()(const CustomerProfile& lhs, const CustomerProfile& rhs) const; // Return 'true' if the specified 'lhs' has the same value as the // specified 'rhs', and 'false' otherwise. }; // ACCESSORS bool CustomerProfileEqual::operator()(const CustomerProfile& lhs, const CustomerProfile& rhs) const { return lhs.d_location == rhs.d_location && lhs.d_customer == rhs.d_customer && lhs.d_project == rhs.d_project; }
= default
comment.) typedef bdlc::FlatHashSet<CustomerProfile, CustomerProfileHash, CustomerProfileEqual> ProfileCategories;
customerProfiles
: bslma::TestAllocator oa("object", veryVeryVeryVerbose); ProfileCategories profileCategories(&oa); for (bsl::size_t idx = 0; idx < numCustomerProfiles; ++idx) { profileCategories.insert(customerProfiles[idx]); } assert(numCustomerProfiles >= profileCategories.size());
insert
method. We fully expect some operations to fail. profileCategories
matches the number of unique customer profiles in this data set: if (verbose) { bsl::cout << numCustomerProfiles << ' ' << profileCategories.size() << bsl::endl; }
100 84