esiaccel 0.2.3.dev80__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esiaccel/CosimBackend.dll +0 -0
- esiaccel/CosimBackend.lib +0 -0
- esiaccel/CosimRpc.dll +0 -0
- esiaccel/CosimRpc.lib +0 -0
- esiaccel/ESICppRuntime.dll +0 -0
- esiaccel/ESICppRuntime.lib +0 -0
- esiaccel/EsiCosimDpiServer.dll +0 -0
- esiaccel/EsiCosimDpiServer.lib +0 -0
- esiaccel/MtiPli.dll +0 -0
- esiaccel/MtiPli.lib +0 -0
- esiaccel/__init__.py +31 -0
- esiaccel/abseil_dll.dll +0 -0
- esiaccel/accelerator.py +134 -0
- esiaccel/cares.dll +0 -0
- esiaccel/cmake/esiaccelConfig.cmake +49 -0
- esiaccel/codegen.py +197 -0
- esiaccel/cosim/Cosim_CycleCount.sv +84 -0
- esiaccel/cosim/Cosim_DpiPkg.sv +85 -0
- esiaccel/cosim/Cosim_Endpoint.sv +218 -0
- esiaccel/cosim/Cosim_Manifest.sv +32 -0
- esiaccel/cosim/driver.cpp +131 -0
- esiaccel/cosim/driver.sv +74 -0
- esiaccel/cosim/questa.py +141 -0
- esiaccel/cosim/simulator.py +383 -0
- esiaccel/cosim/verilator.py +92 -0
- esiaccel/esi-cosim.py +104 -0
- esiaccel/esiCppAccel.cp312-win_amd64.pyd +0 -0
- esiaccel/esiquery.exe +0 -0
- esiaccel/include/esi/Accelerator.h +229 -0
- esiaccel/include/esi/CLI.h +77 -0
- esiaccel/include/esi/Common.h +182 -0
- esiaccel/include/esi/Context.h +82 -0
- esiaccel/include/esi/Design.h +132 -0
- esiaccel/include/esi/Engines.h +124 -0
- esiaccel/include/esi/Logging.h +231 -0
- esiaccel/include/esi/Manifest.h +70 -0
- esiaccel/include/esi/Ports.h +482 -0
- esiaccel/include/esi/Services.h +467 -0
- esiaccel/include/esi/Types.h +334 -0
- esiaccel/include/esi/Utils.h +102 -0
- esiaccel/include/esi/Values.h +313 -0
- esiaccel/include/esi/backends/Cosim.h +78 -0
- esiaccel/include/esi/backends/RpcClient.h +97 -0
- esiaccel/include/esi/backends/RpcServer.h +73 -0
- esiaccel/include/esi/backends/Trace.h +87 -0
- esiaccel/libcrypto-3-x64.dll +0 -0
- esiaccel/libprotobuf.dll +0 -0
- esiaccel/libssl-3-x64.dll +0 -0
- esiaccel/re2.dll +0 -0
- esiaccel/types.py +565 -0
- esiaccel/utils.py +54 -0
- esiaccel/zlib1.dll +0 -0
- esiaccel-0.2.3.dev80.dist-info/METADATA +254 -0
- esiaccel-0.2.3.dev80.dist-info/RECORD +58 -0
- esiaccel-0.2.3.dev80.dist-info/WHEEL +5 -0
- esiaccel-0.2.3.dev80.dist-info/entry_points.txt +4 -0
- esiaccel-0.2.3.dev80.dist-info/licenses/LICENSE +234 -0
- esiaccel-0.2.3.dev80.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
//===- Types.h - ESI type system -------------------------------*- C++ -*-===//
|
|
2
|
+
//
|
|
3
|
+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
4
|
+
// See https://llvm.org/LICENSE.txt for license information.
|
|
5
|
+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
6
|
+
//
|
|
7
|
+
//===----------------------------------------------------------------------===//
|
|
8
|
+
//
|
|
9
|
+
// DO NOT EDIT!
|
|
10
|
+
// This file is distributed as part of an ESI package. The source for this file
|
|
11
|
+
// should always be modified within CIRCT.
|
|
12
|
+
//
|
|
13
|
+
//===----------------------------------------------------------------------===//
|
|
14
|
+
|
|
15
|
+
// NOLINTNEXTLINE(llvm-header-guard)
|
|
16
|
+
#ifndef ESI_TYPES_H
|
|
17
|
+
#define ESI_TYPES_H
|
|
18
|
+
|
|
19
|
+
#include <algorithm>
|
|
20
|
+
#include <any>
|
|
21
|
+
#include <cstdint>
|
|
22
|
+
#include <map>
|
|
23
|
+
#include <span>
|
|
24
|
+
#include <stdexcept>
|
|
25
|
+
#include <string>
|
|
26
|
+
#include <vector>
|
|
27
|
+
|
|
28
|
+
#include "esi/Common.h"
|
|
29
|
+
#include "esi/Values.h" // For BitVector / Int / UInt
|
|
30
|
+
|
|
31
|
+
namespace esi {
|
|
32
|
+
|
|
33
|
+
/// Root class of the ESI type system.
|
|
34
|
+
class Type {
|
|
35
|
+
public:
|
|
36
|
+
using ID = std::string;
|
|
37
|
+
Type(const ID &id) : id(id) {}
|
|
38
|
+
virtual ~Type() = default;
|
|
39
|
+
|
|
40
|
+
ID getID() const { return id; }
|
|
41
|
+
virtual std::ptrdiff_t getBitWidth() const { return -1; }
|
|
42
|
+
|
|
43
|
+
/// Serialize an object to a MutableBitVector (LSB-first stream). The object
|
|
44
|
+
/// should be passed via std::any. Implementations append fields in the order
|
|
45
|
+
/// they are iterated (the first serialized field occupies the
|
|
46
|
+
/// least-significant bits of the result).
|
|
47
|
+
virtual MutableBitVector serialize(const std::any &obj) const {
|
|
48
|
+
throw std::runtime_error("Serialization not implemented for type " + id);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Deserialize from a BitVector stream (LSB-first). Implementations consume
|
|
52
|
+
/// bits from 'data' in-place (via logical right shifts) and return the
|
|
53
|
+
/// reconstructed value. Remaining bits stay in 'data'.
|
|
54
|
+
virtual std::any deserialize(BitVector &data) const {
|
|
55
|
+
throw std::runtime_error("Deserialization not implemented for type " + id);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Deserialize from a MessageData buffer. Maps the MessageData onto a
|
|
59
|
+
// MutableBitVector, and proceeds with regular MutableBitVector
|
|
60
|
+
// deserialization.
|
|
61
|
+
std::any deserialize(const MessageData &data) const {
|
|
62
|
+
auto bv = MutableBitVector(std::vector<uint8_t>(data.getData()));
|
|
63
|
+
return deserialize(bv);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Ensure that a std::any object is valid for this type. Throws
|
|
67
|
+
/// std::runtime_error if the object is not valid.
|
|
68
|
+
virtual void ensureValid(const std::any &obj) const {
|
|
69
|
+
throw std::runtime_error("Validation not implemented for type " + id);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check if a std::any object is valid for this type. Returns an optional
|
|
73
|
+
// error message if the object is not valid, else, std::nullopt.
|
|
74
|
+
std::optional<std::string> isValid(const std::any &obj) const {
|
|
75
|
+
try {
|
|
76
|
+
ensureValid(obj);
|
|
77
|
+
return std::nullopt;
|
|
78
|
+
} catch (const std::runtime_error &e) {
|
|
79
|
+
return e.what();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Dump a textual representation of this type to the provided stream.
|
|
84
|
+
void dump(std::ostream &os, bool oneLine = false) const;
|
|
85
|
+
|
|
86
|
+
// Return a textual representation of this type.
|
|
87
|
+
std::string toString(bool oneLine = false) const;
|
|
88
|
+
|
|
89
|
+
protected:
|
|
90
|
+
ID id;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/// Bundles represent a collection of channels. Services exclusively expose
|
|
94
|
+
/// bundles (sometimes of just one channel). As such, they are the type of
|
|
95
|
+
/// accessible ports on an accelerator, from a host API perspective.
|
|
96
|
+
/// TODO: Add a good description of direction?
|
|
97
|
+
class BundleType : public Type {
|
|
98
|
+
public:
|
|
99
|
+
enum Direction { To, From };
|
|
100
|
+
|
|
101
|
+
using ChannelVector =
|
|
102
|
+
std::vector<std::tuple<std::string, Direction, const Type *>>;
|
|
103
|
+
|
|
104
|
+
BundleType(const ID &id, const ChannelVector &channels)
|
|
105
|
+
: Type(id), channels(channels) {}
|
|
106
|
+
|
|
107
|
+
const ChannelVector &getChannels() const { return channels; }
|
|
108
|
+
std::ptrdiff_t getBitWidth() const override { return -1; };
|
|
109
|
+
|
|
110
|
+
std::pair<const Type *, Direction> findChannel(std::string name) const;
|
|
111
|
+
|
|
112
|
+
protected:
|
|
113
|
+
ChannelVector channels;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/// Channels are the basic communication primitives. They are unidirectional and
|
|
117
|
+
/// carry one values of one type.
|
|
118
|
+
class ChannelType : public Type {
|
|
119
|
+
public:
|
|
120
|
+
using Type::deserialize;
|
|
121
|
+
ChannelType(const ID &id, const Type *inner) : Type(id), inner(inner) {}
|
|
122
|
+
const Type *getInner() const { return inner; }
|
|
123
|
+
std::ptrdiff_t getBitWidth() const override { return inner->getBitWidth(); };
|
|
124
|
+
|
|
125
|
+
void ensureValid(const std::any &obj) const override;
|
|
126
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
127
|
+
std::any deserialize(BitVector &data) const override;
|
|
128
|
+
|
|
129
|
+
private:
|
|
130
|
+
const Type *inner;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/// The "void" type is a special type which can be used to represent no type.
|
|
134
|
+
class VoidType : public Type {
|
|
135
|
+
public:
|
|
136
|
+
using Type::deserialize;
|
|
137
|
+
VoidType(const ID &id) : Type(id) {}
|
|
138
|
+
// 'void' is 1 bit by convention.
|
|
139
|
+
std::ptrdiff_t getBitWidth() const override { return 1; };
|
|
140
|
+
|
|
141
|
+
void ensureValid(const std::any &obj) const override;
|
|
142
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
143
|
+
std::any deserialize(BitVector &data) const override;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/// The "any" type is a special type which can be used to represent any type, as
|
|
147
|
+
/// identified by the type id. Said type id is guaranteed to be present in the
|
|
148
|
+
/// manifest. Importantly, the "any" type id over the wire may not be a string
|
|
149
|
+
/// as it is in software.
|
|
150
|
+
class AnyType : public Type {
|
|
151
|
+
public:
|
|
152
|
+
AnyType(const ID &id) : Type(id) {}
|
|
153
|
+
std::ptrdiff_t getBitWidth() const override { return -1; };
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/// Bit vectors include signed, unsigned, and signless integers.
|
|
157
|
+
class BitVectorType : public Type {
|
|
158
|
+
public:
|
|
159
|
+
BitVectorType(const ID &id, uint64_t width) : Type(id), width(width) {}
|
|
160
|
+
|
|
161
|
+
uint64_t getWidth() const { return width; }
|
|
162
|
+
std::ptrdiff_t getBitWidth() const override { return getWidth(); };
|
|
163
|
+
|
|
164
|
+
private:
|
|
165
|
+
uint64_t width;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/// Bits are just an array of bits. They are not interpreted as a number but are
|
|
169
|
+
/// identified in the manifest as "signless" ints.
|
|
170
|
+
class BitsType : public BitVectorType {
|
|
171
|
+
public:
|
|
172
|
+
using BitVectorType::BitVectorType;
|
|
173
|
+
using Type::deserialize;
|
|
174
|
+
|
|
175
|
+
void ensureValid(const std::any &obj) const override;
|
|
176
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
177
|
+
std::any deserialize(BitVector &data) const override;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/// Integers are bit vectors which may be signed or unsigned and are interpreted
|
|
181
|
+
/// as numbers.
|
|
182
|
+
class IntegerType : public BitVectorType {
|
|
183
|
+
public:
|
|
184
|
+
using BitVectorType::BitVectorType;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/// Signed integer.
|
|
188
|
+
class SIntType : public IntegerType {
|
|
189
|
+
public:
|
|
190
|
+
using IntegerType::IntegerType;
|
|
191
|
+
using Type::deserialize;
|
|
192
|
+
|
|
193
|
+
void ensureValid(const std::any &obj) const override;
|
|
194
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
195
|
+
std::any deserialize(BitVector &data) const override;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/// Unsigned integer.
|
|
199
|
+
class UIntType : public IntegerType {
|
|
200
|
+
public:
|
|
201
|
+
using IntegerType::IntegerType;
|
|
202
|
+
using Type::deserialize;
|
|
203
|
+
|
|
204
|
+
void ensureValid(const std::any &obj) const override;
|
|
205
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
206
|
+
std::any deserialize(BitVector &data) const override;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/// Structs are an ordered collection of fields, each with a name and a type.
|
|
210
|
+
class StructType : public Type {
|
|
211
|
+
public:
|
|
212
|
+
using FieldVector = std::vector<std::pair<std::string, const Type *>>;
|
|
213
|
+
using Type::deserialize;
|
|
214
|
+
|
|
215
|
+
StructType(const ID &id, const FieldVector &fields, bool reverse = true)
|
|
216
|
+
: Type(id), fields(fields), reverse(reverse) {}
|
|
217
|
+
|
|
218
|
+
const FieldVector &getFields() const { return fields; }
|
|
219
|
+
std::ptrdiff_t getBitWidth() const override {
|
|
220
|
+
std::ptrdiff_t size = 0;
|
|
221
|
+
for (auto [name, ty] : getFields()) {
|
|
222
|
+
std::ptrdiff_t fieldSize = ty->getBitWidth();
|
|
223
|
+
if (fieldSize < 0)
|
|
224
|
+
return -1;
|
|
225
|
+
size += fieldSize;
|
|
226
|
+
}
|
|
227
|
+
return size;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
void ensureValid(const std::any &obj) const override;
|
|
231
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
232
|
+
std::any deserialize(BitVector &data) const override;
|
|
233
|
+
|
|
234
|
+
// Returns whether this struct type should be reversed when
|
|
235
|
+
// serializing/deserializing.
|
|
236
|
+
// By default, a truthy value here makes StructType's compatible with system
|
|
237
|
+
// verilog, which has reversed struct field ordering, wrt. C/software struct
|
|
238
|
+
// ordering.
|
|
239
|
+
bool isReverse() const { return reverse; }
|
|
240
|
+
|
|
241
|
+
private:
|
|
242
|
+
FieldVector fields;
|
|
243
|
+
bool reverse;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/// Arrays have a compile time specified (static) size and an element type.
|
|
247
|
+
class ArrayType : public Type {
|
|
248
|
+
public:
|
|
249
|
+
ArrayType(const ID &id, const Type *elementType, uint64_t size,
|
|
250
|
+
bool reverse = true)
|
|
251
|
+
: Type(id), elementType(elementType), size(size), reverse(reverse) {}
|
|
252
|
+
using Type::deserialize;
|
|
253
|
+
|
|
254
|
+
const Type *getElementType() const { return elementType; }
|
|
255
|
+
uint64_t getSize() const { return size; }
|
|
256
|
+
bool isReverse() const { return reverse; }
|
|
257
|
+
std::ptrdiff_t getBitWidth() const override {
|
|
258
|
+
std::ptrdiff_t elementSize = elementType->getBitWidth();
|
|
259
|
+
if (elementSize < 0)
|
|
260
|
+
return -1;
|
|
261
|
+
return elementSize * size;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
void ensureValid(const std::any &obj) const override;
|
|
265
|
+
MutableBitVector serialize(const std::any &obj) const override;
|
|
266
|
+
std::any deserialize(BitVector &data) const override;
|
|
267
|
+
|
|
268
|
+
private:
|
|
269
|
+
const Type *elementType;
|
|
270
|
+
uint64_t size;
|
|
271
|
+
// 'reverse' controls whether array elements are reversed during
|
|
272
|
+
// serialization/deserialization (to match SystemVerilog/Python ordering
|
|
273
|
+
// expectations).
|
|
274
|
+
bool reverse;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/// Windows represent a fixed-size sliding window over a stream of data.
|
|
278
|
+
/// They define an "into" type (the data structure being windowed) and a
|
|
279
|
+
/// "loweredType" (the hardware representation including control signals).
|
|
280
|
+
class WindowType : public Type {
|
|
281
|
+
public:
|
|
282
|
+
/// Field information describing a field within a frame.
|
|
283
|
+
struct Field {
|
|
284
|
+
std::string name;
|
|
285
|
+
uint64_t numItems = 0; // 0 means not specified (use all items)
|
|
286
|
+
uint64_t bulkCountWidth = 0; // 0 means parallel encoding, >0 means serial
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/// Frame information describing which fields are included in a particular
|
|
290
|
+
/// frame.
|
|
291
|
+
struct Frame {
|
|
292
|
+
std::string name;
|
|
293
|
+
std::vector<Field> fields;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
WindowType(const ID &id, const std::string &name, const Type *intoType,
|
|
297
|
+
const Type *loweredType, const std::vector<Frame> &frames)
|
|
298
|
+
: Type(id), name(name), intoType(intoType), loweredType(loweredType),
|
|
299
|
+
frames(frames) {}
|
|
300
|
+
|
|
301
|
+
const std::string &getName() const { return name; }
|
|
302
|
+
const Type *getIntoType() const { return intoType; }
|
|
303
|
+
const Type *getLoweredType() const { return loweredType; }
|
|
304
|
+
const std::vector<Frame> &getFrames() const { return frames; }
|
|
305
|
+
|
|
306
|
+
std::ptrdiff_t getBitWidth() const override {
|
|
307
|
+
return loweredType->getBitWidth();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private:
|
|
311
|
+
std::string name;
|
|
312
|
+
const Type *intoType;
|
|
313
|
+
const Type *loweredType;
|
|
314
|
+
std::vector<Frame> frames;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/// Lists represent variable-length sequences of elements of a single type.
|
|
318
|
+
/// Unlike arrays which have a fixed size, lists can have any length.
|
|
319
|
+
class ListType : public Type {
|
|
320
|
+
public:
|
|
321
|
+
ListType(const ID &id, const Type *elementType)
|
|
322
|
+
: Type(id), elementType(elementType) {}
|
|
323
|
+
|
|
324
|
+
const Type *getElementType() const { return elementType; }
|
|
325
|
+
|
|
326
|
+
std::ptrdiff_t getBitWidth() const override { return -1; }
|
|
327
|
+
|
|
328
|
+
private:
|
|
329
|
+
const Type *elementType;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
} // namespace esi
|
|
333
|
+
|
|
334
|
+
#endif // ESI_TYPES_H
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
//===- Utils.h - ESI runtime utility code -----------------------*- C++ -*-===//
|
|
2
|
+
//
|
|
3
|
+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
4
|
+
// See https://llvm.org/LICENSE.txt for license information.
|
|
5
|
+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
6
|
+
//
|
|
7
|
+
//===----------------------------------------------------------------------===//
|
|
8
|
+
//
|
|
9
|
+
// DO NOT EDIT!
|
|
10
|
+
// This file is distributed as part of an ESI package. The source for this file
|
|
11
|
+
// should always be modified within CIRCT.
|
|
12
|
+
//
|
|
13
|
+
//===----------------------------------------------------------------------===//
|
|
14
|
+
|
|
15
|
+
// NOLINTNEXTLINE(llvm-header-guard)
|
|
16
|
+
#ifndef ESI_UTILS_H
|
|
17
|
+
#define ESI_UTILS_H
|
|
18
|
+
|
|
19
|
+
#include <cstdint>
|
|
20
|
+
#include <functional>
|
|
21
|
+
#include <mutex>
|
|
22
|
+
#include <optional>
|
|
23
|
+
#include <queue>
|
|
24
|
+
#include <string>
|
|
25
|
+
|
|
26
|
+
namespace esi {
|
|
27
|
+
namespace utils {
|
|
28
|
+
// Very basic base64 encoding.
|
|
29
|
+
void encodeBase64(const void *data, size_t size, std::string &out);
|
|
30
|
+
|
|
31
|
+
/// C++'s stdlib doesn't have a hash_combine function. This is a simple one.
|
|
32
|
+
inline size_t hash_combine(size_t h1, size_t h2) {
|
|
33
|
+
return h1 + 0x9e3779b9 + (h2 << 6) + (h2 >> 2);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Thread safe queue. Just wraps std::queue protected with a lock. Long term,
|
|
37
|
+
/// we need to avoid copying data. It has a lot of data copies currently.
|
|
38
|
+
template <typename T>
|
|
39
|
+
class TSQueue {
|
|
40
|
+
using Lock = std::lock_guard<std::mutex>;
|
|
41
|
+
|
|
42
|
+
/// The queue and its mutex.
|
|
43
|
+
mutable std::mutex qM;
|
|
44
|
+
std::queue<T> q;
|
|
45
|
+
|
|
46
|
+
/// A mutex to ensure that only one 'pop' operation is happening at a time. It
|
|
47
|
+
/// is critical that locks be obtained on this and `qM` same order in both pop
|
|
48
|
+
/// methods. This lock should be obtained first since one of the pop methods
|
|
49
|
+
/// must unlock `qM` then relock it.
|
|
50
|
+
std::mutex popM;
|
|
51
|
+
|
|
52
|
+
public:
|
|
53
|
+
/// Push onto the queue.
|
|
54
|
+
template <typename... E>
|
|
55
|
+
void push(E... t) {
|
|
56
|
+
Lock l(qM);
|
|
57
|
+
q.emplace(t...);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Pop something off the queue but return nullopt if the queue is empty. Why
|
|
61
|
+
/// doesn't std::queue have anything like this?
|
|
62
|
+
std::optional<T> pop() {
|
|
63
|
+
Lock pl(popM);
|
|
64
|
+
Lock ql(qM);
|
|
65
|
+
if (q.size() == 0)
|
|
66
|
+
return std::nullopt;
|
|
67
|
+
auto t = q.front();
|
|
68
|
+
q.pop();
|
|
69
|
+
return t;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Call the callback for the front of the queue (if anything is there). Only
|
|
73
|
+
/// pop it off the queue if the callback returns true.
|
|
74
|
+
void pop(std::function<bool(const T &)> callback) {
|
|
75
|
+
// Since we need to unlock the mutex to call the callback, the queue
|
|
76
|
+
// could be pushed on to and its memory layout could thusly change,
|
|
77
|
+
// invalidating the reference returned by `.front()`. The easy solution here
|
|
78
|
+
// is to copy the data. TODO: Avoid copying the data.
|
|
79
|
+
Lock pl(popM);
|
|
80
|
+
T t;
|
|
81
|
+
{
|
|
82
|
+
Lock l(qM);
|
|
83
|
+
if (q.size() == 0)
|
|
84
|
+
return;
|
|
85
|
+
t = q.front();
|
|
86
|
+
}
|
|
87
|
+
if (callback(t)) {
|
|
88
|
+
Lock l(qM);
|
|
89
|
+
q.pop();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Is the queue empty?
|
|
94
|
+
bool empty() const {
|
|
95
|
+
Lock l(qM);
|
|
96
|
+
return q.empty();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
} // namespace utils
|
|
100
|
+
} // namespace esi
|
|
101
|
+
|
|
102
|
+
#endif // ESI_UTILS_H
|