Skip to content

Commit

Permalink
Make compact_map more robust against infinite loops
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafaquraish committed Apr 28, 2024
1 parent 403a281 commit 7e79a40
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 3 deletions.
1 change: 1 addition & 0 deletions compiler/ast/nodes.oc
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ struct Loop {
struct Cast {
lhs: &AST
to: &Type
parsed_to: &Type
}

struct FormatString {
Expand Down
2 changes: 1 addition & 1 deletion compiler/lsp/finder.oc
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def Finder::find_in_expression(&this, node: &AST): bool {
}
Cast => {
if .find_in_expression(node.u.cast.lhs) return true
return .find_in_type(node.u.cast.to)
return .find_in_type(node.u.cast.parsed_to)
}
SizeOf => return .find_in_type(node.u.size_of_type)
If => {
Expand Down
1 change: 1 addition & 0 deletions compiler/parser.oc
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ def Parser::parse_cast(&this, end_type: TokenType): &AST {
let op = AST::new(Cast, lhs.span.join(type_node.span))
op.u.cast.lhs = lhs
op.u.cast.to = type_node
op.u.cast.parsed_to = type_node
lhs = op
}
return lhs
Expand Down
24 changes: 22 additions & 2 deletions std/compact_map.oc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct Map<K, V> {
items: &Vector<Item<K, V>>
indices: &i32
capacity: u32
num_tombstones: u32
}

def Map::new(capacity: u32 = 16): &Map<K, V> {
Expand All @@ -31,10 +32,12 @@ def Map::new(capacity: u32 = 16): &Map<K, V> {
map.items = items
map.indices = indices
map.capacity = capacity
map.num_tombstones = 0
return map
}

def Map::free(&this) {
if not this? return
mem::free(.indices)
.items.free()
mem::free(this)
Expand All @@ -46,7 +49,9 @@ def Map::get_index(&this, key: K, hash: u32): u32 {
let i = j

let first_deleted = -1
while .indices[i] != INDEX_FREE {
let limit = .capacity * 2
while .indices[i] != INDEX_FREE and limit > 0 {
limit--
if .indices[i] == INDEX_DELETED {
if first_deleted < 0 {
first_deleted = i as i32
Expand All @@ -61,6 +66,11 @@ def Map::get_index(&this, key: K, hash: u32): u32 {
i = j % .capacity
perturb = perturb >> 5
}

if limit == 0 {
assert false, "Map::get_index() failed to find an empty slot"
}

if first_deleted < 0 {
return i
}
Expand Down Expand Up @@ -94,6 +104,12 @@ def Map::remove(&this, key: K) {
.indices[index] = INDEX_DELETED
.items.data[item_index] = last_item
.items.pop()
.num_tombstones += 1

// Resize if the number of tombstones is too high
if .num_tombstones + .items.size >= .capacity {
.resize(.capacity * 2)
}
}

def Map::resize(&this, new_capacity: u32) {
Expand All @@ -111,6 +127,7 @@ def Map::resize(&this, new_capacity: u32) {
.indices[index] = i as i32
}
}
.num_tombstones = 0
}

[operator "[]="]
Expand All @@ -125,6 +142,9 @@ def Map::insert(&this, key: K, value: V) {
.resize(.capacity * 2)
}
} else {
if .indices[index] == INDEX_DELETED {
.num_tombstones -= 1
}
let item_index = .indices[index] as u32
.items.data[item_index].value = value // Should be safe
}
Expand Down Expand Up @@ -203,4 +223,4 @@ struct ValueIterator<K, V> {
}
def ValueIterator::has_value(&this): bool => .iter.has_value()
def ValueIterator::next(&this) { .iter.next() }
def ValueIterator::cur(&this): V => .iter.cur().value
def ValueIterator::cur(&this): V => .iter.cur().value

0 comments on commit 7e79a40

Please sign in to comment.