7 #ifndef LLU_WSTP_WSSTREAM_HPP_
8 #define LLU_WSTP_WSSTREAM_HPP_
14 #include <type_traits>
40 template<WS::Encoding EncodingIn, WS::Encoding EncodingOut = EncodingIn>
66 WSStream(WSLINK mlp,
const std::string& head,
int argc);
76 WSLINK&
get() noexcept {
87 template<
typename Iterator,
typename = enable_if_input_iterator<Iterator>>
98 template<
typename Iterator,
typename = enable_if_input_iterator<Iterator>>
99 void sendRange(Iterator begin, Iterator end,
const std::string& head);
213 template<
typename T,
typename D>
234 template<WS::Encoding E>
254 template<WS::Encoding E,
typename T>
278 template<
typename T, std::
size_t N,
typename = std::enable_if_t<WS::StringTypeQ<T>>>
298 template<
typename K,
typename V>
310 template<
typename T,
typename = std::enable_if_t<std::is_arithmetic_v<T>>>
322 template<
typename Container,
typename = std::void_t<
323 decltype(std::declval<Container>().begin(), std::declval<Container>().end(), std::declval<Container>().size())>>
440 template<WS::Encoding E = EncodingIn>
464 template<WS::Encoding E,
typename T>
477 template<
typename K,
typename V>
489 template<
typename T,
typename = std::enable_if_t<std::is_arithmetic_v<T>>>
501 void check(
int statusOk,
const std::string& errorName,
const std::string& debugInfo =
"");
510 int testHead(
const std::string& head);
519 void testHead(
const std::string& head,
int argc);
524 void refreshCurrentWSLINK();
533 std::stack<LoopbackData> loopbackStack;
536 bool currentExprDropped =
false;
541 template<WS::Encoding EIn, WS::Encoding EOut>
548 template<WS::Encoding EIn, WS::Encoding EOut>
551 template<WS::Encoding EIn, WS::Encoding EOut>
553 testHead(head, argc);
556 template<WS::Encoding EIn, WS::Encoding EOut>
557 template<
typename Iterator,
typename>
559 sendRange(begin, end,
"List");
562 template<WS::Encoding EIn, WS::Encoding EOut>
563 template<
typename Iterator,
typename>
565 *this << WS::Function(head, static_cast<int>(std::distance(begin, end)));
566 std::for_each(begin, end, [
this](
const auto& elem) { *
this << elem; });
569 template<WS::Encoding EIn, WS::Encoding EOut>
570 void WSStream<EIn, EOut>::check(
int statusOk,
const std::string& errorName,
const std::string& debugInfo) {
571 WS::Detail::checkError(m, statusOk, errorName, debugInfo);
574 template<WS::Encoding EIn, WS::Encoding EOut>
575 int WSStream<EIn, EOut>::testHead(
const std::string& head) {
581 template<WS::Encoding EIn, WS::Encoding EOut>
582 void WSStream<EIn, EOut>::testHead(
const std::string& head,
int argc) {
583 int argcount = testHead(head);
584 if (argc != argcount) {
585 WS::Detail::throwLLUException(
ErrorName::WSTestHeadError,
"Expected " + std::to_string(argc) +
" arguments but got " + std::to_string(argcount));
589 template<WS::Encoding EIn, WS::Encoding EOut>
590 void WSStream<EIn, EOut>::refreshCurrentWSLINK() {
591 if (loopbackStack.empty()) {
594 m = std::get<WSLINK>(loopbackStack.top());
601 template<WS::Encoding EIn, WS::Encoding EOut>
606 template<WS::Encoding EIn, WS::Encoding EOut>
608 return f(*
this, WS::Direction::Put);
611 template<WS::Encoding EIn, WS::Encoding EOut>
617 template<WS::Encoding EIn, WS::Encoding EOut>
620 "Cannot put function: \"" + f.getHead() +
"\" with " + std::to_string(f.getArgc()) +
" arguments");
624 template<WS::Encoding EIn, WS::Encoding EOut>
626 check(WSPutFunction(m, f.getHead().c_str(), 1),
632 template<WS::Encoding EIn, WS::Encoding EOut>
636 currentExprDropped =
false;
639 auto* loopback = WS::Detail::getNewLoopback(m);
642 loopbackStack.emplace(expr.getHead(), loopback);
645 refreshCurrentWSLINK();
650 template<WS::Encoding EIn, WS::Encoding EOut>
653 if (loopbackStack.size() < 2) {
655 "Trying to Drop expression with loopback stack size " + std::to_string(loopbackStack.size()));
658 WSClose(std::get<WSLINK>(loopbackStack.top()));
660 refreshCurrentWSLINK();
663 currentExprDropped =
true;
668 template<WS::Encoding EIn, WS::Encoding EOut>
672 if (currentExprDropped) {
673 currentExprDropped =
false;
678 if (loopbackStack.size() < 2) {
680 "Trying to End expression with loopback stack size " + std::to_string(loopbackStack.size()));
684 auto currentPartialExpr = loopbackStack.top();
688 refreshCurrentWSLINK();
691 auto& exprArgs = std::get<WSLINK>(currentPartialExpr);
692 auto argCnt = WS::Detail::countExpressionsInLoopbackLink(exprArgs);
693 *this << WS::Function(std::get<std::string>(currentPartialExpr), argCnt);
695 "Could not transfer " + std::to_string(argCnt) +
" expressions from Loopback Link");
702 template<WS::Encoding EIn, WS::Encoding EOut>
704 return *
this << WS::Symbol(b ?
"True" :
"False");
707 template<WS::Encoding EIn, WS::Encoding EOut>
709 WS::PutScalar<wsint64>::put(m,
static_cast<wsint64
>(i));
713 template<WS::Encoding EIn, WS::Encoding EOut>
716 const auto& del = a.get_deleter();
717 WS::PutArray<T>::put(m, a.get(), del.getDims(), del.getHeads(), del.getRank());
721 template<WS::Encoding EIn, WS::Encoding EOut>
724 const auto& del = l.get_deleter();
725 WS::PutList<T>::put(m, l.get(), del.getLength());
729 template<WS::Encoding EIn, WS::Encoding EOut>
730 template<
typename T,
typename D>
740 template<WS::Encoding EIn, WS::Encoding EOut>
743 if constexpr (WS::ScalarSupportedTypeQ<T>) {
744 WS::PutList<T>::put(m, l.data(),
static_cast<int>(l.size()));
746 *this << WS::List(static_cast<int>(l.size()));
747 for (
const auto& elem : l) {
754 template<WS::Encoding EIn, WS::Encoding EOut>
755 template<WS::Encoding E>
757 WS::String<E>::put(m, s.get(), s.get_deleter().getLength());
761 template<WS::Encoding EIn, WS::Encoding EOut>
764 if constexpr (WS::StringTypeQ<T>) {
765 WS::String<EOut>::put(m, s.c_str(),
static_cast<int>(s.size()));
767 static_assert(dependent_false_v<T>,
"Calling operator<< with unsupported character type.");
772 template<WS::Encoding EIn, WS::Encoding EOut>
773 template<
typename T, std::
size_t N,
typename>
775 WS::String<EOut>::put(m, s, N);
779 template<WS::Encoding EIn, WS::Encoding EOut>
780 template<WS::Encoding E,
typename T>
782 WSStream<EIn, E> tmpWSS {m};
787 template<WS::Encoding EIn, WS::Encoding EOut>
789 WS::String<EOut>::put(m, s,
static_cast<int>(std::strlen(s)));
793 template<WS::Encoding EIn, WS::Encoding EOut>
794 template<
typename T,
typename>
796 if constexpr (WS::ScalarSupportedTypeQ<T>) {
797 WS::PutScalar<T>::put(m, value);
799 static_assert(dependent_false_v<T>,
"Calling operator<< with unsupported scalar type.");
804 template<WS::Encoding EIn, WS::Encoding EOut>
805 template<
typename K,
typename V>
807 *this << WS::Association(static_cast<int>(map.size()));
808 for (
const auto& elem : map) {
809 *
this <<
WS::Rule << elem.first << elem.second;
818 template<WS::Encoding EIn, WS::Encoding EOut>
820 return f(*
this, WS::Direction::Get);
823 template<WS::Encoding EIn, WS::Encoding EOut>
829 template<WS::Encoding EIn, WS::Encoding EOut>
831 if (!s.getHead().empty()) {
837 WSReleaseSymbol(m, head);
842 template<WS::Encoding EIn, WS::Encoding EOut>
844 testHead(f.getHead(), f.getArgc());
848 template<WS::Encoding EIn, WS::Encoding EOut>
850 if (!f.getHead().empty()) {
851 if (f.getArgc() < 0) {
852 f.setArgc(testHead(f.getHead()));
854 testHead(f.getHead(), f.getArgc());
861 WSReleaseSymbol(m, head);
867 template<WS::Encoding EIn, WS::Encoding EOut>
871 if (
boolean.getHead() ==
"True") {
873 }
else if (
boolean.getHead() ==
"False") {
881 template<WS::Encoding EIn, WS::Encoding EOut>
883 i =
static_cast<mint
>(WS::GetScalar<wsint64>::get(m));
887 template<WS::Encoding EIn, WS::Encoding EOut>
888 template<WS::Encoding E,
typename T>
890 WSStream<E, EOut> tmpWSS {m};
895 template<WS::Encoding EIn, WS::Encoding EOut>
898 a = WS::GetArray<T>::get(m);
902 template<WS::Encoding EIn, WS::Encoding EOut>
905 l = WS::GetList<T>::get(m);
909 template<WS::Encoding EIn, WS::Encoding EOut>
912 if constexpr (WS::ScalarSupportedTypeQ<T>) {
913 auto list = WS::GetList<T>::get(m);
914 T* start = list.get();
915 auto listLen = list.get_deleter().getLength();
916 l = std::vector<T> {start, std::next(start, listLen)};
920 std::vector<T> res(inList.getArgc());
921 for (
auto& elem : res) {
929 template<WS::Encoding EIn, WS::Encoding EOut>
930 template<WS::Encoding E>
932 s = WS::String<E>::get(m);
936 template<WS::Encoding EIn, WS::Encoding EOut>
939 if constexpr (WS::StringTypeQ<T>) {
940 s = WS::String<EIn>::template getString<T>(m);
942 static_assert(dependent_false_v<T>,
"Calling operator>> with unsupported character type.");
947 template<WS::Encoding EIn, WS::Encoding EOut>
948 template<
typename K,
typename V>
950 auto elemCount = testHead(
"Association");
951 for (
auto i = 0; i < elemCount; ++i) {
957 map.emplace(std::move(key), std::move(value));
962 template<WS::Encoding EIn, WS::Encoding EOut>
963 template<
typename T,
typename>
965 if constexpr (WS::ScalarSupportedTypeQ<T>) {
966 value = WS::GetScalar<T>::get(m);
968 static_assert(dependent_false_v<T>,
"Calling operator>> with unsupported type.");