1 /*
2  *
3  *  Copyright (C) 2009-2019, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module:  ofstd
15  *
16  *  Author:  Uli Schlachter
17  *
18  *  Purpose: Defines a template map class with interfaces similar to the C++
19  *           Standard
20  *
21  */
22 
23 #ifndef OFMAP_H
24 #define OFMAP_H
25 
26 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
27 
28 #include "dcmtk/ofstd/ofutil.h" // for OFPair
29 
30 #ifdef HAVE_STL_MAP
31 // it is possible to use the standard template library map class since the
32 // interface is nearly identical.
33 #include <map>
34 #define OFMap std::map
35 #else
36 
37 #include "dcmtk/ofstd/oftypes.h"
38 #include "dcmtk/ofstd/ofcast.h"
39 #include "dcmtk/ofstd/oflist.h"
40 
41 #ifndef HAVE_CLASS_TEMPLATE
42 #error Your C++ compiler cannot handle class templates:
43 #endif
44 
45 /** associative container class. This class is a subset of std::map.
46  */
47 template<typename K, typename V> class OFMap
48 {
49 public:
50 
51     /** the type of values saved in this map */
52     typedef OFPair<const K, V> value_type;
53 
54 protected:
55 
56     /// @todo using a list as base is slooooow
57     OFList<value_type> values_;
58 
59 public:
60 
61     /** iterator class for OFMap. You can modify elements through this
62      *  iterator's ->first and ->second properties.
63      */
64     typedef OFListIterator(value_type) iterator;
65 
66     /** constant iterator class for OFMap. You can read the elements, but you may
67      *  not modify them.
68      */
69     typedef OFListConstIterator(value_type) const_iterator;
70 
71     /** default constructor */
OFMap()72     OFMap() : values_() { }
73 
74     /** assignment operator */
75     OFMap& operator=(const OFMap& other)
76     {
77         if (this == &other)
78             return *this;
79 
80         clear();
81 
82         for (const_iterator it = other.begin();
83                 it != other.end(); it++)
84             insert(*it);
85 
86         return *this;
87     }
88 
89     /** index operator. You can use this to add new elements to the map.
90      *  Beware: Don't use this for checking if a given key is already used in
91      *  the map, use find() != end() for this job!
92      *  @param key the key you want to access
93      *  @return reference to the value saved under the given key.
94      */
95     V& operator[](const K& key)
96     {
97         iterator it = find(key);
98         if (it == end())
99         {
100             it = insert(value_type(key, V())).first;
101         }
102 
103         return it->second;
104     }
105 
106     /** returns iterator pointing to the first element of this map
107      *  @return iterator pointing to the first element of this map
108      */
begin()109     iterator begin() { return values_.begin(); }
110 
111     /** returns iterator pointer after the last element of this map
112      *  @return iterator pointer after the last element of this map
113      */
end()114     iterator end() { return values_.end(); }
115 
116     /** returns constant iterator pointing to the first element of this map
117      *  @return constant iterator pointing to the first element of this map
118      */
begin()119     const_iterator begin() const { return values_.begin(); }
120 
121     /** returns constant iterator pointer after the last element of this map
122      *  @return constant iterator pointer after the last element of this map
123      */
end()124     const_iterator end() const { return values_.end(); }
125 
126     /** looks up the given key in this map
127      *  @param key the key to look for
128      *  @return iterator for that key to end()
129      */
find(const K & key)130     iterator find(const K& key)
131     {
132         iterator it = begin();
133         while (it != end())
134         {
135             if (it->first == key)
136                 break;
137             it++;
138         }
139 
140         return it;
141     }
142 
143     /** looks up the given key in this map
144      *  @param key the key to look for
145      *  @return constant iterator for that key to end()
146      */
find(const K & key)147     const_iterator find(const K& key) const
148     {
149         const_iterator it = begin();
150         while (it != end())
151         {
152             if (it->first == key)
153                 break;
154             it++;
155         }
156 
157         return it;
158     }
159 
160     /** returns whether this map is empty (i.e.\ whether its size is 0)
161      *  @return OFTrue if this map is empty, OFFalse otherwise
162      */
empty()163     OFBool empty() const { return values_.size() == 0; }
164 
165     /** returns the number of elements saved in this map
166      *  @return the number of elements saved in this map
167      */
size()168     size_t size() const { return values_.size(); }
169 
170     /** removes all elements from this map */
clear()171     void clear() { values_.clear(); }
172 
173     /** removes all elements in the given range from this map
174      *  @param first the first element to remove
175      *  @param last the first element NOT to remove
176      */
erase(const iterator & first,const iterator & last)177     void erase(const iterator& first, const iterator& last)
178     {
179         values_.erase(first, last);
180     }
181 
182     /** removes the element to which the given iterator points to
183      *  @param elem the element to remove
184      */
erase(const iterator & elem)185     void erase(const iterator& elem)
186     {
187         values_.erase(elem);
188     }
189 
190     /** removes the element with the given key from this map
191      *  @return the number of elements removed (0 or 1)
192      */
erase(const K & key)193     int erase(const K& key)
194     {
195         iterator it = find(key);
196         if (it == end())
197             return 0;
198 
199         values_.erase(it);
200         return 1;
201     }
202 
203     /** inserts a new element into the map, but does not overwrite existing
204      *  elements
205      *  @param val the value to insert
206      *  @return a pair of an iterator and a boolean. The iterator always points
207      *  to the element which got val's key. The boolean is true if val was
208      *  inserted, false otherwise.
209      */
insert(const value_type & val)210     OFPair<iterator, bool> insert(const value_type& val)
211     {
212         // If value already exists, return it
213         OFListIterator(value_type) it = find(val.first);
214         if (it != end())
215             return OFMake_pair(it, false);
216 
217         // Sorted insertion
218         it = begin();
219         while ( (it != end()) && (val.first > it->first) )
220             it++;
221         if (it == end())
222             it = values_.insert(values_.end(), val);
223         else
224         {
225             // Insert at current position and rewind iterator
226             // to the inserted element
227             values_.insert(it, val);
228             it--;
229         }
230 
231         return OFMake_pair(it, true);
232     }
233 
234     /** swaps the contents of the two maps. The time complexity of this
235      *  function should be constant.
236      *  @param s map to swap with
237      */
swap(OFMap<K,V> & s)238     void swap(OFMap<K, V>& s)
239     {
240         OFList<value_type> own_values = values_;
241         values_ = s.values_;
242         s.values_ = own_values;
243     }
244 };
245 
246 #endif
247 #endif
248