Thread-Safe Map Class in C++: Generic and Production-Ready

Discover a generic, thread-safe map class in C++ that’s production-ready and handles any data type. Unlike std::map, which is not thread-safe by default, this class ensures safe concurrent access in multi-threaded environments.

Why Use This?
This thread-safe map class offers robust protection against concurrent access issues, unlike the default std::map, which isn’t thread-safe. Its generic design accommodates any data type, making it a versatile choice for reliable and efficient multi-threaded applications.

Source code:

#ifndef ThreadSafeMap_h
#define ThreadSafeMap_h
#include <map>
#include <mutex>

namespace your_namespace {
template <class Key, class T, class Compare = std::less<Key>,
          class Allocator = std::allocator<std::pair<const Key, T>>>
class ThreadSafeMap {
  public:
    typedef typename std::map<Key, T, Compare, Allocator>::iterator iterator;
    typedef typename std::map<Key, T, Compare, Allocator>::const_iterator
        const_iterator;
    typedef typename std::map<Key, T, Compare, Allocator>::reverse_iterator
        reverse_iterator;
    typedef
        typename std::map<Key, T, Compare, Allocator>::const_reverse_iterator
            const_reverse_iterator;
    typedef typename std::map<Key, T, Compare, Allocator>::allocator_type
        allocator_type;
    typedef typename std::map<Key, T, Compare, Allocator>::size_type size_type;
    typedef
        typename std::map<Key, T, Compare, Allocator>::key_compare key_compare;
    typedef typename std::map<Key, T, Compare, Allocator>::value_compare
        value_compare;
    typedef
        typename std::map<Key, T, Compare, Allocator>::value_type value_type;

    explicit ThreadSafeMap(const Compare &comp = Compare(),
                           const Allocator &alloc = Allocator())
        : internal(comp, alloc) {}
    template <class InputIterator>
    ThreadSafeMap(InputIterator first, InputIterator last,
                  const Compare &comp = Compare(),
                  const Allocator &alloc = Allocator())
        : internal(first, last, comp, alloc) {}
    ThreadSafeMap(const ThreadSafeMap<Key, T, Compare, Allocator> &x)
        : internal(x.internal) {}
    ThreadSafeMap(std::initializer_list<std::pair<const Key, T>> ilist,
                  const Compare &comp = Compare(),
                  const Allocator &alloc = Allocator())
        : internal(ilist, comp, alloc) {}

    ThreadSafeMap<Key, Compare, Allocator> &
    operator=(const ThreadSafeMap<Key, Compare, Allocator> &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        std::scoped_lock<std::mutex> lock2(x.mutex);
        internal = x.internal;
        return *this;
    }

    iterator begin(void) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.begin();
    }
    const_iterator begin(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.begin();
    }

    iterator end(void) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.end();
    }
    const_iterator end(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.end();
    }

    reverse_iterator rbegin(void) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.rbegin();
    }
    const_reverse_iterator rbegin(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.rbegin();
    }

    reverse_iterator rend(void) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.rend();
    }
    const_reverse_iterator rend(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.rend();
    }

    T &operator[](const Key &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal[x];
    }

    std::pair<iterator, bool> insert(const value_type &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.insert(x);
    }
    template <class... _Args>
    std::pair<iterator, bool> emplace(_Args &&...args) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.emplace(std::forward<_Args>(args)...);
    }
    iterator insert(iterator position, const value_type &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.insert(position, x);
    }
    template <class InputIterator>
    void insert(InputIterator first, InputIterator last) {
        std::scoped_lock<std::mutex> lock(mutex);
        internal.insert(first, last);
    }

    void erase(iterator pos) {
        std::scoped_lock<std::mutex> lock(mutex);
        internal.erase(pos);
    }
    size_type erase(const Key &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.erase(x);
    }
    void erase(iterator begin, iterator end) {
        std::scoped_lock<std::mutex> lock(mutex);
        internal.erase(begin, end);
    }

    void swap(ThreadSafeMap<Key, T, Compare, Allocator> &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        std::scoped_lock<std::mutex> lock2(x.mutex);
        internal.swap(x.internal);
    }

    void clear(void) {
        std::scoped_lock<std::mutex> lock(mutex);
        internal.clear();
    }

    // Observers
    key_compare key_comp(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.key_comp();
    }
    value_compare value_comp(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.value_comp();
    }

    // Operations
    const_iterator find(const Key &x) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.find(x);
    }
    iterator find(const Key &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.find(x);
    }

    size_type count(const Key &x) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.count(x);
    }

    bool contains(const Key &x) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.contains(x);
    }

    const_iterator lower_bound(const Key &x) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.lower_bound(x);
    }
    iterator lower_bound(const Key &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.lower_bound(x);
    }

    const_iterator upper_bound(const Key &x) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.upper_bound(x);
    }
    iterator upper_bound(const Key &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.upper_bound(x);
    }

    std::pair<const_iterator, const_iterator> equal_range(const Key &x) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.equal_range(x);
    }
    std::pair<iterator, iterator> equal_range(const Key &x) {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.equal_range(x);
    }

    size_type size(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.size();
    }

    size_type max_size(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.max_size();
    }

    bool empty(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.empty();
    }

    allocator_type get_allocator(void) const {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal.get_allocator();
    }

    ~ThreadSafeMap(void) {}

    std::map<Key, T, Compare, Allocator> get() {
        std::scoped_lock<std::mutex> lock(mutex);
        return internal;
    }

  private:
    std::map<Key, T, Compare, Allocator> internal;
    mutable std::mutex mutex;
};
} // namespace Your_namespace
#endif /* ThreadSafeMap_h */