#pragma once namespace fluid { namespace client { struct ToFloatArray { static index allocSize(typename BufferT::type) { return 1; } template static std::enable_if_t< std::is_integral::value || std::is_floating_point::value, index> allocSize(T) { return 1; } static index allocSize(std::string s) { return asSigned(s.size()) + 1; } // put null char at end when we send static index allocSize(FluidTensor s) { index count = 0; for (auto& str : s) count += (str.size() + 1); return count; } template static index allocSize(FluidTensor s) { return s.size(); } template static std::tuple, index> allocSize(std::tuple&& t) { return allocSizeImpl(std::forward(t), std::index_sequence_for()); } template static std::tuple, index> allocSizeImpl(std::tuple&& t, std::index_sequence) { index size{0}; std::array res; (void) std::initializer_list{ (res[Is] = size, size += ToFloatArray::allocSize(std::get(t)), 0)...}; return std::make_tuple(res, size); // array of offsets into allocated buffer & // total number of floats to alloc } static void convert(float* f, typename BufferT::type buf) { f[0] = static_cast(static_cast(buf.get())->bufnum()); } template static std::enable_if_t::value || std::is_floating_point::value> convert(float* f, T x) { f[0] = static_cast(x); } static void convert(float* f, std::string s) { std::copy(s.begin(), s.end(), f); f[s.size()] = 0; // terminate } static void convert(float* f, FluidTensor s) { for (auto& str : s) { std::copy(str.begin(), str.end(), f); f += str.size(); *f++ = 0; } } template static void convert(float* f, FluidTensor s) { static_assert(std::is_convertible::value, "Can't convert this to float output"); std::copy(s.begin(), s.end(), f); } template static void convert(float* f, std::tuple&& t, std::array offsets, std::index_sequence) { (void) std::initializer_list{ (convert(f + offsets[Is], std::get(t)), 0)...}; } }; template struct ToOSCTypes { static index numTags(typename BufferT::type) { return 1; } template static std::enable_if_t< std::is_integral::value || std::is_floating_point::value, index> numTags(T) { return 1; } static index numTags(std::string) { return 1;; } template static index numTags(FluidTensor s) { return s.size(); } template static index numTags(std::tuple&&) { return std::tuple_size>::value; } static void getTag(Packet& p, typename BufferT::type) { p.addtag('i'); } template static std::enable_if_t>::value> getTag(Packet& p, T&&) { p.addtag('i'); } template static std::enable_if_t>::value> getTag(Packet& p, T&&) { p.addtag('f'); } static void getTag (Packet& p, std::string) { p.addtag('s'); } template static void getTag(Packet& p, FluidTensor x) { T dummy{}; for (int i = 0; i < x.rows(); i++) getTag(p, dummy); } template static void getTag(Packet& p, std::tuple&& t) { ForEach(t,[&p](auto& x){getTag(p,x);}); } static void convert(Packet& p, typename BufferT::type buf) { p.addi(static_cast(static_cast(buf.get())->bufnum())); } template static std::enable_if_t::value> convert(Packet& p, T x) { p.addi(static_cast(x)); } template static std::enable_if_t::value> convert(Packet& p, T x) { p.addf(static_cast(x)); } static void convert(Packet& p, std::string s) { p.adds(s.c_str()); } template static void convert(Packet& p, FluidTensor s) { for(auto& x: s) convert(p,x); } template static void convert(Packet& p, std::tuple&& t) { ForEach(t,[&p](auto& x){ convert(p,x);}); } }; } }