Skip to content

Commit 1aa4807

Browse files
committed
Version 2.3.0
1 parent 6825b7a commit 1aa4807

File tree

1 file changed

+55
-30
lines changed

1 file changed

+55
-30
lines changed

Hashmap.hpp

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@
3434
#include <iostream>
3535
#include <mutex>
3636
#include <optional>
37+
#include <shared_mutex>
3738
#include <stdexcept>
3839
#include <vector>
3940

4041
namespace LouiEriksson {
4142

4243
/**
43-
* @mainpage Version 2.2.1
44+
* @mainpage Version 2.3.0
4445
* @details Custom Hashmap implementation accepting a customisable key and value type.
4546
* This implementation requires that your "key" type is compatible with std::hash and that the stored data types are copyable.
4647
* @see Wang, Q. (Harry) (2020). Implementing Your Own HashMap (Explanation + Code). YouTube.
@@ -51,7 +52,7 @@ namespace LouiEriksson {
5152
template<typename Tk, typename Tv>
5253
class Hashmap final {
5354

54-
inline static std::recursive_mutex s_Lock;
55+
inline static std::shared_mutex s_Lock;
5556

5657
public:
5758

@@ -130,12 +131,35 @@ namespace LouiEriksson {
130131
for (auto& bucket : shallow_cpy) {
131132
for (auto& kvp : bucket) {
132133

133-
std::exception_ptr e_ptr = nullptr;
134+
auto& k = kvp.first;
135+
auto& v = kvp.second;
134136

135-
Assign(std::move(kvp.first), std::move(kvp.second), e_ptr);
137+
if (m_Size >= m_Buckets.size()) {
138+
Resize(m_Buckets.size() * 2U);
139+
}
140+
141+
// Create an index by taking the key's hash value and "wrapping" it with the number of buckets.
142+
const auto hash = GetHashcode(k);
143+
const auto i = hash % m_Buckets.size();
144+
145+
auto& bucket = m_Buckets[i];
146+
147+
auto exists = false;
148+
for (auto& kvp : bucket) {
149+
150+
if (GetHashcode(kvp.first) == hash) {
151+
exists = true;
152+
153+
kvp.second = std::move(v);
154+
155+
break;
156+
}
157+
}
158+
159+
if (!exists) {
160+
m_Size++;
136161

137-
if (e_ptr != nullptr) {
138-
std::rethrow_exception(e_ptr);
162+
bucket.emplace_back(std::move(k), std::move(v));
139163
}
140164
}
141165
}
@@ -156,8 +180,6 @@ namespace LouiEriksson {
156180
*/
157181
const Tv& Return(const Tk& _key) const {
158182

159-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
160-
161183
const Tv* result = nullptr;
162184

163185
if (!m_Buckets.empty()) {
@@ -247,7 +269,7 @@ namespace LouiEriksson {
247269
* @return The number of items stored within the Hashmap.
248270
*/
249271
[[nodiscard]] const size_t& size() const noexcept {
250-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
272+
const std::shared_lock lock(s_Lock);
251273

252274
return m_Size;
253275
}
@@ -268,7 +290,7 @@ namespace LouiEriksson {
268290
*/
269291
bool ContainsKey(const Tk& _key) const noexcept {
270292

271-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
293+
const std::shared_lock lock(s_Lock);
272294

273295
auto result = false;
274296

@@ -303,8 +325,8 @@ namespace LouiEriksson {
303325
*/
304326
bool ContainsKey(const Tk& _key, std::exception_ptr& _exception) const noexcept {
305327

306-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
307-
328+
const std::shared_lock lock(s_Lock);
329+
308330
auto result = false;
309331

310332
try {
@@ -341,7 +363,7 @@ namespace LouiEriksson {
341363
*/
342364
bool Add(const Tk& _key, const Tv& _value) noexcept {
343365

344-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
366+
const std::unique_lock lock(s_Lock);
345367

346368
auto result = true;
347369

@@ -390,7 +412,7 @@ namespace LouiEriksson {
390412
*/
391413
bool Add(const Tk& _key, const Tv& _value, std::exception_ptr& _exception) noexcept {
392414

393-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
415+
const std::unique_lock lock(s_Lock);
394416

395417
auto result = true;
396418

@@ -440,7 +462,7 @@ namespace LouiEriksson {
440462
*/
441463
bool Add(const Tk&& _key, const Tv&& _value) noexcept {
442464

443-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
465+
const std::unique_lock lock(s_Lock);
444466

445467
auto result = true;
446468

@@ -489,7 +511,7 @@ namespace LouiEriksson {
489511
*/
490512
bool Add(const Tk&& _key, const Tv&& _value, std::exception_ptr& _exception) noexcept {
491513

492-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
514+
const std::unique_lock lock(s_Lock);
493515

494516
auto result = true;
495517

@@ -537,7 +559,7 @@ namespace LouiEriksson {
537559
*/
538560
void Assign(const Tk& _key, const Tv& _value) noexcept {
539561

540-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
562+
const std::unique_lock lock(s_Lock);
541563

542564
try {
543565

@@ -581,7 +603,7 @@ namespace LouiEriksson {
581603
*/
582604
void Assign(const Tk& _key, const Tv& _value, std::exception_ptr& _exception) noexcept {
583605

584-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
606+
const std::unique_lock lock(s_Lock);
585607

586608
try {
587609

@@ -626,7 +648,7 @@ namespace LouiEriksson {
626648
*/
627649
void Assign(Tk&& _key, Tv&& _value) noexcept {
628650

629-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
651+
const std::unique_lock lock(s_Lock);
630652

631653
try {
632654

@@ -670,7 +692,7 @@ namespace LouiEriksson {
670692
*/
671693
void Assign(Tk&& _key, Tv&& _value, std::exception_ptr& _exception) noexcept {
672694

673-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
695+
const std::unique_lock lock(s_Lock);
674696

675697
try {
676698

@@ -715,7 +737,7 @@ namespace LouiEriksson {
715737
*/
716738
bool Remove(const Tk& _key) noexcept {
717739

718-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
740+
const std::unique_lock lock(s_Lock);
719741

720742
bool result = false;
721743

@@ -756,7 +778,7 @@ namespace LouiEriksson {
756778
*/
757779
bool Remove(const Tk& _key, std::exception_ptr& _exception) noexcept {
758780

759-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
781+
const std::unique_lock lock(s_Lock);
760782

761783
bool result = false;
762784

@@ -800,7 +822,7 @@ namespace LouiEriksson {
800822
*/
801823
optional_ref Get(const Tk& _key) const noexcept {
802824

803-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
825+
const std::shared_lock lock(s_Lock);
804826

805827
typename optional_ref::optional_t result = std::nullopt;
806828

@@ -839,7 +861,7 @@ namespace LouiEriksson {
839861
*/
840862
optional_ref Get(const Tk& _key, std::exception_ptr& _exception) const noexcept {
841863

842-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
864+
const std::shared_lock lock(s_Lock);
843865

844866
typename optional_ref::optional_t result = std::nullopt;
845867

@@ -874,7 +896,7 @@ namespace LouiEriksson {
874896
*/
875897
void Trim() {
876898

877-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
899+
const std::unique_lock lock(s_Lock);
878900

879901
size_t trimStart = 1U;
880902

@@ -895,7 +917,7 @@ namespace LouiEriksson {
895917
*/
896918
[[nodiscard]] std::vector<Tk> Keys() const {
897919

898-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
920+
const std::shared_lock lock(s_Lock);
899921

900922
std::vector<Tk> result;
901923

@@ -914,7 +936,7 @@ namespace LouiEriksson {
914936
*/
915937
[[nodiscard]] std::vector<Tv> Values() const {
916938

917-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
939+
const std::shared_lock lock(s_Lock);
918940

919941
std::vector<Tv> result;
920942

@@ -933,7 +955,7 @@ namespace LouiEriksson {
933955
*/
934956
[[nodiscard]] std::vector<KeyValuePair> GetAll() const {
935957

936-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
958+
const std::shared_lock lock(s_Lock);
937959

938960
std::vector<KeyValuePair> result;
939961

@@ -953,7 +975,7 @@ namespace LouiEriksson {
953975
*/
954976
void Reserve(const std::size_t& _newSize) {
955977

956-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
978+
const std::unique_lock lock(s_Lock);
957979

958980
if (m_Size < _newSize) {
959981
Resize(_newSize);
@@ -965,7 +987,7 @@ namespace LouiEriksson {
965987
*/
966988
void Clear() noexcept {
967989

968-
const std::lock_guard<std::recursive_mutex> lock(s_Lock);
990+
const std::unique_lock lock(s_Lock);
969991

970992
try {
971993
m_Buckets.clear();
@@ -991,6 +1013,9 @@ namespace LouiEriksson {
9911013
[[deprecated("This function does not guarantee exception-safety and will explicitly throw if no entry exists. Consider using Get() if exception-safe access is required.\nSuppress this warning by defining \"HASHMAP_SUPPRESS_UNSAFE_WARNING\".")]]
9921014
#endif
9931015
const Tv& operator[](const Tk& _key) const {
1016+
1017+
const std::shared_lock lock(s_Lock);
1018+
9941019
return Return(_key);
9951020
}
9961021

0 commit comments

Comments
 (0)