31#ifndef DW_FRAMEWORK_PORTDESCRIPTOR_HPP_
32#define DW_FRAMEWORK_PORTDESCRIPTOR_HPP_
34#include <dwshared/dwfoundation/dw/core/container/StringView.hpp>
36#include <dwshared/dwfoundation/dw/core/language/cxx20.hpp>
37#include <dwshared/dwfoundation/dw/core/language/Tuple.hpp>
38#include <dwshared/dwfoundation/dw/core/safety/Safety.hpp>
52template <
typename... Args>
56 return dw::core::make_tuple<Args...>(std::forward<Args>(args)...);
65template <
typename PortType,
size_t ArraySize,
size_t NameSize>
68 static_assert(std::is_constructible<PortType>::value,
"PortType must be constructible");
85 ,
name{std::move(name_)}
92#define DW_PORT_TYPE_NAME_STRING_VIEW_IMPL(TYPE_NAME_STR) TYPE_NAME_STR##_sv
93#define DW_PORT_TYPE_NAME_STRING_VIEW(TYPE_NAME) DW_PORT_TYPE_NAME_STRING_VIEW_IMPL(#TYPE_NAME)
94#define DW_DESCRIBE_PORT(TYPE_NAME, NAME, args...) dw::framework::describePort<TYPE_NAME, NAME.size()>(DW_PORT_TYPE_NAME_STRING_VIEW(TYPE_NAME), NAME, ##args)
96template <
typename PortType,
size_t NameSize>
108#define DW_DESCRIBE_PORT_ARRAY(TYPE_NAME, ARRAYSIZE, NAME, args...) dw::framework::describePortArray<TYPE_NAME, ARRAYSIZE, NAME.size()>(DW_PORT_TYPE_NAME_STRING_VIEW(TYPE_NAME), NAME, ##args)
113 typename std::enable_if_t<ArraySize != 0, void>* =
nullptr>
129 typename std::enable_if_t<ArraySize != 0, void>* =
nullptr>
132 dw::core::StringView typeName, dw::core::StringView name, dw::core::StringView comment)
134 return describePortArray<PortType, ArraySize, NameSize>(
144template <
typename Node>
149 return Node::describeInputPorts();
153template <
typename Node>
158 return Node::describeOutputPorts();
165 typename std::enable_if_t<Direction == PortDirection::INPUT, void>* =
nullptr>
170 return describeNodeInputPorts<Node>();
177 typename std::enable_if_t<Direction == PortDirection::OUTPUT, void>* =
nullptr>
182 return describeNodeOutputPorts<Node>();
188template <
typename Node, PortDirection Direction>
192 return dw::core::tuple_size<decltype(describePorts<Node, Direction>())>::value;
196template <
typename Node, PortDirection Direction,
size_t DescriptorIndex>
200 constexpr size_t array_length{dw::core::tuple_element_t<
202 decltype(describePorts<Node, Direction>())>::arraySize};
204 return array_length > 0U;
209template <
typename Node, PortDirection Direction,
size_t DescriptorIndex>
213 constexpr size_t array_length{dw::core::tuple_element_t<
215 decltype(describePorts<Node, Direction>())>::arraySize};
217 if (0U == array_length)
226template <
typename Node, PortDirection Direction,
size_t DescriptorIndex>
229 constexpr PortBinding port_binding = dw::core::get<DescriptorIndex>(describePorts<Node, Direction>()).binding;
234template <
typename Node, PortDirection Direction,
size_t DescriptorIndex>
237 constexpr dw::core::StringView port_comment = dw::core::get<DescriptorIndex>(describePorts<Node, Direction>()).comment;
242template <
typename Node, PortDirection Direction,
size_t DescriptorIndex>
247 return typename dw::core::tuple_element_t<
249 decltype(describePorts<Node, Direction>())>::Type();
257 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
258 typename std::enable_if_t<DescriptorIndex == portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
260constexpr std::size_t portSize_()
267 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
268 typename std::enable_if_t<DescriptorIndex<portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
270 constexpr std::size_t portSize_()
272 return descriptorPortSize<Node, Direction, DescriptorIndex>() + portSize_<Node, Direction, DescriptorIndex + 1>();
277template <
typename Node, PortDirection Direction>
281 return detail::portSize_<Node, Direction, 0>();
289 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
size_t RemainingPortIndex,
290 typename std::enable_if_t<DescriptorIndex == portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
292constexpr std::size_t descriptorIndex_()
299 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
size_t RemainingPortIndex,
300 typename std::enable_if_t<DescriptorIndex<portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
302 constexpr std::size_t descriptorIndex_()
305 if (RemainingPortIndex < descriptorPortSize<Node, Direction, DescriptorIndex>())
313 constexpr size_t remainingPortIndex{RemainingPortIndex - descriptorPortSize<Node, Direction, DescriptorIndex>()};
315 return 1U + descriptorIndex_<Node, Direction, DescriptorIndex + 1, remainingPortIndex>();
320template <
typename Node, PortDirection Direction,
size_t PortIndex>
326 return detail::descriptorIndex_<
Node, Direction, 0, PortIndex - portSize<Node, PortDirection::INPUT>()>();
328 return detail::descriptorIndex_<Node, Direction, 0, PortIndex>();
331template <
typename Node, PortDirection Direction,
size_t PortIndex>
337 constexpr size_t index{descriptorIndex<Node, Direction, PortIndex>()};
338 return dw::core::get<index>(describePorts<Node, Direction>()).name;
345constexpr const size_t DECIMAL_BASE{10U};
347constexpr size_t numberOfDigits(
size_t number)
349 static_assert(std::numeric_limits<size_t>::digits10 <= std::numeric_limits<size_t>::max(),
"size_t number of digits exceeds size_t (not possible)");
361 number = number / DECIMAL_BASE;
363 if (std::numeric_limits<size_t>::max() == count)
365 throw std::logic_error(
"size_t number of digits exceeds size_t (not possible)");
372constexpr size_t getArrayNameSize(
size_t portNameSize,
size_t arrayIndex)
375 constexpr size_t MAX_SIZE_WITHOUT_BRACKETS{std::numeric_limits<size_t>::max() - 1U - 1U};
376 if (portNameSize >= MAX_SIZE_WITHOUT_BRACKETS)
378 throw std::runtime_error(
"Array name too long");
380 if (MAX_SIZE_WITHOUT_BRACKETS - portNameSize < numberOfDigits(arrayIndex))
382 throw std::runtime_error(
"Array name + digits for array index too long");
385 return portNameSize + 1U + numberOfDigits(arrayIndex) + 1U;
388template <
size_t NameSize,
size_t ArraySize>
390constexpr size_t getMaximumArrayNameSize()
392 static_assert(NameSize > 0U,
"Name size must not be zero");
393 static_assert(ArraySize > 0U,
"Array size must not be zero");
396 return getArrayNameSize(NameSize, ArraySize - 1U);
399template <
size_t NameSize,
size_t ArraySize>
400class PortNamesGenerator
403 static_assert(NameSize > 0U,
"Name size must not be zero");
404 static_assert(ArraySize > 0U,
"Array size must not be zero");
407 static_assert(std::numeric_limits<size_t>::max() / ArraySize > getMaximumArrayNameSize<NameSize, ArraySize>() + 1U,
"The storage size exceeds size_t");
411 static constexpr size_t StorageSize{ArraySize * (getMaximumArrayNameSize<NameSize, ArraySize>() + 1U)};
412 constexpr PortNamesGenerator(dw::core::StringView baseName)
415 if (baseName.size() > NameSize)
418 throw ExceptionWithStatus(DW_INTERNAL_ERROR,
"The passed string size ", baseName.size(),
" exceeds the template parameter NameSize ", NameSize);
422 for (
size_t arrayIndex{0U}; ArraySize != arrayIndex; ++arrayIndex)
425 for (
size_t j{0U}; j < baseName.size(); ++j)
427 m_data.at(i) = baseName[j];
429 dw::core::safeIncrement(i, 1U);
433 const char8_t OPENING_BRACKET{
'['};
434 m_data.at(i) = OPENING_BRACKET;
436 dw::core::safeIncrement(i, 1U);
438 size_t remainingValue{arrayIndex};
441 const size_t INDEX_LAST_DIGIT{dw::core::safeAdd(i, numberOfDigits(arrayIndex) - 1U).value()};
443 for (
size_t j{0U}; j < numberOfDigits(arrayIndex); ++j)
446 constexpr char8_t digits[10]{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9'};
448 if (INDEX_LAST_DIGIT < j)
450 throw std::logic_error(
"index j must never be greater than the index of the last digit");
452 m_data.at(INDEX_LAST_DIGIT - j) = digits[remainingValue % DECIMAL_BASE];
454 dw::core::safeIncrement(i, 1U);
455 remainingValue = remainingValue / DECIMAL_BASE;
458 const char8_t CLOSING_BRACKET{
']'};
459 m_data.at(i) = CLOSING_BRACKET;
461 dw::core::safeIncrement(i, 1U);
463 m_data.at(i) =
static_cast<char8_t>(0);
465 dw::core::safeIncrement(i, 1U);
468 if (i > std::numeric_limits<size_t>::max() - numberOfDigits(ArraySize - 1U))
470 throw std::logic_error(
"index j must never be greater than the index of the last digit");
474 i += numberOfDigits(ArraySize - 1U) - numberOfDigits(arrayIndex);
478 dw::core::StringView getName(
size_t arrayIndex)
const
480 if (arrayIndex >= ArraySize)
482 throw ExceptionWithStatus(DW_OUT_OF_BOUNDS,
"Array index ", arrayIndex,
" out of bound for array size ", ArraySize);
485 return dw::core::StringView(&m_data.at(arrayIndex * (getMaximumArrayNameSize<NameSize, ArraySize>() + 1U)), getArrayNameSize(NameSize, arrayIndex));
489 std::array<char8_t, StorageSize> m_data;
494template <
typename Node, PortDirection Direction,
size_t PortIndex>
500 constexpr size_t index{descriptorIndex<Node, Direction, PortIndex>()};
502 constexpr auto desc = dw::core::get<index>(describePorts<Node, Direction>());
503 static_assert(desc.arraySize > 0U,
"A port name with an array index argument is only applicable to array ports");
505 static const detail::PortNamesGenerator<desc.nameSize, desc.arraySize> generatedNames{desc.name};
506 return generatedNames.getName(arrayIndex);
510template <
typename Node, PortDirection Direction,
size_t PortIndex>
517 constexpr size_t index{descriptorIndex<Node, Direction, PortIndex>()};
518 return portDescriptorType<Node, Direction, index>();
522template <
typename Node, PortDirection Direction>
529 return portID >= portSize<Node, PortDirection::INPUT>() && portID < portSize<Node, PortDirection::INPUT>() + portSize<Node, Direction>();
531 return portID < portSize<Node, Direction>();
539 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
540 typename std::enable_if_t<DescriptorIndex == portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
541constexpr std::size_t portArraySize_(StringView identifier)
548 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
549 typename std::enable_if_t<DescriptorIndex<portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
551 constexpr std::size_t portArraySize_(StringView identifier)
553 constexpr auto descriptorName = dw::core::get<DescriptorIndex>(describePorts<Node, Direction>()).name;
554 if (descriptorName == identifier)
556 return descriptorPortSize<Node, Direction, DescriptorIndex>();
558 return portArraySize_<Node, Direction, DescriptorIndex + 1>(identifier);
563template <
typename Node, PortDirection Direction>
566 return detail::portArraySize_<Node, Direction, 0>(identifier);
575 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
576 typename std::enable_if_t<DescriptorIndex == portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
578constexpr std::size_t portIndex_(StringView identifier)
580 static_cast<void>(identifier);
586 return dw::framework::portSize<Node, PortDirection::OUTPUT>();
593 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
594 typename std::enable_if_t<DescriptorIndex<portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
596 constexpr std::size_t portIndex_(StringView identifier)
598 constexpr StringView descriptorName{dw::core::get<DescriptorIndex>(describePorts<Node, Direction>()).name};
599 if (descriptorName == identifier)
604 return descriptorPortSize<Node, Direction, DescriptorIndex>() + portIndex_<Node, Direction, DescriptorIndex + 1>(identifier);
609template <
typename Node, PortDirection Direction>
617 return portSize<Node, PortDirection::INPUT>() + detail::portIndex_<Node, Direction, 0>(identifier);
619 return detail::portIndex_<Node, Direction, 0>(identifier);
624template <
typename Node, PortDirection Direction>
627 constexpr size_t index = portIndex<Node, Direction>(identifier);
628 return isValidPortIndex<Node, Direction>(index);
636 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
637 typename std::enable_if_t<DescriptorIndex == portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
638constexpr std::size_t portDescriptorIndex_(StringView identifier)
645 typename Node,
PortDirection Direction,
size_t DescriptorIndex,
646 typename std::enable_if_t<DescriptorIndex<portDescriptorSize<Node, Direction>(),
void>* =
nullptr>
648 constexpr std::size_t portDescriptorIndex_(StringView identifier)
650 constexpr auto descriptorName = dw::core::get<DescriptorIndex>(describePorts<Node, Direction>()).name;
651 if (descriptorName == identifier)
655 return 1 + portDescriptorIndex_<Node, Direction, DescriptorIndex + 1>(identifier);
660template <
typename Node, PortDirection Direction>
663 return detail::portDescriptorIndex_<Node, Direction, 0>(identifier);
constexpr auto describePorts()
constexpr bool descriptorPortArray()
constexpr size_t portIndex(StringView identifier)
constexpr size_t descriptorPortSize()
constexpr auto describePortArray(dw::core::StringView typeName, dw::core::StringView name, PortBinding binding=PortBinding::OPTIONAL, dw::core::StringView comment=""_sv) -> PortDescriptorT< PortType, ArraySize, NameSize >
constexpr size_t portDescriptorIndex(StringView identifier)
constexpr auto describeNodeInputPorts()
constexpr auto portDescriptorType()
constexpr auto describePort(dw::core::StringView typeName, dw::core::StringView name, PortBinding binding=PortBinding::OPTIONAL, dw::core::StringView comment=""_sv) -> PortDescriptorT< PortType, 0, NameSize >
constexpr size_t portArraySize(StringView identifier)
constexpr std::size_t portDescriptorSize()
constexpr auto describePortCollection(Args &&... args) -> dw::core::Tuple< Args... >
constexpr bool isValidPortIndex(std::size_t portID)
constexpr std::size_t portSize()
constexpr PortBinding descriptorPortBinding()
constexpr dw::core::StringView portName()
constexpr auto describeNodeOutputPorts()
constexpr bool isValidPortIdentifier(StringView identifier)
constexpr dw::core::StringView descriptorPortComment()
constexpr auto portType()
constexpr size_t descriptorIndex()
static constexpr size_t arraySize
dw::core::StringView typeName
dw::core::StringView comment
dw::core::StringView name
constexpr PortDescriptorT(dw::core::StringView &&typeName_, dw::core::StringView &&name_, PortBinding binding_=PortBinding::OPTIONAL, dw::core::StringView comment_=""_sv)
static constexpr size_t nameSize