Skip to content

Commit 1a16b3a

Browse files
committed
New implementation of ordered_map, O(1) on all practically used methods.
1 parent bfcd214 commit 1a16b3a

File tree

4 files changed

+1323
-298
lines changed

4 files changed

+1323
-298
lines changed

include/nlohmann/ordered_map.hpp

Lines changed: 81 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ template<class Key,
5252
class T,
5353
class IgnoredCompare = std::less<Key>, // Unused
5454
class Allocator = std::allocator<std::pair<const Key, T>>>
55-
struct ordered_map
55+
struct ordered_map
5656
{
57-
private:
57+
private:
5858
using value_pair = std::pair<const Key, T>;
5959
using list_type = std::list<value_pair, Allocator>;
6060
using list_iterator = typename list_type::iterator;
@@ -70,7 +70,7 @@ struct ordered_map
7070
};
7171
struct key_ref_hash
7272
{
73-
std::size_t operator()(const key_ref& kr) const noexcept
73+
std::size_t operator()(const key_ref& kr) const
7474
{
7575
return std::hash<Key> {}(*kr.p);
7676
}
@@ -98,87 +98,87 @@ struct ordered_map
9898
using reference = Ref;
9999
using pointer = Ptr;
100100

101-
iter_base() : it_() {}
102-
explicit iter_base(ListIter it) : it_(it) {}
101+
iter_base() : it_() {}
102+
explicit iter_base(ListIter it) : it_(it) {}
103103

104-
reference operator*() const
105-
{
106-
return *it_;
107-
}
108-
pointer operator->() const
109-
{
110-
return std::addressof(*it_);
111-
}
104+
reference operator*() const
105+
{
106+
return *it_;
107+
}
108+
pointer operator->() const
109+
{
110+
return std::addressof(*it_);
111+
}
112112

113-
Self& operator++()
114-
{
115-
++it_;
116-
return self();
117-
}
118-
Self operator++(int)
119-
{
120-
Self tmp = self();
121-
++(*this);
122-
return tmp;
123-
}
124-
Self& operator--()
125-
{
126-
--it_;
127-
return self();
128-
}
129-
Self operator--(int)
130-
{
131-
Self tmp = self();
132-
--(*this);
133-
return tmp;
134-
}
113+
Self& operator++()
114+
{
115+
++it_;
116+
return self();
117+
}
118+
Self operator++(int)
119+
{
120+
Self tmp = self();
121+
++(*this);
122+
return tmp;
123+
}
124+
Self& operator--()
125+
{
126+
--it_;
127+
return self();
128+
}
129+
Self operator--(int)
130+
{
131+
Self tmp = self();
132+
--(*this);
133+
return tmp;
134+
}
135135

136-
// This is O(n), but used only by unit tests
137-
Self operator+(difference_type n) const
138-
{
139-
Self tmp = self();
140-
if (n >= 0) // NOLINT(*-braces-around-statements)
141-
while (n--)
142-
{
143-
++tmp.it_;
144-
}
145-
else // NOLINT(*-braces-around-statements)
146-
while (n++)
147-
{
148-
--tmp.it_;
149-
}
150-
return tmp;
151-
}
152-
Self& operator+=(difference_type n)
153-
{
154-
*this = *this + n;
155-
return self();
156-
}
136+
// This is O(n), but used only by unit tests
137+
Self operator+(difference_type n) const
138+
{
139+
Self tmp = self();
140+
if (n >= 0) // NOLINT(*-braces-around-statements)
141+
while (n--)
142+
{
143+
++tmp.it_;
144+
}
145+
else // NOLINT(*-braces-around-statements)
146+
while (n++)
147+
{
148+
--tmp.it_;
149+
}
150+
return tmp;
151+
}
152+
Self& operator+=(difference_type n)
153+
{
154+
*this = *this + n;
155+
return self();
156+
}
157157

158-
bool operator==(const Self& o) const
159-
{
160-
return it_ == o.it_;
161-
}
162-
bool operator!=(const Self& o) const
163-
{
164-
return it_ != o.it_;
165-
}
158+
bool operator==(const Self& o) const
159+
{
160+
return it_ == o.it_;
161+
}
162+
bool operator!=(const Self& o) const
163+
{
164+
return it_ != o.it_;
165+
}
166166

167-
ListIter base() const
168-
{
169-
return it_;
170-
}
167+
ListIter base() const
168+
{
169+
return it_;
170+
}
171171

172172
private:
173-
ListIter it_;
174-
Self& self()
175-
{
176-
return static_cast<Self&>(*this);
177-
}
178-
const Self& self() const
179-
{
180-
return static_cast<const Self&>(*this);
181-
}
173+
ListIter it_;
174+
Self& self()
175+
{
176+
return static_cast<Self&>(*this);
177+
}
178+
const Self& self() const
179+
{
180+
return static_cast<const Self&>(*this);
181+
}
182182
};
183183

184184
// Strong-safety rebuild: build a temporary index, then swap.
@@ -318,7 +318,8 @@ struct ordered_map
318318
{
319319
if (this != &other)
320320
{
321-
m_list = other.m_list;
321+
list_type tmp(other.m_list); // may throw; strong guarantee
322+
m_list.swap(tmp);
322323
rebuild_index();
323324
}
324325
return *this;
@@ -328,7 +329,8 @@ struct ordered_map
328329
{
329330
if (this != &other)
330331
{
331-
m_list = std::move(other.m_list);
332+
list_type tmp(std::move(other.m_list)); // noexcept move-construct
333+
m_list.swap(tmp);
332334
rebuild_index();
333335
}
334336
return *this;

0 commit comments

Comments
 (0)