summaryrefslogtreecommitdiffstats
path: root/src/linkedmap.h
blob: c724a39959401218887658d4005442c379d4cc6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/******************************************************************************
 *
 * Copyright (C) 1997-2020 by Dimitri van Heesch.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation under the terms of the GNU General Public License is hereby
 * granted. No representations are made about the suitability of this software
 * for any purpose. It is provided "as is" without express or implied warranty.
 * See the GNU General Public License for more details.
 *
 * Documents produced by Doxygen are derivative works derived from the
 * input used in their production; they are not affected by this license.
 *
 */

#ifndef LINKEDMAP_H
#define LINKEDMAP_H

#include <unordered_map>
#include <vector>
#include <memory>
#include <string>

//! @brief Container class representing a vector of objects with unique keys.
//! @details Elements can be quickly looked up given the key.
//! When adding objects the order of addition is kept, and used while iterating.
template<class T>
class LinkedMap
{
  public:
    using Ptr = std::unique_ptr<T>;
    using Vec = std::vector<Ptr>;
    using Map = std::unordered_map<std::string,T*>;
    using iterator = typename Vec::iterator;
    using const_iterator = typename Vec::const_iterator;

    //! find an element given the key.
    //! Returns a pointer to the element if found or nullptr if it is not found.
    const T *find(const char *k) const
    {
      std::string key = k ? std::string(k) : std::string();
      auto it = m_lookup.find(key);
      return it!=m_lookup.end() ? it->second : nullptr;
    }

    //! non-const wrapper for find() const
    T* find(const char *key)
    {
      return const_cast<T*>(static_cast<const LinkedMap&>(*this).find(key));
    }

    //! Adds a new element to the ordered set if it was not added already.
    //! Return a non-owning pointer to the newly added item, or to the existing item if it was
    //! already inserted before.
    template<class...Args>
    T *add(const char *k, Args&&... args)
    {
      T *result = find(k);
      if (result==nullptr)
      {
        std::string key = k ? std::string(k) : std::string();
        Ptr ptr = std::make_unique<T>(k,std::forward<Args>(args)...);
        result = ptr.get();
        m_lookup.insert({key,result});
        m_entries.push_back(std::move(ptr));
      }
      return result;
    }

    iterator begin()    { return m_entries.begin(); }
    iterator end()      { return m_entries.end();   }
    const_iterator begin() const    { return m_entries.cbegin(); }
    const_iterator end() const     { return m_entries.cend();   }
    bool empty() const  { return m_entries.empty(); }
    int size() const    { return m_entries.size();  }

    void clear()
    {
      m_entries.clear();
      m_lookup.clear();
    }

  private:
    Map m_lookup;
    Vec m_entries;
};


#endif