Skip to content

Commit 05bc40c

Browse files
committed
Update README.md.
1 parent 4a4600b commit 05bc40c

1 file changed

Lines changed: 31 additions & 16 deletions

File tree

README.md

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ The ordered-map library provides a hash map and a hash set which preserve the or
66

77
The values are stored contiguously in an underlying structure, no holes in-between values even after an erase operation. By default a `std::deque` is used for this structure, but it's also possible to use a `std::vector`. This structure is directly accessible through the `values_container()` method and if the structure is a `std::vector`, a `data()` method is also provided to easily interact with C APIs.
88

9-
To resolve collisions on hashes, the library uses robin hood probing with backward shift deletion.
9+
To resolve collisions on hashes, the library uses linear robin hood probing with backward shift deletion.
1010

1111
The library provides a behaviour similar to a `std::deque/std::vector` with unique values but with an average time complexity of O(1) for lookups and an amortised time complexity of O(1) for insertions. This comes at the price of a little higher memory footprint (8 bytes per bucket by default).
1212

1313
Two classes are provided: `tsl::ordered_map` and `tsl::ordered_set`.
1414

15-
**Note**: The library uses a power of two for the size of its buckets array to take advantage of the [fast modulo](https://en.wikipedia.org/wiki/Modulo_operation#Performance_issues). For good performance, it requires the hash table to have a well-distributed hash function. If you encounter performance issues check your hash function.
15+
**Note**: The library uses a power of two for the size of its buckets array to take advantage of the [fast modulo](https://en.wikipedia.org/wiki/Modulo_operation#Performance_issues). For good performances, it requires the hash table to have a well-distributed hash function. If you encounter performance issues check your hash function.
1616

1717
### Key features
1818

1919
- Header-only library, just add the [include](include/) directory to your include path and you are ready to go. If you use CMake, you can also use the `tsl::ordered_map` exported target from the [CMakeLists.txt](CMakeLists.txt).
2020
- Values are stored in the same order as the insertion order. The library provides a direct access to the underlying structure which stores the values.
2121
- O(1) average time complexity for lookups with performances similar to `std::unordered_map` but with faster insertions and reduced memory usage (see [benchmark](https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html) for details).
2222
- Provide random access iterators and also reverse iterators.
23-
- Support for heterogeneous lookups (e.g. if you have a map that uses `std::unique_ptr<int>` as key, you could use an `int*` or a `std::uintptr_t` for example as key parameter for `find`, see [example](#heterogeneous-lookup)).
24-
- If the hash is known before a lookup, it is possible to pass it as parameter to speed-up the lookup (see [API](https://tessil.github.io/ordered-map/classtsl_1_1ordered__map.html#a7fcde27edc6697a0b127f4b1aefa8a7d)).
23+
- Support for heterogeneous lookups allowing the usage of `find` with a type different than `Key` (e.g. if you have a map that uses `std::unique_ptr<foo>` as key, you could use a `foo*` or a `std::uintptr_t` as key parameter to `find` without constructing a `std::unique_ptr<foo>`, see [example](#heterogeneous-lookups)).
24+
- If the hash is known before a lookup, it is possible to pass it as parameter to speed-up the lookup (see `precalculated_hash` parameter in [API](https://tessil.github.io/ordered-map/classtsl_1_1ordered__map.html#a7fcde27edc6697a0b127f4b1aefa8a7d)).
2525
- The library can be used with exceptions disabled (through `-fno-exceptions` option on Clang and GCC, without an `/EH` option on MSVC or simply by defining `TSL_NO_EXCEPTIONS`). `std::terminate` is used in replacement of the `throw` instruction when exceptions are disabled.
2626
- API closely similar to `std::unordered_map` and `std::unordered_set`.
2727

@@ -39,12 +39,12 @@ for(auto it = map.begin(); it != map.end(); ++it) {
3939
}
4040
```
4141
- By default the map can only hold up to 2<sup>32</sup> - 1 values, that is 4 294 967 295 values. This can be raised through the `IndexType` class template parameter, check the [API](https://tessil.github.io/ordered-map/classtsl_1_1ordered__map.html#details) for details.
42-
- No support for some bucket related methods (like bucket_size, bucket, ...).
42+
- No support for some bucket related methods (like `bucket_size`, `bucket`, ...).
4343
4444
4545
Thread-safety guarantee is the same as `std::unordered_map` (i.e. possible to have multiple concurrent readers with no writer).
4646
47-
Concerning the strong exception guarantee, it holds only if `ValueContainer::emplace_back` has the strong exception guarantee (which is true for `std::vector` and `std::deque` as long as the type T is not a move-only type with a move constructor that may throw an exception, see [details](http://en.cppreference.com/w/cpp/container/vector/emplace_back#Exceptions)).
47+
Concerning the strong exception guarantee, it holds only if `ValueContainer::emplace_back` has the strong exception guarantee (which is true for `std::vector` and `std::deque` as long as the type `T` is not a move-only type with a move constructor that may throw an exception, see [details](http://en.cppreference.com/w/cpp/container/vector/emplace_back#Exceptions)).
4848
4949
These differences also apply between `std::unordered_set` and `tsl::ordered_set`.
5050
@@ -109,12 +109,24 @@ int main() {
109109
std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl;
110110
}
111111

112+
112113
for(auto it = map.begin(); it != map.end(); ++it) {
113114
//it->second += 2; // Not valid.
114115
it.value() += 2;
115116
}
116117

117118

119+
if(map.find("a") != map.end()) {
120+
std::cout << "Found \"a\"." << std::endl;
121+
}
122+
123+
const std::size_t precalculated_hash = std::hash<std::string>()("a");
124+
// If we already know the hash beforehand, we can pass it as argument to speed-up the lookup.
125+
if(map.find("a", precalculated_hash) != map.end()) {
126+
std::cout << "Found \"a\" with hash " << precalculated_hash << "." << std::endl;
127+
}
128+
129+
118130
tsl::ordered_set<char, std::hash<char>, std::equal_to<char>,
119131
std::allocator<char>, std::vector<char>> set;
120132
set.reserve(6);
@@ -147,10 +159,12 @@ Both `KeyEqual` and `Hash` will need to be able to deal with the different types
147159
#include <tsl/ordered_map.h>
148160

149161

162+
150163
struct employee {
151164
employee(int id, std::string name) : m_id(id), m_name(std::move(name)) {
152165
}
153166

167+
// Either we include the comparators in the class and we use `std::equal_to<>`...
154168
friend bool operator==(const employee& empl, int empl_id) {
155169
return empl.m_id == empl_id;
156170
}
@@ -168,16 +182,7 @@ struct employee {
168182
std::string m_name;
169183
};
170184

171-
struct hash_employee {
172-
std::size_t operator()(const employee& empl) const {
173-
return std::hash<int>()(empl.m_id);
174-
}
175-
176-
std::size_t operator()(int id) const {
177-
return std::hash<int>()(id);
178-
}
179-
};
180-
185+
// ... or we implement a separate class to compare employees.
181186
struct equal_employee {
182187
using is_transparent = void;
183188

@@ -194,6 +199,16 @@ struct equal_employee {
194199
}
195200
};
196201

202+
struct hash_employee {
203+
std::size_t operator()(const employee& empl) const {
204+
return std::hash<int>()(empl.m_id);
205+
}
206+
207+
std::size_t operator()(int id) const {
208+
return std::hash<int>()(id);
209+
}
210+
};
211+
197212

198213
int main() {
199214
// Use std::equal_to<> which will automatically deduce and forward the parameters

0 commit comments

Comments
 (0)