Skip to content

Commit 854f948

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 1893fdb commit 854f948

File tree

7 files changed

+154
-39
lines changed

7 files changed

+154
-39
lines changed

Diff for: src/util/format_expr.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Author: Daniel Kroening, [email protected]
2727
#include "string2int.h"
2828
#include "string_utils.h"
2929

30+
#include <map>
3031
#include <ostream>
3132
#include <stack>
3233

Diff for: src/util/irep.cpp

+51-9
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ void irept::nonrecursive_destructor(dt *old_data)
153153
if(d->ref_count==0)
154154
{
155155
stack.reserve(stack.size()+
156-
d->named_sub.size()+
157-
d->comments.size()+
156+
std::distance(d->named_sub.begin(), d->named_sub.end()) +
157+
std::distance(d->comments.begin(), d->comments.end()) +
158158
d->sub.size());
159159

160160
for(named_subt::iterator
@@ -275,7 +275,11 @@ void irept::remove(const irep_namet &name)
275275
named_subt::iterator it=named_subt_lower_bound(s, name);
276276

277277
if(it!=s.end() && it->first==name)
278-
s.erase(it);
278+
{
279+
named_subt::iterator before = s.before_begin();
280+
while(std::next(before) != it) ++before;
281+
s.erase_after(before);
282+
}
279283
#else
280284
s.erase(name);
281285
#endif
@@ -312,7 +316,11 @@ irept &irept::add(const irep_namet &name)
312316

313317
if(it==s.end() ||
314318
it->first!=name)
315-
it=s.insert(it, std::make_pair(name, irept()));
319+
{
320+
named_subt::iterator before = s.before_begin();
321+
while(std::next(before) != it) ++before;
322+
it = s.emplace_after(before, name, irept());
323+
}
316324

317325
return it->second;
318326
#else
@@ -330,7 +338,11 @@ irept &irept::add(const irep_namet &name, const irept &irep)
330338

331339
if(it==s.end() ||
332340
it->first!=name)
333-
it=s.insert(it, std::make_pair(name, irep));
341+
{
342+
named_subt::iterator before = s.before_begin();
343+
while(std::next(before) != it) ++before;
344+
it = s.emplace_after(before, name, irep);
345+
}
334346
else
335347
it->second=irep;
336348

@@ -393,10 +405,20 @@ bool irept::full_eq(const irept &other) const
393405
const irept::named_subt &i1_comments=get_comments();
394406
const irept::named_subt &i2_comments=other.get_comments();
395407

408+
#ifdef SUB_IS_LIST
409+
if(
410+
i1_sub.size() != i2_sub.size() ||
411+
std::distance(i1_named_sub.begin(), i1_named_sub.end()) !=
412+
std::distance(i2_named_sub.begin(), i2_named_sub.end()) ||
413+
std::distance(i1_comments.begin(), i1_comments.end()) !=
414+
std::distance(i2_comments.begin(), i2_comments.end()))
415+
return false;
416+
#else
396417
if(i1_sub.size()!=i2_sub.size() ||
397418
i1_named_sub.size()!=i2_named_sub.size() ||
398419
i1_comments.size()!=i2_comments.size())
399420
return false;
421+
#endif
400422

401423
for(std::size_t i=0; i<i1_sub.size(); i++)
402424
if(!i1_sub[i].full_eq(i2_sub[i]))
@@ -527,8 +549,15 @@ int irept::compare(const irept &i) const
527549
"Unequal lengths will return before this");
528550
}
529551

552+
#ifdef SUB_IS_LIST
553+
const named_subt::size_type n_size =
554+
std::distance(get_named_sub().begin(), get_named_sub().end());
555+
const named_subt::size_type i_n_size =
556+
std::distance(i.get_named_sub().begin(), i.get_named_sub().end());
557+
#else
530558
const named_subt::size_type n_size=get_named_sub().size(),
531559
i_n_size=i.get_named_sub().size();
560+
#endif
532561
if(n_size<i_n_size)
533562
return -1;
534563
if(n_size>i_n_size)
@@ -591,7 +620,13 @@ std::size_t irept::hash() const
591620
result=hash_combine(result, it->second.hash());
592621
}
593622

594-
result=hash_finalize(result, named_sub.size()+sub.size());
623+
#ifdef SUB_IS_LIST
624+
const std::size_t named_sub_size =
625+
std::distance(named_sub.begin(), named_sub.end());
626+
#else
627+
const std::size_t named_sub_size = named_sub.size();
628+
#endif
629+
result = hash_finalize(result, named_sub_size + sub.size());
595630

596631
#ifdef HASH_CODE
597632
read().hash_code=result;
@@ -624,9 +659,16 @@ std::size_t irept::full_hash() const
624659
result=hash_combine(result, it->second.full_hash());
625660
}
626661

627-
result=hash_finalize(
628-
result,
629-
named_sub.size()+sub.size()+comments.size());
662+
#ifdef SUB_IS_LIST
663+
const std::size_t named_sub_size =
664+
std::distance(named_sub.begin(), named_sub.end());
665+
const std::size_t comments_size =
666+
std::distance(comments.begin(), comments.end());
667+
#else
668+
const std::size_t named_sub_size = named_sub.size();
669+
const std::size_t comments_size = comments.size();
670+
#endif
671+
result = hash_finalize(result, named_sub_size + sub.size() + comments_size);
630672

631673
return result;
632674
}

Diff for: src/util/irep.h

+2-2
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
@@ -164,7 +164,7 @@ class irept
164164
// memory and increase efficiency.
165165

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

Diff for: src/util/irep_hash_container.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,24 @@ void irep_hash_container_baset::pack(
5151
const irept::named_subt &named_sub=irep.get_named_sub();
5252
const irept::named_subt &comments=irep.get_comments();
5353

54-
packed.reserve(
55-
1+1+sub.size()+named_sub.size()*2+
56-
(full?comments.size()*2:0));
54+
#ifdef SUB_IS_LIST
55+
const std::size_t named_sub_size =
56+
std::distance(named_sub.begin(), named_sub.end());
57+
const std::size_t comments_size = full ?
58+
std::distance(comments.begin(), comments.end()) : 0;
59+
#else
60+
const std::size_t named_sub_size = named_sub.size();
61+
const std::size_t comments_size = full ? comments.size() : 0;
62+
#endif
63+
packed.reserve(1 + 1 + sub.size() + named_sub_size * 2 + comments_size * 2);
5764

5865
packed.push_back(irep_id_hash()(irep.id()));
5966

6067
packed.push_back(sub.size());
6168
forall_irep(it, sub)
6269
packed.push_back(number(*it));
6370

64-
packed.push_back(named_sub.size());
71+
packed.push_back(named_sub_size);
6572
forall_named_irep(it, named_sub)
6673
{
6774
packed.push_back(irep_id_hash()(it->first)); // id
@@ -70,7 +77,7 @@ void irep_hash_container_baset::pack(
7077

7178
if(full)
7279
{
73-
packed.push_back(comments.size());
80+
packed.push_back(comments_size);
7481
forall_named_irep(it, comments)
7582
{
7683
packed.push_back(irep_id_hash()(it->first)); // id

Diff for: src/util/lispirep.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,17 @@ 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()
50-
+2*src.get_named_sub().size()
51-
+2*src.get_comments().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+
const std::size_t comments_size =
53+
std::distance(src.get_comments().begin(), src.get_comments().end());
54+
#else
55+
const std::size_t named_sub_size = src.get_named_sub().size();
56+
const std::size_t comments_size = src.get_comments().size();
57+
#endif
58+
dest.reserve(
59+
2 + 2 * src.get_sub().size() + 2 * named_sub_size + 2 * comments_size);
5260

5361
lispexprt id;
5462
id.type=lispexprt::String;

Diff for: src/util/merge_irep.cpp

+56-13
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
}
@@ -44,9 +50,16 @@ bool to_be_merged_irept::operator == (const to_be_merged_irept &other) const
4450
const irept::named_subt &o_named_sub=other.get_named_sub();
4551

4652
if(sub.size()!=o_sub.size())
47-
return true;
53+
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+
return false;
59+
#else
4860
if(named_sub.size()!=o_named_sub.size())
49-
return true;
61+
return false;
62+
#endif
5063

5164
{
5265
irept::subt::const_iterator s_it=sub.begin();
@@ -95,13 +108,19 @@ const merged_irept &merged_irepst::merged(const irept &irep)
95108
const irept::named_subt &src_named_sub=irep.get_named_sub();
96109
irept::named_subt &dest_named_sub=new_irep.get_named_sub();
97110

111+
#ifdef SUB_IS_LIST
112+
irept::named_subt::iterator before = dest_named_sub.before_begin();
113+
#endif
98114
forall_named_irep(it, src_named_sub)
115+
{
99116
#ifdef SUB_IS_LIST
100-
dest_named_sub.push_back(
101-
std::make_pair(it->first, merged(it->second))); // recursive call
117+
dest_named_sub.emplace_after(
118+
before, it->first, merged(it->second)); // recursive call
119+
++before;
102120
#else
103121
dest_named_sub[it->first]=merged(it->second); // recursive call
104122
#endif
123+
}
105124

106125
std::pair<to_be_merged_irep_storet::const_iterator, bool> result=
107126
to_be_merged_irep_store.insert(to_be_merged_irept(new_irep));
@@ -140,24 +159,36 @@ const irept &merge_irept::merged(const irept &irep)
140159
const irept::named_subt &src_named_sub=irep.get_named_sub();
141160
irept::named_subt &dest_named_sub=new_irep.get_named_sub();
142161

162+
#ifdef SUB_IS_LIST
163+
irept::named_subt::iterator before = dest_named_sub.before_begin();
164+
#endif
143165
forall_named_irep(it, src_named_sub)
166+
{
144167
#ifdef SUB_IS_LIST
145-
dest_named_sub.push_back(
146-
std::make_pair(it->first, merged(it->second))); // recursive call
168+
dest_named_sub.emplace_after(
169+
before, it->first, merged(it->second)); // recursive call
170+
++before;
147171
#else
148172
dest_named_sub[it->first]=merged(it->second); // recursive call
149173
#endif
174+
}
150175

151176
const irept::named_subt &src_comments=irep.get_comments();
152177
irept::named_subt &dest_comments=new_irep.get_comments();
153178

179+
#ifdef SUB_IS_LIST
180+
before = dest_comments.before_begin();
181+
#endif
154182
forall_named_irep(it, src_comments)
183+
{
155184
#ifdef SUB_IS_LIST
156-
dest_comments.push_back(
157-
std::make_pair(it->first, merged(it->second))); // recursive call
185+
dest_comments.emplace_after(
186+
before, it->first, merged(it->second)); // recursive call
187+
++before;
158188
#else
159189
dest_comments[it->first]=merged(it->second); // recursive call
160190
#endif
191+
}
161192

162193
return *irep_store.insert(new_irep).first;
163194
}
@@ -188,24 +219,36 @@ const irept &merge_full_irept::merged(const irept &irep)
188219
const irept::named_subt &src_named_sub=irep.get_named_sub();
189220
irept::named_subt &dest_named_sub=new_irep.get_named_sub();
190221

222+
#ifdef SUB_IS_LIST
223+
irept::named_subt::iterator before = dest_named_sub.before_begin();
224+
#endif
191225
forall_named_irep(it, src_named_sub)
226+
{
192227
#ifdef SUB_IS_LIST
193-
dest_named_sub.push_back(
194-
std::make_pair(it->first, merged(it->second))); // recursive call
228+
dest_named_sub.emplace_after(
229+
before, it->first, merged(it->second)); // recursive call
230+
++before;
195231
#else
196232
dest_named_sub[it->first]=merged(it->second); // recursive call
197233
#endif
234+
}
198235

199236
const irept::named_subt &src_comments=irep.get_comments();
200237
irept::named_subt &dest_comments=new_irep.get_comments();
201238

239+
#ifdef SUB_IS_LIST
240+
before = dest_comments.before_begin();
241+
#endif
202242
forall_named_irep(it, src_comments)
243+
{
203244
#ifdef SUB_IS_LIST
204-
dest_comments.push_back(
205-
std::make_pair(it->first, merged(it->second))); // recursive call
245+
dest_comments.emplace_after(
246+
before, it->first, merged(it->second)); // recursive call
247+
++before;
206248
#else
207249
dest_comments[it->first]=merged(it->second); // recursive call
208250
#endif
251+
}
209252

210253
return *irep_store.insert(new_irep).first;
211254
}

Diff for: unit/util/irep.cpp

+21-7
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,15 @@ SCENARIO("irept_memory", "[core][utils][irept]")
141141
irept irep2("second_irep");
142142
irep.add("a_new_element", irep2);
143143
REQUIRE(irep.find("a_new_element").id() == "second_irep");
144-
REQUIRE(irep.get_named_sub().size() == 1);
144+
std::size_t named_sub_size = std::distance(
145+
irep.get_named_sub().begin(), irep.get_named_sub().end());
146+
REQUIRE(named_sub_size == 1);
145147

146148
irep.add("#a_comment", irep2);
147149
REQUIRE(irep.find("#a_comment").id() == "second_irep");
148-
REQUIRE(irep.get_comments().size() == 1);
150+
std::size_t comments_size =
151+
std::distance(irep.get_comments().begin(), irep.get_comments().end());
152+
REQUIRE(comments_size == 1);
149153

150154
irept bak(irep);
151155
irep.remove("no_such_id");
@@ -159,19 +163,29 @@ SCENARIO("irept_memory", "[core][utils][irept]")
159163

160164
irep.move_to_named_sub("another_entry", irep2);
161165
REQUIRE(irep.get_sub().size() == 1);
162-
REQUIRE(irep.get_named_sub().size() == 1);
163-
REQUIRE(irep.get_comments().size() == 1);
166+
named_sub_size = std::distance(
167+
irep.get_named_sub().begin(), irep.get_named_sub().end());
168+
REQUIRE(named_sub_size == 1);
169+
comments_size =
170+
std::distance(irep.get_comments().begin(), irep.get_comments().end());
171+
REQUIRE(comments_size == 1);
164172

165173
irept irep3;
166174
irep.move_to_named_sub("#a_comment", irep3);
167175
REQUIRE(irep.find("#a_comment").id().empty());
168176
REQUIRE(irep.get_sub().size() == 1);
169-
REQUIRE(irep.get_named_sub().size() == 1);
170-
REQUIRE(irep.get_comments().size() == 1);
177+
named_sub_size = std::distance(
178+
irep.get_named_sub().begin(), irep.get_named_sub().end());
179+
REQUIRE(named_sub_size == 1);
180+
comments_size =
181+
std::distance(irep.get_comments().begin(), irep.get_comments().end());
182+
REQUIRE(comments_size == 1);
171183

172184
irept irep4;
173185
irep.move_to_named_sub("#another_comment", irep4);
174-
REQUIRE(irep.get_comments().size() == 2);
186+
comments_size =
187+
std::distance(irep.get_comments().begin(), irep.get_comments().end());
188+
REQUIRE(comments_size == 2);
175189
}
176190

177191
THEN("Setting and getting works")

0 commit comments

Comments
 (0)