diff --git a/include/wrapper/ArgsFromClient.hpp b/include/wrapper/ArgsFromClient.hpp index 88ae458..7e49cab 100644 --- a/include/wrapper/ArgsFromClient.hpp +++ b/include/wrapper/ArgsFromClient.hpp @@ -135,38 +135,45 @@ struct ParamReader } } - static const char* argTypeToString(std::string&) + + template + static const char* argTypeToString(Optional&) + { + return argTypeToString(T{}); + } + + static const char* argTypeToString(const std::string&) { return "string"; } template static std::enable_if_t::value, const char*> - argTypeToString(T&) + argTypeToString(T) { return "integer"; } template static std::enable_if_t::value, const char*> - argTypeToString(T&) + argTypeToString(T) { return "float"; } - static const char* argTypeToString(BufferT::type&) + static const char* argTypeToString(const BufferT::type&) { return "buffer"; } - static const char* argTypeToString(InputBufferT::type&) + static const char* argTypeToString(const InputBufferT::type&) { return "buffer"; } template static std::enable_if_t::value,const char*> - argTypeToString(P&) + argTypeToString(const P&) { return "shared_object"; //not ideal } @@ -179,28 +186,34 @@ struct ParamReader template static std::enable_if_t::value || std::is_floating_point::value, bool> - argTypeOK(T&, char tag) + argTypeOK(T, char tag) { return tag == 'i' || tag == 'f' || tag == 'd'; } - static bool argTypeOK(BufferT::type&, char tag) + static bool argTypeOK(const BufferT::type&, char tag) { return tag == 'i'; } - static bool argTypeOK(InputBufferT::type&, char tag) + static bool argTypeOK(const InputBufferT::type&, char tag) { return tag == 'i'; } template static std::enable_if_t::value,bool> - argTypeOK(P&, char tag) + argTypeOK(const P&, char tag) { return tag == 'i'; } + template + static bool argTypeOK(const Optional&, char tag) + { + return argTypeOK(T{},tag); + } + static auto fromArgs(World*, sc_msg_iter& args, std::string, int) { const char* recv = args.gets(""); @@ -266,6 +279,13 @@ struct ParamReader res[i] = static_cast(args.geti()); return res; } + + template + static auto fromArgs(World* w, sc_msg_iter& args, Optional, int) + { + return Optional{fromArgs(w,args,T{},int{})}; + } + }; diff --git a/include/wrapper/Messaging.hpp b/include/wrapper/Messaging.hpp index 77c4d05..ef5ee8b 100644 --- a/include/wrapper/Messaging.hpp +++ b/include/wrapper/Messaging.hpp @@ -48,10 +48,27 @@ struct FluidSCMessaging{ }; + + template + static auto constexpr filterOneOptional(const T&) { return std::make_tuple(T{}); } + + template + static auto constexpr filterOneOptional(const Optional&) { return std::make_tuple(); } + + + template + static auto constexpr filterOptional(std::tuple) + { + return std::tuple_cat(filterOneOptional(Ts{})...); + } + + template - static bool validateMessageArgs(Message* msg, sc_msg_iter* inArgs) + static Optional validateMessageArgs(Message* msg, sc_msg_iter* inArgs) { + //we can be sure that optional args always follow mandatory ones, as this is enforced at compile time in flucoma-core using ArgTuple = decltype(msg->args); + using MandatoryArgsTuple = decltype(filterOptional(msg->args)); std::string tags(inArgs->tags + inArgs->count);//evidently this needs commenting: construct string at pointer offset by tag count, to pick up args bool willContinue = true; @@ -59,7 +76,7 @@ struct FluidSCMessaging{ auto& args = msg->args; - constexpr size_t expectedArgCount = std::tuple_size::value; + constexpr size_t expectedArgCount = std::tuple_size::value; /// TODO this squawks if we have a completion message, so maybe we can check if extra arg is a 'b' and squawk if not? // if(tags.size() > expectedArgCount) @@ -77,14 +94,16 @@ struct FluidSCMessaging{ auto tagsIter = tags.begin(); auto tagsEnd = tags.end(); - ForEach(args,[&typesMatch,&tagsIter,&tagsEnd](auto& arg){ + size_t argCount = 0; + ForEach(args,[&typesMatch,&tagsIter,&tagsEnd,firstTag=tags.begin(),&argCount](auto& arg){ if(tagsIter == tagsEnd) { - typesMatch = false; + if(std::distance(firstTag,tagsIter) < expectedArgCount) typesMatch = false; return; } char t = *(tagsIter++); typesMatch = typesMatch && ParamReader::argTypeOK(arg,t); + argCount++; }); willContinue = willContinue && typesMatch; @@ -116,7 +135,7 @@ struct FluidSCMessaging{ report << ")\n"; } - return willContinue; + return willContinue ? Optional(argCount) : Optional(); } static void refreshParams(Params& p, MessageResult& r) @@ -137,9 +156,9 @@ struct FluidSCMessaging{ msg->id = args->geti(); msg->replyAddr = copyReplyAddress(replyAddr); ///TODO make this step contingent on verbosity or something, in the name of effieciency - bool willContinue = validateMessageArgs(msg, args); + auto tagCount = validateMessageArgs(msg, args); - if(!willContinue) + if(!tagCount.has_value()) { delete msg; return; @@ -148,9 +167,10 @@ struct FluidSCMessaging{ msg->name = std::string{'/'} + (const char*)(inUserData); - ForEach(msg-> args,[inWorld,&args](auto& thisarg) + ForEach(msg-> args,[inWorld,&args,tagCount,n=0](auto& thisarg)mutable { - thisarg = ParamReader::fromArgs(inWorld, *args,thisarg,0); + if(n++ < tagCount.value()) + thisarg = ParamReader::fromArgs(inWorld, *args,thisarg,0); }); size_t completionMsgSize{args ? args->getbsize() : 0}; diff --git a/release-packaging/Classes/FluidKDTree.sc b/release-packaging/Classes/FluidKDTree.sc index 8ce1aac..3dc3c04 100644 --- a/release-packaging/Classes/FluidKDTree.sc +++ b/release-packaging/Classes/FluidKDTree.sc @@ -24,13 +24,16 @@ FluidKDTree : FluidModelObject this.prSendMsg(this.fitMsg(dataSet)); } - kNearestMsg{|buffer| - ^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer)); + kNearestMsg{|buffer,k| + k !? + {^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer),k);} + ?? + {^this.prMakeMsg(\kNearest,id,this.prEncodeBuffer(buffer));} } - kNearest{ |buffer, action| + kNearest{ |buffer, k, action| actions[\kNearest] = [strings(FluidMessageResponse,_,_),action]; - this.prSendMsg(this.kNearestMsg(buffer)); + this.prSendMsg(this.kNearestMsg(buffer,k)); } kNearestDistMsg {|buffer|