Skip to content

Commit 4d0c932

Browse files
committed
Change erase() method of the sharing map to require that the given key exists
Previously when sharing_map.erase(key) was called, two traversals of the path to the leaf to erase were done. One to check whether the key was in the map, and if it was, a second one to copy and detach the nodes on the path to the leaf to erase. This commit changes erase() to require that the given key exists in the map. This simplifies the implementation and avoids two traversals of the path to the leaf to erase when it is known that the key exists. If it is not known whether the key exists, sharing_map.has_key(key) should be explicitely called first.
1 parent 5f68f70 commit 4d0c932

File tree

3 files changed

+25
-75
lines changed

3 files changed

+25
-75
lines changed

src/goto-symex/symex_dead.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ void goto_symext::symex_dead(statet &state)
2828
// information is not local to a path, but removing it from the propagation
2929
// map and value-set is safe as 1) it is local to a path and 2) this instance
3030
// can no longer appear
31-
state.value_set.values.erase(l1_identifier);
31+
32+
if (state.value_set.values.has_key(l1_identifier)) {
33+
state.value_set.values.erase(l1_identifier);
34+
}
35+
3236
state.propagation.erase(l1_identifier);
3337
// Remove from the local L2 renaming map; this means any reads from the dead
3438
// identifier will use generation 0 (e.g. x!N@M#0, where N and M are positive

src/util/sharing_map.h

Lines changed: 10 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,6 @@ Author: Daniel Poetzl
157157
/// For this to work, the type of the values stored in the map needs to have a
158158
/// defined equality operator (operator==).
159159
///
160-
/// Several methods take a hint indicating whether the element is known not to
161-
/// be in the map (`false`), known to be in the map (`true`), or it is unknown
162-
/// whether the element is in the map (`unknown`). The value `unknown` is always
163-
/// valid. When `true` or `false` are given they need to be accurate, otherwise
164-
/// the behavior is undefined. A correct hint can prevent the need to follow a
165-
/// path from the root to a key-value pair twice (e.g., once for checking that
166-
/// it exists, and second for copying nodes).
167-
///
168160
/// In the descriptions of the methods of the sharing map we also give the
169161
/// complexity of the operations. We use the following symbols:
170162
/// - N: number of key-value pairs in the map
@@ -221,31 +213,14 @@ class sharing_mapt
221213
public:
222214
// interface
223215

224-
/// Erase element
216+
/// Erase element, element must exist in map
225217
///
226218
/// Complexity:
227219
/// - Worst case: O(H * S + M)
228220
/// - Best case: O(H)
229221
///
230222
/// \param k: The key of the element to erase
231-
/// \param key_exists: Hint to indicate whether the element is known to exist
232-
/// (possible values `unknown` or` true`)
233-
size_type erase(const key_type &k, const tvt &key_exists = tvt::unknown());
234-
235-
/// Erase all elements
236-
///
237-
/// Complexity:
238-
/// - Worst case: O(K * (H * S + M))
239-
/// - Best case: O(K * H)
240-
///
241-
/// \param ks: The keys of the element to erase
242-
/// \param key_exists: Hint to indicate whether the elements are known to
243-
/// exist (possible values `unknown` or `true`). Applies to all elements
244-
/// (i.e., have to use `unknown` if for at least one element it is not known
245-
/// whether it exists)
246-
size_type erase_all(
247-
const keyst &ks,
248-
const tvt &key_exists = tvt::unknown()); // applies to all keys
223+
void erase(const key_type &k);
249224

250225
/// Insert element, element must not exist in map
251226
///
@@ -871,18 +846,9 @@ SHARING_MAPT2(const, innert *)::get_container_node(const key_type &k) const
871846
return ip;
872847
}
873848

874-
SHARING_MAPT2(, size_type)::erase(const key_type &k, const tvt &key_exists)
875-
{
876-
SM_ASSERT(!key_exists.is_false());
877-
SM_ASSERT(!key_exists.is_true() || has_key(k));
878-
879-
// check if key exists
880-
if(key_exists.is_unknown() && !has_key(k))
881-
return 0;
882-
849+
SHARING_MAPT(void)::erase(const key_type &k) {
883850
innert *del = nullptr;
884851
std::size_t del_bit = 0;
885-
std::size_t del_level = 0;
886852

887853
std::size_t key = hash()(k);
888854
innert *ip = ↦
@@ -897,52 +863,26 @@ SHARING_MAPT2(, size_type)::erase(const key_type &k, const tvt &key_exists)
897863
{
898864
del = ip;
899865
del_bit=bit;
900-
del_level = i;
901866
}
902867

903868
ip = ip->add_child(bit);
904869

905870
key >>= chunk;
906871
}
907872

873+
PRECONDITION(!ip->empty());
908874
const leaf_listt &ll = as_const(ip)->get_container();
875+
PRECONDITION(!ll.empty());
909876

910877
// forward list has one element
911-
if(!ll.empty() && std::next(ll.begin()) == ll.end())
912-
{
913-
if(del_level < steps - 1)
914-
{
915-
del->remove_child(del_bit);
916-
}
917-
else
918-
{
919-
SM_ASSERT(del_level == steps - 1);
920-
del->remove_child(del_bit);
921-
}
922-
923-
num--;
924-
return 1;
878+
if (std::next(ll.begin()) == ll.end()) {
879+
PRECONDITION(equalT()(ll.front().get_key(), k));
880+
del->remove_child(del_bit);
881+
} else {
882+
ip->remove_leaf(k);
925883
}
926884

927-
SM_ASSERT(!ll.empty());
928-
929-
ip->remove_leaf(k);
930885
num--;
931-
932-
return 1;
933-
}
934-
935-
SHARING_MAPT2(, size_type)
936-
::erase_all(const keyst &ks, const tvt &key_exists)
937-
{
938-
size_type cnt = 0;
939-
940-
for(const key_type &k : ks)
941-
{
942-
cnt+=erase(k, key_exists);
943-
}
944-
945-
return cnt;
946886
}
947887

948888
SHARING_MAPT4(valueU, void)

unit/util/sharing_map.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,12 @@ TEST_CASE("Sharing map interface", "[core][util]")
193193
sm.insert("i", "0");
194194
sm.insert("j", "1");
195195

196-
REQUIRE(sm.erase("k") == 0);
197196
REQUIRE(sm.size() == 2);
198197

199-
REQUIRE(sm.erase("i") == 1);
198+
sm.erase("i");
200199
REQUIRE(!sm.has_key("i"));
201200

202-
REQUIRE(sm.erase("j") == 1);
201+
sm.erase("j");
203202
REQUIRE(!sm.has_key("j"));
204203

205204
sm.insert("i", "0");
@@ -232,7 +231,7 @@ TEST_CASE("Sharing map copying", "[core][util]")
232231

233232
sharing_map_standardt sm2(sm1);
234233

235-
REQUIRE(sm2.erase("i") == 1);
234+
sm2.erase("i");
236235
REQUIRE(!sm2.has_key("i"));
237236
REQUIRE(sm1.has_key("i"));
238237

@@ -510,3 +509,10 @@ TEST_CASE("Sharing map insert existing", "[.]")
510509

511510
sm.insert("i", "4");
512511
}
512+
513+
TEST_CASE("Sharing map erase non-existing", "[.]") {
514+
sharing_map_standardt sm;
515+
fill(sm);
516+
517+
sm.erase("x");
518+
}

0 commit comments

Comments
 (0)