A thread-safe dictionary container with reader-writer locking for efficient concurrent access.
RWLContainer is a template class that wraps std::unordered_map with std::shared_mutex to provide safe concurrent access. Multiple threads can read simultaneously, while writes are exclusive. All values are stored as shared_ptr for automatic memory management.
template <class KeyType,
class StorageType,
typename StorageContainer = std::unordered_map<KeyType, std::shared_ptr<StorageType>>>
class RWLContainer
| Parameter | Description | Default |
|---|---|---|
KeyType |
The key type (e.g., std::string, int) |
Required |
StorageType |
The value type to store (use value types, not pointers) | Required |
StorageContainer |
The underlying container type | std::unordered_map<KeyType, std::shared_ptr<StorageType>> |
bool ReplaceExisting {false};
Controls behavior when adding a key that already exists:
true - Replaces the existing valuefalse - Returns the existing value without modificationbool FailOnCollission {false};
Controls behavior when adding a key that already exists:
true - Returns empty shared_ptr on collisionfalse - Returns existing value on collisionNote: FailOnCollission takes precedence over ReplaceExisting.
Adds or updates an element by moving a value into a shared_ptr.
StorageTypePtr add(const KeyType& key, StorageType&& value)
Parameters:
key - The key to associate with the valuevalue - The value to store (moved into shared_ptr)Returns: shared_ptr<StorageType> to the newly inserted or existing item, or empty shared_ptr on collision with FailOnCollission=true
Thread Safety: Exclusive write lock
Collision Behavior:
FailOnCollission=true → Returns empty shared_ptrReplaceExisting=true → Replaces existing valueExample:
siddiqsoft::RWLContainer<std::string, int> cache;
auto item = cache.add("key1", 42);
if (item) {
std::cout << "Added: " << *item << std::endl;
}
Throws: std::runtime_error if insertion fails
Adds or updates an element using an existing shared_ptr.
StorageTypePtr add(const KeyType& key, StorageTypePtr&& value)
Parameters:
key - The key to associate with the valuevalue - The shared_ptr to store (moved into container)Returns: shared_ptr<StorageType> to the newly inserted or existing item
Thread Safety: Exclusive write lock
Note: The input shared_ptr is moved; the original reference becomes invalid.
Example:
auto ptr = std::make_shared<int>(42);
auto item = cache.add("key1", std::move(ptr));
Adds an element by invoking a callback function for lazy initialization.
StorageTypePtr add(const KeyType& key,
std::function<StorageTypePtr(const KeyType&)>&& newObjectCallback)
Parameters:
key - The key to addnewObjectCallback - Callback that accepts the key and returns shared_ptr<StorageType>Returns: shared_ptr<StorageType> to the newly created or existing item
Thread Safety: Exclusive write lock
Note: The callback executes within the write lock, so keep it brief.
Example:
auto item = cache.add("key1", [](const auto& key) {
return std::make_shared<int>(42);
});
Removes and returns an element by key.
[[nodiscard]] StorageTypePtr remove(const KeyType& key)
Parameters:
key - The key to removeReturns: shared_ptr<StorageType> to the removed item, or empty shared_ptr if key not found
Thread Safety: Exclusive write lock
Note: The returned shared_ptr keeps the item alive even after removal from container.
Example:
auto removed = cache.remove("key1");
if (removed) {
std::cout << "Removed: " << *removed << std::endl;
}
Finds and returns an element by key without removing it.
StorageTypePtr find(const KeyType& key)
Parameters:
key - The key to findReturns: shared_ptr<StorageType> to the found item, or empty shared_ptr if key not found
Thread Safety: Shared read lock (allows concurrent reads)
Note: Multiple threads can call find() simultaneously.
Example:
auto item = cache.find("key1");
if (item) {
std::cout << "Found: " << *item << std::endl;
}
Returns the number of elements in the container.
size_t size() const
Returns: The number of elements currently in the container
Thread Safety: Shared read lock
Complexity: O(1)
Example:
std::cout << "Container has " << cache.size() << " items" << std::endl;
Iterates through all elements and returns the first match.
StorageTypePtr scan(std::function<bool(const KeyType&, StorageTypePtr&)> scanCallback)
Parameters:
scanCallback - Callback function that receives (key, value) and returns true to stop iterationReturns: shared_ptr<StorageType> to the first matching item, or empty shared_ptr if no match found
Thread Safety: Shared read lock (entire scan is atomic)
Note: The callback is invoked for each element until it returns true.
Example:
auto item = cache.scan([](const auto& key, auto& value) {
return key.find("target") != std::string::npos;
});
Serializes container metadata to JSON.
nlohmann::json toJson()
Returns: JSON object with container statistics
Thread Safety: Shared read lock
Requirements: nlohmann/json.hpp must be included before this header
JSON Structure:
{
"_typver": "RWLContainer/1.5.3",
"adds": 42,
"removes": 10,
"ReplaceExisting": false,
"FailOnCollission": false,
"size": 32
}
Example:
#include "nlohmann/json.hpp"
auto json = cache.toJson();
std::cout << json.dump(2) << std::endl;
All operations in RWLContainer are thread-safe:
find, size, scan) use shared locks - multiple threads can execute concurrentlyadd, remove) use exclusive locks - only one thread can execute at a time_counterAdds, _counterRemoves) are thread-safe| Operation | Complexity | Lock Type |
|---|---|---|
add() |
O(1) average | Exclusive |
remove() |
O(1) average | Exclusive |
find() |
O(1) average | Shared |
size() |
O(1) | Shared |
scan() |
O(n) | Shared |
std::string or numeric types with good hash functionsshared_ptradd() execute within the write lockfind() or remove() returned a valid shared_ptrReplaceExisting and FailOnCollission based on your use casesiddiqsoft::RWLContainer<std::string, std::string> cache;
// Try to find, if not found, add
auto item = cache.find("key");
if (!item) {
item = cache.add("key", "value");
}
auto item = cache.add("key", [](const auto& key) {
return std::make_shared<ExpensiveObject>(key);
});
cache.ReplaceExisting = true;
auto newItem = cache.add("key", "new_value");
Version: 1.5.3
Last Updated: 2024