Skip to content

Commit f9b4d9e

Browse files
committed
irept: Use singly-linked lists with SUB_IS_LIST
This reduces the memory footprint by two pointers for both named_sub and comments. The cost is that computing the size of lists and add/remove require additional iterator increments.
1 parent d4649bc commit f9b4d9e

File tree

6 files changed

+122
-36
lines changed

6 files changed

+122
-36
lines changed

src/util/irep.cpp

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ void irept::nonrecursive_destructor(dt *old_data)
152152

153153
if(d->ref_count==0)
154154
{
155-
stack.reserve(stack.size()+
156-
d->named_sub.size()+
157-
d->sub.size());
155+
stack.reserve(
156+
stack.size() + std::distance(d->named_sub.begin(), d->named_sub.end()) +
157+
d->sub.size());
158158

159159
for(named_subt::iterator
160160
it=d->named_sub.begin();
@@ -263,7 +263,12 @@ void irept::remove(const irep_namet &name)
263263
named_subt::iterator it=named_subt_lower_bound(s, name);
264264

265265
if(it!=s.end() && it->first==name)
266-
s.erase(it);
266+
{
267+
named_subt::iterator before = s.before_begin();
268+
while(std::next(before) != it)
269+
++before;
270+
s.erase_after(before);
271+
}
267272
#else
268273
s.erase(name);
269274
#endif
@@ -298,7 +303,12 @@ irept &irept::add(const irep_namet &name)
298303

299304
if(it==s.end() ||
300305
it->first!=name)
301-
it=s.insert(it, std::make_pair(name, irept()));
306+
{
307+
named_subt::iterator before = s.before_begin();
308+
while(std::next(before) != it)
309+
++before;
310+
it = s.emplace_after(before, name, irept());
311+
}
302312

303313
return it->second;
304314
#else
@@ -315,7 +325,12 @@ irept &irept::add(const irep_namet &name, const irept &irep)
315325

316326
if(it==s.end() ||
317327
it->first!=name)
318-
it=s.insert(it, std::make_pair(name, irep));
328+
{
329+
named_subt::iterator before = s.before_begin();
330+
while(std::next(before) != it)
331+
++before;
332+
it = s.emplace_after(before, name, irep);
333+
}
319334
else
320335
it->second=irep;
321336

@@ -410,10 +425,20 @@ bool irept::full_eq(const irept &other) const
410425
const irept::named_subt &i1_named_sub=get_named_sub();
411426
const irept::named_subt &i2_named_sub=other.get_named_sub();
412427

428+
#ifdef SUB_IS_LIST
429+
if(
430+
i1_sub.size() != i2_sub.size() ||
431+
std::distance(i1_named_sub.begin(), i1_named_sub.end()) !=
432+
std::distance(i2_named_sub.begin(), i2_named_sub.end()))
433+
{
434+
return false;
435+
}
436+
#else
413437
if(
414438
i1_sub.size() != i2_sub.size() ||
415439
i1_named_sub.size() != i2_named_sub.size())
416440
return false;
441+
#endif
417442

418443
for(std::size_t i=0; i<i1_sub.size(); i++)
419444
if(!i1_sub[i].full_eq(i2_sub[i]))
@@ -667,7 +692,13 @@ std::size_t irept::full_hash() const
667692
result=hash_combine(result, it->second.full_hash());
668693
}
669694

670-
result = hash_finalize(result, named_sub.size() + sub.size());
695+
#ifdef SUB_IS_LIST
696+
const std::size_t named_sub_size =
697+
std::distance(named_sub.begin(), named_sub.end());
698+
#else
699+
const std::size_t named_sub_size = named_sub.size();
700+
#endif
701+
result = hash_finalize(result, named_sub_size + sub.size());
671702

672703
return result;
673704
}

src/util/irep.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Author: Daniel Kroening, [email protected]
2323
// #define SUB_IS_LIST
2424

2525
#ifdef SUB_IS_LIST
26-
#include <list>
26+
#include <forward_list>
2727
#else
2828
#include <map>
2929
#endif
@@ -160,11 +160,11 @@ class irept
160160
// use std::forward_list or std::vector< unique_ptr<T> > to save
161161
// memory and increase efficiency.
162162

163-
#ifdef SUB_IS_LIST
164-
typedef std::list<std::pair<irep_namet, irept> > named_subt;
165-
#else
163+
#ifdef SUB_IS_LIST
164+
typedef std::forward_list<std::pair<irep_namet, irept>> named_subt;
165+
#else
166166
typedef std::map<irep_namet, irept> named_subt;
167-
#endif
167+
#endif
168168

169169
bool is_nil() const { return id()==ID_nil; }
170170
bool is_not_nil() const { return id()!=ID_nil; }

src/util/irep_hash_container.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,21 @@ void irep_hash_container_baset::pack(
5454
{
5555
// we pack: the irep id, the sub size, the subs, the named-sub size, and
5656
// each of the named subs with their ids
57-
packed.reserve(1 + 1 + sub.size() + 1 + named_sub.size() * 2);
57+
#ifdef SUB_IS_LIST
58+
const std::size_t named_sub_size =
59+
std::distance(named_sub.begin(), named_sub.end());
60+
#else
61+
const std::size_t named_sub_size = named_sub.size();
62+
#endif
63+
packed.reserve(1 + 1 + sub.size() + 1 + named_sub_size * 2);
5864

5965
packed.push_back(irep_id_hash()(irep.id()));
6066

6167
packed.push_back(sub.size());
6268
forall_irep(it, sub)
6369
packed.push_back(number(*it));
6470

65-
packed.push_back(named_sub.size());
71+
packed.push_back(named_sub_size);
6672
for(const auto &sub_irep : named_sub)
6773
{
6874
packed.push_back(irep_id_hash()(sub_irep.first)); // id

src/util/lispirep.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ void irep2lisp(const irept &src, lispexprt &dest)
4646
dest.value="";
4747
dest.type=lispexprt::List;
4848

49-
dest.reserve(2 + 2 * src.get_sub().size() + 2 * src.get_named_sub().size());
49+
#ifdef SUB_IS_LIST
50+
const std::size_t named_sub_size =
51+
std::distance(src.get_named_sub().begin(), src.get_named_sub().end());
52+
#else
53+
const std::size_t named_sub_size = src.get_named_sub().size();
54+
#endif
55+
dest.reserve(2 + 2 * src.get_sub().size() + 2 * named_sub_size);
5056

5157
lispexprt id;
5258
id.type=lispexprt::String;

src/util/merge_irep.cpp

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@ std::size_t to_be_merged_irept::hash() const
2828
result, static_cast<const merged_irept &>(it->second).hash());
2929
}
3030

31-
result=hash_finalize(result, named_sub.size()+sub.size());
31+
#ifdef SUB_IS_LIST
32+
const std::size_t named_sub_size =
33+
std::distance(named_sub.begin(), named_sub.end());
34+
#else
35+
const std::size_t named_sub_size = named_sub.size();
36+
#endif
37+
result = hash_finalize(result, named_sub_size + sub.size());
3238

3339
return result;
3440
}
@@ -45,8 +51,17 @@ bool to_be_merged_irept::operator == (const to_be_merged_irept &other) const
4551

4652
if(sub.size()!=o_sub.size())
4753
return false;
54+
#ifdef SUB_IS_LIST
55+
if(
56+
std::distance(named_sub.begin(), named_sub.end()) !=
57+
std::distance(o_named_sub.begin(), o_named_sub.end()))
58+
{
59+
return false;
60+
}
61+
#else
4862
if(named_sub.size()!=o_named_sub.size())
4963
return false;
64+
#endif
5065

5166
{
5267
irept::subt::const_iterator s_it=sub.begin();
@@ -95,13 +110,19 @@ const merged_irept &merged_irepst::merged(const irept &irep)
95110
const irept::named_subt &src_named_sub=irep.get_named_sub();
96111
irept::named_subt &dest_named_sub=new_irep.get_named_sub();
97112

113+
#ifdef SUB_IS_LIST
114+
irept::named_subt::iterator before = dest_named_sub.before_begin();
115+
#endif
98116
forall_named_irep(it, src_named_sub)
99-
#ifdef SUB_IS_LIST
100-
dest_named_sub.push_back(
101-
std::make_pair(it->first, merged(it->second))); // recursive call
102-
#else
117+
{
118+
#ifdef SUB_IS_LIST
119+
dest_named_sub.emplace_after(
120+
before, it->first, merged(it->second)); // recursive call
121+
++before;
122+
#else
103123
dest_named_sub[it->first]=merged(it->second); // recursive call
104-
#endif
124+
#endif
125+
}
105126

106127
std::pair<to_be_merged_irep_storet::const_iterator, bool> result=
107128
to_be_merged_irep_store.insert(to_be_merged_irept(new_irep));
@@ -140,13 +161,19 @@ const irept &merge_irept::merged(const irept &irep)
140161
const irept::named_subt &src_named_sub=irep.get_named_sub();
141162
irept::named_subt &dest_named_sub=new_irep.get_named_sub();
142163

164+
#ifdef SUB_IS_LIST
165+
irept::named_subt::iterator before = dest_named_sub.before_begin();
166+
#endif
143167
forall_named_irep(it, src_named_sub)
144-
#ifdef SUB_IS_LIST
145-
dest_named_sub.push_back(
146-
std::make_pair(it->first, merged(it->second))); // recursive call
147-
#else
168+
{
169+
#ifdef SUB_IS_LIST
170+
dest_named_sub.emplace_after(
171+
before, it->first, merged(it->second)); // recursive call
172+
++before;
173+
#else
148174
dest_named_sub[it->first]=merged(it->second); // recursive call
149-
#endif
175+
#endif
176+
}
150177

151178
return *irep_store.insert(std::move(new_irep)).first;
152179
}
@@ -177,13 +204,19 @@ const irept &merge_full_irept::merged(const irept &irep)
177204
const irept::named_subt &src_named_sub=irep.get_named_sub();
178205
irept::named_subt &dest_named_sub=new_irep.get_named_sub();
179206

207+
#ifdef SUB_IS_LIST
208+
irept::named_subt::iterator before = dest_named_sub.before_begin();
209+
#endif
180210
forall_named_irep(it, src_named_sub)
181-
#ifdef SUB_IS_LIST
182-
dest_named_sub.push_back(
183-
std::make_pair(it->first, merged(it->second))); // recursive call
184-
#else
211+
{
212+
#ifdef SUB_IS_LIST
213+
dest_named_sub.emplace_after(
214+
before, it->first, merged(it->second)); // recursive call
215+
++before;
216+
#else
185217
dest_named_sub[it->first]=merged(it->second); // recursive call
186-
#endif
218+
#endif
219+
}
187220

188221
return *irep_store.insert(std::move(new_irep)).first;
189222
}

unit/util/irep.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,16 @@ SCENARIO("irept_memory", "[core][utils][irept]")
140140
irep.add("a_new_element", irep2);
141141
REQUIRE(!irept::is_comment("a_new_element"));
142142
REQUIRE(irep.find("a_new_element").id() == "second_irep");
143-
REQUIRE(irep.get_named_sub().size() == 1);
143+
std::size_t named_sub_size =
144+
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
145+
REQUIRE(named_sub_size == 1);
144146

145147
irep.add("#a_comment", irep2);
146148
REQUIRE(irept::is_comment("#a_comment"));
147149
REQUIRE(irep.find("#a_comment").id() == "second_irep");
148-
REQUIRE(irep.get_named_sub().size() == 2);
150+
named_sub_size =
151+
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
152+
REQUIRE(named_sub_size == 2);
149153
REQUIRE(irept::number_of_non_comments(irep.get_named_sub()) == 1);
150154

151155
irept bak(irep);
@@ -160,17 +164,23 @@ SCENARIO("irept_memory", "[core][utils][irept]")
160164

161165
irep.move_to_named_sub("another_entry", irep2);
162166
REQUIRE(irep.get_sub().size() == 1);
163-
REQUIRE(irep.get_named_sub().size() == 2);
167+
named_sub_size =
168+
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
169+
REQUIRE(named_sub_size == 2);
164170

165171
irept irep3;
166172
irep.move_to_named_sub("#a_comment", irep3);
167173
REQUIRE(irep.find("#a_comment").id().empty());
168174
REQUIRE(irep.get_sub().size() == 1);
169-
REQUIRE(irep.get_named_sub().size() == 2);
175+
named_sub_size =
176+
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
177+
REQUIRE(named_sub_size == 2);
170178

171179
irept irep4;
172180
irep.move_to_named_sub("#another_comment", irep4);
173-
REQUIRE(irep.get_named_sub().size() == 3);
181+
named_sub_size =
182+
std::distance(irep.get_named_sub().begin(), irep.get_named_sub().end());
183+
REQUIRE(named_sub_size == 3);
174184
}
175185

176186
THEN("Setting and getting works")

0 commit comments

Comments
 (0)