22#ifndef ESI_TYPED_PORTS_H
23#define ESI_TYPED_PORTS_H
47 using std::runtime_error::runtime_error;
57 t = alias->getInnerType();
72 return {(bv->getWidth() + 7) / 8, bv->getWidth()};
80 if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
82 std::vector<uint8_t> buf(wi.
bytes, 0);
83 std::memcpy(buf.data(), &data, std::min(wi.
bytes,
sizeof(T)));
86 }
else if constexpr (std::is_base_of_v<SegmentedMessageData, T>) {
87 return data.toMessageData();
89 return MessageData(
reinterpret_cast<const uint8_t *
>(&data),
sizeof(T));
98 if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
103 std::memcpy(&val, msg.
getBytes(), std::min(wi.
bytes,
sizeof(T)));
105 if constexpr (std::is_signed_v<T>) {
107 size_t signByte = signBit / 8;
108 uint8_t signMask = uint8_t(1) << (signBit % 8);
109 if (signByte < wi.
bytes && (msg.
getBytes()[signByte] & signMask)) {
112 val |=
static_cast<T
>(~T(0)) << wi.
bitWidth;
125template <
typename T,
typename =
void>
130 : std::is_convertible<decltype(T::_ESI_ID), std::string_view> {};
150 if constexpr (has_esi_id_v<T>) {
152 if (std::string_view(portType->
getID()) != T::_ESI_ID)
154 "ESI type mismatch: C++ type has _ESI_ID '" +
155 std::string(T::_ESI_ID) +
"' but port type is '" +
157 }
else if constexpr (std::is_void_v<T>) {
158 if (!
dynamic_cast<const VoidType *
>(portType))
160 "void, but port type is '" +
163 }
else if constexpr (std::is_same_v<T, bool>) {
165 auto *bits =
dynamic_cast<const BitsType *
>(portType);
166 if (!bits || bits->getWidth() > 1)
168 "ESI type mismatch: expected BitsType with width <= 1 for "
169 "bool, but port type is '" +
171 }
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
172 auto *sint =
dynamic_cast<const SIntType *
>(portType);
175 "ESI type mismatch: expected SIntType for signed integer, "
176 "but port type is '" +
178 if (sint->getWidth() >
sizeof(T) * 8)
180 "ESI type mismatch: SIntType width " +
181 std::to_string(sint->getWidth()) +
" does not fit in " +
182 std::to_string(
sizeof(T) * 8) +
"-bit signed integer");
184 if (
sizeof(T) > 1 && sint->getWidth() <= (
sizeof(T) / 2) * 8)
186 std::to_string(sint->getWidth()) +
187 " should use a smaller C++ type than " +
188 std::to_string(
sizeof(T) * 8) +
"-bit");
189 }
else if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
191 auto *uintPort =
dynamic_cast<const UIntType *
>(portType);
192 auto *bits =
dynamic_cast<const BitsType *
>(portType);
193 if (!uintPort && !bits)
195 "ESI type mismatch: expected UIntType or BitsType for unsigned "
196 "integer, but port type is '" +
198 uint64_t width = uintPort ? uintPort->getWidth() : bits->getWidth();
199 if (width >
sizeof(T) * 8)
201 "ESI type mismatch: bit width " + std::to_string(width) +
202 " does not fit in " + std::to_string(
sizeof(T) * 8) +
203 "-bit unsigned integer");
205 if (
sizeof(T) > 1 && width <= (
sizeof(T) / 2) * 8)
207 std::to_string(width) +
208 " should use a smaller C++ type than " +
209 std::to_string(
sizeof(T) * 8) +
"-bit");
212 std::string(
"Cannot verify type compatibility for C++ type '") +
213 typeid(T).name() +
"' against ESI port type '" +
226template <
typename T,
bool SkipTypeCheck = false>
246 void write(std::unique_ptr<T> &data) {
248 throw std::runtime_error(
"TypedWritePort::write: null unique_ptr");
249 if constexpr (std::is_base_of_v<SegmentedMessageData, T>) {
328 void connect(std::function<
bool(
const T &)> callback,
336 [cb = std::move(callback), wb](
MessageData data) ->
bool {
337 return cb(fromMessageData<T>(data, wb));
345 return fromMessageData<T>(outData,
wireInfo_);
351 return std::async(std::launch::deferred,
352 [f = std::move(innerFuture), wb]()
mutable -> T {
354 return fromMessageData<T>(data, wb);
390 [cb = std::move(callback)](
MessageData) ->
bool {
return cb(); }, opts);
401 std::launch::deferred,
402 [f = std::move(innerFuture)]()
mutable ->
void { f.get(); });
423template <
typename ArgT,
typename ResultT,
bool SkipTypeCheck = false>
433 "TypedFunction: null Function pointer (getAs failed or wrong type)");
434 if constexpr (!SkipTypeCheck) {
444 std::future<ResultT>
call(
const ArgT &arg) {
447 return std::async(std::launch::deferred,
448 [fut = std::move(f), rwb]()
mutable -> ResultT {
450 return fromMessageData<ResultT>(data, rwb);
464template <
typename ResultT,
bool SkipTypeCheck>
473 "TypedFunction: null Function pointer (getAs failed or wrong type)");
474 if constexpr (!SkipTypeCheck) {
486 return std::async(std::launch::deferred,
487 [fut = std::move(f), resType]()
mutable -> ResultT {
489 return fromMessageData<ResultT>(data, resType);
501template <
typename ArgT,
bool SkipTypeCheck>
510 "TypedFunction: null Function pointer (getAs failed or wrong type)");
511 if constexpr (!SkipTypeCheck) {
520 std::future<void>
call(
const ArgT &arg) {
522 return std::async(std::launch::deferred,
523 [fut = std::move(f)]()
mutable ->
void { fut.get(); });
535template <
bool SkipTypeCheck>
544 "TypedFunction: null Function pointer (getAs failed or wrong type)");
545 if constexpr (!SkipTypeCheck) {
556 return std::async(std::launch::deferred,
557 [fut = std::move(f)]()
mutable ->
void { fut.get(); });
575template <
typename ArgT,
typename ResultT,
bool SkipTypeCheck = false>
581 void connect(std::function<ResultT(
const ArgT &)> callback,
582 bool quick =
false) {
585 "TypedCallback: null Callback pointer (getAs failed or wrong type)");
586 if constexpr (!SkipTypeCheck) {
594 ResultT result = cb(fromMessageData<ArgT>(argData, argType));
595 return toMessageData(result, resType);
610template <
typename ResultT,
bool SkipTypeCheck>
616 void connect(std::function<ResultT()> callback,
bool quick =
false) {
619 "TypedCallback: null Callback pointer (getAs failed or wrong type)");
620 if constexpr (!SkipTypeCheck) {
627 ResultT result = cb();
643template <
typename ArgT,
bool SkipTypeCheck>
649 void connect(std::function<
void(
const ArgT &)> callback,
bool quick =
false) {
652 "TypedCallback: null Callback pointer (getAs failed or wrong type)");
653 if constexpr (!SkipTypeCheck) {
660 cb(fromMessageData<ArgT>(argData, argType));
662 return MessageData(&zero, 1);
677template <
bool SkipTypeCheck>
683 void connect(std::function<
void()> callback,
bool quick =
false) {
686 "TypedCallback: null Callback pointer (getAs failed or wrong type)");
687 if constexpr (!SkipTypeCheck) {
Bit vectors include signed, unsigned, and signless integers.
Bits are just an array of bits.
const Type * getType() const
A logical chunk of data representing serialized data.
const uint8_t * getBytes() const
const T * as() const
Cast to a type.
size_t getSize() const
Get the size of the data in bytes.
A ChannelPort which reads data from the accelerator.
virtual std::future< MessageData > readAsync()
Asynchronous read.
virtual bool isConnected() const override
virtual void connect(std::function< bool(MessageData)> callback, const ConnectOptions &options={})
virtual void disconnect() override
virtual void read(MessageData &outData)
Specify a buffer to read into.
Type aliases provide a named type which forwards to an inner type.
Root class of the ESI type system.
std::string toString(bool oneLine=false) const
services::CallService::Callback * inner
const services::CallService::Callback & raw() const
void connect(std::function< void(const ArgT &)> callback, bool quick=false)
services::CallService::Callback & raw()
TypedCallback(services::CallService::Callback *cb)
services::CallService::Callback & raw()
void connect(std::function< ResultT()> callback, bool quick=false)
TypedCallback(services::CallService::Callback *cb)
const services::CallService::Callback & raw() const
services::CallService::Callback * inner
TypedCallback(services::CallService::Callback *cb)
services::CallService::Callback & raw()
void connect(std::function< void()> callback, bool quick=false)
const services::CallService::Callback & raw() const
services::CallService::Callback * inner
services::CallService::Callback * inner
services::CallService::Callback & raw()
void connect(std::function< ResultT(const ArgT &)> callback, bool quick=false)
TypedCallback(services::CallService::Callback *cb)
const services::CallService::Callback & raw() const
const services::FuncService::Function & raw() const
services::FuncService::Function & raw()
std::future< void > call(const ArgT &arg)
services::FuncService::Function * inner
TypedFunction(services::FuncService::Function *func)
std::future< ResultT > call()
services::FuncService::Function & raw()
services::FuncService::Function * inner
const services::FuncService::Function & raw() const
TypedFunction(services::FuncService::Function *func)
const services::FuncService::Function & raw() const
services::FuncService::Function * inner
std::future< void > call()
TypedFunction(services::FuncService::Function *func)
services::FuncService::Function & raw()
services::FuncService::Function & raw()
std::future< ResultT > call(const ArgT &arg)
const services::FuncService::Function & raw() const
TypedFunction(services::FuncService::Function *func)
Implicit conversion from Function* (returned by getAs<>()).
services::FuncService::Function * inner
TypedReadPort(ReadChannelPort &port)
void connect(const ChannelPort::ConnectOptions &opts={})
TypedReadPort(ReadChannelPort *port)
std::future< void > readAsync()
const ReadChannelPort & raw() const
void connect(std::function< bool()> callback, const ChannelPort::ConnectOptions &opts={})
TypedReadPort(ReadChannelPort &port)
TypedReadPort(ReadChannelPort *port)
std::future< T > readAsync()
void connect(const ChannelPort::ConnectOptions &opts={})
const ReadChannelPort & raw() const
void connect(std::function< bool(const T &)> callback, const ChannelPort::ConnectOptions &opts={})
void connect(const ChannelPort::ConnectOptions &opts={})
TypedWritePort(WriteChannelPort &port)
TypedWritePort(WriteChannelPort *port)
const WriteChannelPort & raw() const
const WriteChannelPort & raw() const
void write(std::unique_ptr< T > &data)
Write by taking ownership.
bool tryWrite(const T &data)
void connect(const ChannelPort::ConnectOptions &opts={})
TypedWritePort(WriteChannelPort &port)
void write(const T &data)
TypedWritePort(WriteChannelPort *port)
The "void" type is a special type which can be used to represent no type.
A ChannelPort which sends data to the accelerator.
virtual bool isConnected() const override
virtual void disconnect() override
void write(const MessageData &data)
A very basic blocking write API.
bool flush()
Flush any buffered data.
bool tryWrite(const MessageData &data)
A basic non-blocking write API.
virtual void connect(const ConnectOptions &options={}) override
Set up a connection to the accelerator.
A function call which gets attached to a service port.
const esi::Type * getArgType() const
const esi::Type * getResultType() const
void connect(std::function< MessageData(const MessageData &)> callback, bool quick=false, const ChannelPort::ConnectOptions &options={})
Connect a callback to code which will be executed when the accelerator invokes the callback.
A function call which gets attached to a service port.
const esi::Type * getArgType() const
const esi::Type * getResultType() const
std::future< MessageData > call(const MessageData &arg)
void connect(const ChannelPort::ConnectOptions &options={})
void verifyTypeCompatibility(const Type *portType)
MessageData toMessageData(const T &data, WireInfo wi)
Pack a C++ integral value into a MessageData with the given wire byte count.
WireInfo getWireInfo(const Type *portType)
constexpr bool has_esi_id_v
const Type * unwrapTypeAlias(const Type *t)
Unwrap TypeAliasType (possibly recursively) to get the underlying type.
T fromMessageData(const MessageData &msg, WireInfo wi)
Unpack a MessageData into a C++ integral value with the given wire info.
Compute the wire byte count for a port type.