-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathstore.go
More file actions
132 lines (104 loc) · 3.14 KB
/
Copy pathstore.go
File metadata and controls
132 lines (104 loc) · 3.14 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
package simgo
import (
"math"
)
// Store is a resource for storing objects. The objects are put and retrieved
// from the store in a first-in first-out order.
type Store[T any] struct {
// sim is the reference to the simulation.
sim *Simulation
// gets holds the list of pending get events.
gets []*GetEvent[T]
// puts holds the list of pending put events.
puts []*PutEvent[T]
// items holds the items currently in the store.
items []T
// capacity is the maximum number of items in the store.
capacity int
}
// GetEvent is the event returned from (*Store).Get.
type GetEvent[T any] struct {
// Event is the underlying event.
*Event
// Item holds the item retrieved from the store after the underlying event is
// triggered.
Item T
}
// PutEvent is the returned from (*Store).Put.
type PutEvent[T any] struct {
// Event is the underlying event.
*Event
// item holds the item to be returned to the store.
item T
}
// NewStore creates a store for the given simulation with an unlimited capacity.
func NewStore[T any](sim *Simulation) *Store[T] {
return NewStoreWithCapacity[T](sim, math.MaxInt)
}
// NewStoreWithCapacity crates a store for the given simulation with the given
// capacity.
func NewStoreWithCapacity[T any](sim *Simulation, capacity int) *Store[T] {
if capacity <= 0 {
panic("NewStoreWithCapacity: capacity must be > 0")
}
return &Store[T]{sim: sim, capacity: capacity}
}
// Capacity returns the capacity of the store.
func (store *Store[T]) Capacity() int {
return store.capacity
}
// Available returns the number of items currently in the store.
func (store *Store[T]) Available() int {
return len(store.items)
}
// Get returns an event that is triggered when an item is retrieved from the
// store, which may be immediately.
func (store *Store[T]) Get() *GetEvent[T] {
ev := &GetEvent[T]{Event: store.sim.Event()}
ev.AddHandler(func(*Event) {
// the store has one less item, so check whether any pending puts can be
// triggered.
store.triggerPuts()
})
store.gets = append(store.gets, ev)
store.triggerGets()
return ev
}
// Put returns an event that is triggered when the given item is returned to the
// store, which may be immediately.
func (store *Store[T]) Put(item T) *PutEvent[T] {
ev := &PutEvent[T]{Event: store.sim.Event(), item: item}
ev.AddHandler(func(*Event) {
// the store has one more item, so check whether any pending gets can be
// triggered
store.triggerGets()
})
store.puts = append(store.puts, ev)
store.triggerPuts()
return ev
}
// triggerGets triggers pending get events until the store is empty.
// left in the store.
func (store *Store[T]) triggerGets() {
for len(store.gets) > 0 && len(store.items) > 0 {
get := store.gets[0]
store.gets = store.gets[1:]
if !get.Trigger() {
continue
}
item := store.items[0]
store.items = store.items[1:]
get.Item = item
}
}
// triggerPuts triggers pending put events until the store is full.
func (store *Store[T]) triggerPuts() {
for len(store.puts) > 0 && len(store.items) < store.Capacity() {
put := store.puts[0]
store.puts = store.puts[1:]
if !put.Trigger() {
continue
}
store.items = append(store.items, put.item)
}
}