File: StaticHashMapIterator.h

package info (click to toggle)
jazz2-native 3.5.0-2
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 16,912 kB
  • sloc: cpp: 172,557; xml: 113; python: 36; makefile: 5; sh: 2
file content (278 lines) | stat: -rw-r--r-- 10,188 bytes parent folder | download
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#pragma once

#include "StaticHashMap.h"
#include "Iterator.h"

namespace nCine
{
	/// Base helper structure for type traits used in the hashmap iterator
	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	struct StaticHashMapHelperTraits
	{};

	/// Helper structure providing type traits used in the non constant hashmap iterator
	template<class K, class T, class HashFunc, std::uint32_t Capacity>
	struct StaticHashMapHelperTraits<K, T, HashFunc, Capacity, false>
	{
		using HashMapPtr = StaticHashMap<K, T, Capacity, HashFunc>*;
		using NodeReference = typename StaticHashMap<K, T, Capacity, HashFunc>::Node&;
	};

	/// Helper structure providing type traits used in the constant hashmap iterator
	template<class K, class T, class HashFunc, std::uint32_t Capacity>
	struct StaticHashMapHelperTraits<K, T, HashFunc, Capacity, true>
	{
		using HashMapPtr = const StaticHashMap<K, T, Capacity, HashFunc>*;
		using NodeReference = const typename StaticHashMap<K, T, Capacity, HashFunc>::Node&;
	};

	/// Static hashmap iterator
	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	class StaticHashMapIterator
	{
	public:
		/// Reference type which respects iterator constness
		using Reference = typename IteratorTraits<StaticHashMapIterator>::Reference;

		/// Sentinel tags to initialize the iterator at the beginning and end
		enum class SentinelTagInit
		{
			/// Iterator at the beginning, next element is the first one
			BEGINNING,
			/// Iterator at the end, previous element is the last one
			END
		};

		StaticHashMapIterator(typename StaticHashMapHelperTraits<K, T, HashFunc, Capacity, IsConst>::HashMapPtr hashMap, std::uint32_t bucketIndex)
			: hashMap_(hashMap), bucketIndex_(bucketIndex), tag_(SentinelTag::REGULAR) {}

		StaticHashMapIterator(typename StaticHashMapHelperTraits<K, T, HashFunc, Capacity, IsConst>::HashMapPtr hashMap, SentinelTagInit tag);

		/// Copy constructor to implicitly convert a non constant iterator to a constant one
		StaticHashMapIterator(const StaticHashMapIterator<K, T, HashFunc, Capacity, false>& it)
			: hashMap_(it.hashMap_), bucketIndex_(it.bucketIndex_), tag_(SentinelTag(it.tag_)) {}

		/// Deferencing operator
		Reference operator*() const;

		/// Iterates to the next element (prefix)
		StaticHashMapIterator& operator++();
		/// Iterates to the next element (postfix)
		StaticHashMapIterator operator++(int);

		/// Iterates to the previous element (prefix)
		StaticHashMapIterator& operator--();
		/// Iterates to the previous element (postfix)
		StaticHashMapIterator operator--(int);

		/// Equality operator
		friend inline bool operator==(const StaticHashMapIterator& lhs, const StaticHashMapIterator& rhs)
		{
			if (lhs.tag_ == SentinelTag::REGULAR && rhs.tag_ == SentinelTag::REGULAR) {
				return (lhs.hashMap_ == rhs.hashMap_ && lhs.bucketIndex_ == rhs.bucketIndex_);
			} else {
				return (lhs.tag_ == rhs.tag_);
			}
		}

		/// Inequality operator
		friend inline bool operator!=(const StaticHashMapIterator& lhs, const StaticHashMapIterator& rhs)
		{
			if (lhs.tag_ == SentinelTag::REGULAR && rhs.tag_ == SentinelTag::REGULAR) {
				return (lhs.hashMap_ != rhs.hashMap_ || lhs.bucketIndex_ != rhs.bucketIndex_);
			} else {
				return (lhs.tag_ != rhs.tag_);
			}
		}

		/// Returns the hashmap node currently pointed by the iterator
		typename StaticHashMapHelperTraits<K, T, HashFunc, Capacity, IsConst>::NodeReference node() const;
		/// Returns the value associated to the currently pointed node
		const T& value() const;
		/// Returns the key associated to the currently pointed node
		const K& key() const;
		/// Returns the hash associated to the currently pointed node
		hash_t hash() const;

	private:
		/// Sentinel tags to detect begin and end conditions
		enum SentinelTag {
			/// Iterator poiting to a real element
			REGULAR,
			/// Iterator at the beginning, next element is the first one
			BEGINNING,
			/// Iterator at the end, previous element is the last one
			END
		};

		typename StaticHashMapHelperTraits<K, T, HashFunc, Capacity, IsConst>::HashMapPtr hashMap_;
		std::uint32_t bucketIndex_;
		SentinelTag tag_;

		/// Makes the iterator point to the next element in the hashmap
		void next();
		/// Makes the iterator point to the previous element in the hashmap
		void previous();

		/// For non constant to constant iterator implicit conversion
		friend class StaticHashMapIterator<K, T, HashFunc, Capacity, true>;
	};

#ifndef DOXYGEN_GENERATING_OUTPUT

	/// Iterator traits structure specialization for `HashMapIterator` class
	template<class K, class T, class HashFunc, std::uint32_t Capacity>
	struct IteratorTraits<StaticHashMapIterator<K, T, HashFunc, Capacity, false>>
	{
		/// Type of the values deferenced by the iterator
		using ValueType = T;
		/// Pointer to the type of the values deferenced by the iterator
		using Pointer = T*;
		/// Reference to the type of the values deferenced by the iterator
		using Reference = T&;
		/// Type trait for iterator category
		static inline BidirectionalIteratorTag IteratorCategory() {
			return BidirectionalIteratorTag();
		}
	};

	/// Iterator traits structure specialization for constant `HashMapIterator` class
	template<class K, class T, class HashFunc, std::uint32_t Capacity>
	struct IteratorTraits<StaticHashMapIterator<K, T, HashFunc, Capacity, true>>
	{
		/// Type of the values deferenced by the iterator (never const)
		using ValueType = T;
		/// Pointer to the type of the values deferenced by the iterator
		using Pointer = const T*;
		/// Reference to the type of the values deferenced by the iterator
		using Reference = const T&;
		/// Type trait for iterator category
		static inline BidirectionalIteratorTag IteratorCategory() {
			return BidirectionalIteratorTag();
		}
	};

#endif

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::StaticHashMapIterator(typename StaticHashMapHelperTraits<K, T, HashFunc, Capacity, IsConst>::HashMapPtr hashMap, SentinelTagInit tag)
		: hashMap_(hashMap), bucketIndex_(0)
	{
		switch (tag) {
			case SentinelTagInit::BEGINNING: tag_ = SentinelTag::BEGINNING; break;
			case SentinelTagInit::END: tag_ = SentinelTag::END; break;
		}
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	typename StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::Reference StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::operator*() const
	{
		return node().value;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>& StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::operator++()
	{
		next();
		return *this;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst> StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::operator++(int)
	{
		// Create an unmodified copy to return
		StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst> iterator = *this;
		next();
		return iterator;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>& StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::operator--()
	{
		previous();
		return *this;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst> StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::operator--(int)
	{
		// Create an unmodified copy to return
		StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst> iterator = *this;
		previous();
		return iterator;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	typename StaticHashMapHelperTraits<K, T, HashFunc, Capacity, IsConst>::NodeReference StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::node() const
	{
		return hashMap_->nodes_[bucketIndex_];
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	const T& StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::value() const
	{
		return node().value;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	const K& StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::key() const
	{
		return node().key;
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	hash_t StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::hash() const
	{
		return hashMap_->hashes_[bucketIndex_];
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	void StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::next()
	{
		if (tag_ == SentinelTag::REGULAR) {
			if (bucketIndex_ >= hashMap_->capacity() - 1) {
				tag_ = SentinelTag::END;
				return;
			} else {
				bucketIndex_++;
			}
		} else if (tag_ == SentinelTag::BEGINNING) {
			tag_ = SentinelTag::REGULAR;
			bucketIndex_ = 0;
		} else if (tag_ == SentinelTag::END) {
			return;
		}
		// Search the first non empty index starting from the current one
		while (bucketIndex_ < hashMap_->capacity() - 1 && hashMap_->hashes_[bucketIndex_] == NullHash) {
			bucketIndex_++;
		}
		if (hashMap_->hashes_[bucketIndex_] == NullHash) {
			tag_ = SentinelTag::END;
		}
	}

	template<class K, class T, class HashFunc, std::uint32_t Capacity, bool IsConst>
	void StaticHashMapIterator<K, T, HashFunc, Capacity, IsConst>::previous()
	{
		if (tag_ == SentinelTag::REGULAR) {
			if (bucketIndex_ == 0) {
				tag_ = SentinelTag::BEGINNING;
				return;
			} else {
				bucketIndex_--;
			}
		} else if (tag_ == SentinelTag::END) {
			tag_ = SentinelTag::REGULAR;
			bucketIndex_ = hashMap_->capacity() - 1;
		} else if (tag_ == SentinelTag::BEGINNING) {
			return;
		}
		// Search the first non empty index starting from the current one
		while (bucketIndex_ > 0 && hashMap_->hashes_[bucketIndex_] == NullHash) {
			bucketIndex_--;
		}
		if (hashMap_->hashes_[bucketIndex_] == NullHash) {
			tag_ = SentinelTag::BEGINNING;
		}
	}
}