-
-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathhistory-buffer.gd
More file actions
141 lines (112 loc) · 3.07 KB
/
history-buffer.gd
File metadata and controls
141 lines (112 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
extends RefCounted
class_name _HistoryBuffer
# Maps ticks (int) to arbitrary data, stored in a sliding ring buffer
var _capacity := 64
var _buffer := []
var _previous := []
var _tail := 0
var _head := 0
static func of(capacity: int, data: Dictionary) -> _HistoryBuffer:
var history_buffer := _HistoryBuffer.new(capacity)
for idx in data:
history_buffer.set_at(idx, data[idx])
return history_buffer
func _init(capacity: int = 64):
_capacity = capacity
_buffer.resize(_capacity)
_previous.resize(_capacity)
func duplicate(deep: bool = false) -> _HistoryBuffer:
var buffer := _HistoryBuffer.new(_capacity)
buffer._buffer = _buffer.duplicate(deep)
buffer._previous = _previous.duplicate()
buffer._tail = _tail
buffer._head = _head
return buffer
func push(value: Variant) -> void:
_buffer[_head % _capacity] = value
_previous[_head % _capacity] = _head
_head += 1
_tail += maxi(0, size() - capacity())
func pop() -> Variant:
assert(is_not_empty(), "History buffer is empty!")
var value = _buffer[_tail % _capacity]
_tail += 1
return value
func values() -> Array:
var result := []
for i in range(_tail, _head + 1):
if i == _previous[i % _capacity]:
result.append(_buffer[i % _capacity])
return result
func set_at(at: int, value: Variant) -> void:
# Why does this need so many branches?
if is_empty():
# Buffer is empty, jump to specified index
_tail = at
_head = at
push(value)
elif at < _head - capacity():
# Trying to set something that would wrap back around and overwrite
# current data
return
elif at == _head:
# Simply adding a new item
push(value)
elif at < _head:
_buffer[at % _capacity] = value
# Update prev-buffer
for i in range(at, _head):
if _previous[i % _capacity] == i:
break
_previous[i % _capacity] = at
_tail = mini(_tail, at)
elif at >= _head + _capacity:
# We're leaving all data behind
_tail = at
_head = at
_previous.fill(null)
_buffer.fill(null)
push(value)
elif at >= _head:
# Skipping forward a bit
var previous := _head - 1
while _head < at:
_previous[_head % _capacity] = previous
_head += 1
_tail += maxi(0, size() - _capacity)
push(value)
func has_at(at: int) -> bool:
if is_empty(): return false
if at < _head - capacity(): return false
if at >= _head: return false
return _previous[at % _capacity] == at
func get_at(at: int, default: Variant = null) -> Variant:
if not has_at(at):
return default
return _buffer[at % _capacity]
func has_latest_at(at: int) -> bool:
if is_empty(): return false
if at < _tail: return false
return true
func size() -> int:
return _head - _tail
func capacity() -> int:
return _capacity
func get_earliest_index() -> int:
return _tail
func get_latest_index() -> int:
return _head - 1
func get_latest_index_at(at: int) -> int:
if not has_latest_at(at):
return -1
if at >= _head:
return get_latest_index()
return _previous[at % _capacity]
func get_latest_at(at: int) -> Variant:
return get_at(get_latest_index_at(at))
func clear():
_tail = _head
func is_empty() -> bool:
return size() == 0
func is_not_empty() -> bool:
return not is_empty()