summaryrefslogtreecommitdiff
path: root/c++
diff options
context:
space:
mode:
Diffstat (limited to 'c++')
-rw-r--r--c++/codec/schema_stringify.h118
-rw-r--r--c++/core/string_literal.h21
-rw-r--r--c++/core/templates.h39
-rw-r--r--c++/tools/c_gen_iface.cpp7
-rw-r--r--c++/tools/c_gen_iface.hpp323
5 files changed, 457 insertions, 51 deletions
diff --git a/c++/codec/schema_stringify.h b/c++/codec/schema_stringify.h
new file mode 100644
index 0000000..a82081a
--- /dev/null
+++ b/c++/codec/schema_stringify.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#include "schema.h"
+
+#include <sstream>
+#include <type_traits>
+
+namespace saw {
+template<typename Schema>
+struct schema_stringify {
+ static_assert(always_false<Schema>, "Not supported");
+};
+
+template<typename T, size_t Dim>
+struct schema_stringify<schema::Array<T,Dim>> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw::schema::Array<";
+ schema_stringify<T>::apply(iss);
+ iss << ",";
+ iss << ct_convert_to_digits<Dim, 10>::literal.view();
+ iss << ">";
+ }
+};
+
+template<typename T, size_t N>
+struct schema_stringify<schema::Primitive<T,N>> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw::schema::Primitive<";
+ schema_stringify<T>::apply(iss);
+ iss << ",";
+ iss << ct_convert_to_digits<N,10>::literal.view();
+ iss << ">";
+ }
+};
+
+template<>
+struct schema_stringify<schema::SignedInteger> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw:schema::SignedInteger";
+ }
+};
+
+template<>
+struct schema_stringify<schema::UnsignedInteger> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw:schema::UnsignedInteger";
+ }
+};
+
+template<>
+struct schema_stringify<schema::FloatingPoint> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw:schema::FloatingPoint";
+ }
+};
+
+template<typename... T>
+struct schema_stringify_member {
+ static void apply(std::stringstream& iss) {
+ (void)iss;
+ }
+};
+
+template<typename T0, string_literal Name, typename... TL>
+struct schema_stringify_member<schema::Member<T0,Name>, TL...> {
+
+ static void apply(std::stringstream& iss) {
+ iss << "saw::schema::Member<";
+ schema_stringify<T0>::apply(iss);
+ iss << ",\"";
+ iss << Name.view();
+ iss << "\">";
+ if constexpr ( sizeof...(TL) > 0){
+ iss << ",";
+ schema_stringify_member<TL...>::apply(iss);
+ }
+ }
+};
+
+template<typename... T, string_literal... Lits>
+struct schema_stringify<schema::Struct<schema::Member<T,Lits>...>> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw::schema::Struct<";
+ schema_stringify_member<schema::Member<T,Lits>...>::apply(iss);
+ iss << ">";
+ }
+};
+
+template<typename... T, string_literal... Lits>
+struct schema_stringify<schema::Union<schema::Member<T,Lits>...>> {
+ static void apply(std::stringstream& iss) {
+ iss << "saw::schema::Union<";
+ schema_stringify_member<schema::Member<T,Lits>...>::apply(iss);
+ iss << ">";
+ }
+};
+
+template<typename Req, typename Resp>
+struct schema_stringify<schema::Function<Req, Resp>> {
+ static void apply(std::stringstream& iss){
+ iss << "saw::schema::Function<";
+ schema_stringify<Req>::apply(iss);
+ iss << ",";
+ schema_stringify<Resp>::apply(iss);
+ iss << ">";
+ }
+};
+
+template<typename... T, string_literal... Lits>
+struct schema_stringify<schema::Interface<schema::Member<T,Lits>...>>{
+ static void apply(std::stringstream& iss){
+ iss << "saw::schema::Interface<";
+ schema_stringify_member<schema::Member<T,Lits>...>::apply(iss);
+ iss << ">";
+ }
+};
+
+}
diff --git a/c++/core/string_literal.h b/c++/core/string_literal.h
index d530a54..7373d5c 100644
--- a/c++/core/string_literal.h
+++ b/c++/core/string_literal.h
@@ -11,6 +11,8 @@ namespace saw {
*/
template <class CharT, size_t N> class string_literal {
public:
+ static_assert(N > 0, "string_literal needs a null terminator");
+
constexpr string_literal(const CharT (&input)[N]) noexcept {
for (size_t i = 0; i < N; ++i) {
data[i] = input[i];
@@ -31,10 +33,25 @@ public:
operator==(const string_literal<CharTR, NR> &) const noexcept {
return false;
}
+
+ template<size_t NR>
+ constexpr string_literal<CharT, N+NR-1> operator+(const string_literal<CharT, NR>& rhs) const noexcept {
+ CharT sum[N+NR-1];
+
+ // The weird +1 happen due to needing to skip the '\0' terminator
+ for(size_t i = 0; (i+1) < N; ++i){
+ sum[i] = data[i];
+ }
+ for(size_t i = N; (i+1) < (N+NR); ++i){
+ sum[i+1] = rhs.data[i+1];
+ }
+
+ return string_literal<CharT, N+NR-1>{sum};
+ }
};
template <typename T, T... Chars>
-constexpr string_literal<T, sizeof...(Chars)> operator""_key() {
- return string_literal<T, sizeof...(Chars) + 1u>{Chars..., '\0'};
+constexpr string_literal<T, sizeof...(Chars)+1u> operator""_sl() {
+ return string_literal<T, sizeof...(Chars) + 1u>{{Chars..., '\0'}};
}
} // namespace saw
diff --git a/c++/core/templates.h b/c++/core/templates.h
index e704f37..e2851a0 100644
--- a/c++/core/templates.h
+++ b/c++/core/templates.h
@@ -102,4 +102,43 @@ struct ct_multiply<T, V0, VN...> {
static constexpr T value = V0 * ct_multiply<T,VN...>::value;
};
+namespace impl {
+template<typename T, size_t i>
+struct ct_convert_digits_table_helper {
+ static constexpr std::array<T, 16> table = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F'
+ };
+
+ static constexpr T value = table[i];
+};
+
+template<uint64_t Num, uint64_t Base, uint64_t... Digs>
+struct ct_convert_digits_helper {
+ static constexpr size_t size = ct_convert_digits_helper<Num / Base, Base, Num % Base, Digs...>::size;
+ static constexpr std::array<uint64_t, size> value = ct_convert_digits_helper<Num / Base, Base, Num % Base, Digs...>::value;
+};
+
+template<uint64_t Base, uint64_t... Digs>
+struct ct_convert_digits_helper<0, Base, Digs...> {
+ static constexpr size_t size = sizeof...(Digs);
+ static constexpr std::array<uint64_t, size> value = {Digs...};
+};
+
+template<uint64_t Base>
+struct ct_convert_digits_helper<0, Base> {
+ static constexpr size_t size = 0;
+ static constexpr std::array<uint64_t, 1> value = {0};
+};
+}
+
+template<uint64_t Num, uint64_t Base>
+struct ct_convert_to_digits {
+ static_assert(Base <= 16, "Only conversion up to hex is supported");
+
+ static constexpr size_t size = impl::ct_convert_digits_helper<Num, Base>::size;
+ static constexpr std::array<uint64_t, size> value = impl::ct_convert_digits_helper<Num, Base>::value;
+};
}
diff --git a/c++/tools/c_gen_iface.cpp b/c++/tools/c_gen_iface.cpp
index 6ef2db7..996f3c3 100644
--- a/c++/tools/c_gen_iface.cpp
+++ b/c++/tools/c_gen_iface.cpp
@@ -1,8 +1,11 @@
#include "c_gen_iface.hpp"
int main(){
+ // saw::generate_array_example();
-
- saw::generate_array_example();
+ auto eov = saw::generate_iface_example();
+ if(eov.is_error()){
+ return -1;
+ }
return 0;
}
diff --git a/c++/tools/c_gen_iface.hpp b/c++/tools/c_gen_iface.hpp
index 3209505..7e2e396 100644
--- a/c++/tools/c_gen_iface.hpp
+++ b/c++/tools/c_gen_iface.hpp
@@ -8,9 +8,72 @@
#include <iostream>
+#include <forstio/codec/schema_stringify.h>
+
namespace saw {
namespace impl {
+/**
+ * Type meant to provide future help if I decide to introduce more maps
+ */
+struct c_types {
+ struct c_member {
+ std::string key;
+ std::string name;
+ };
+
+ struct c_param {
+ std::string key;
+ std::string name;
+ bool is_primitive;
+ };
+
+ struct c_struct {
+ std::string def;
+ std::string cpp_schema;
+ std::vector<c_member> member_keys;
+ std::string translate_to_c_source;
+ std::string translate_to_cpp_source;
+ };
+
+ struct c_response {
+ std::string key;
+ bool is_primitive;
+ };
+
+ struct c_func {
+ std::string def;
+ std::string cpp_schema;
+ c_response response;
+ std::vector<c_param> requests;
+ std::string source;
+ std::string cpp_name;
+ };
+
+ using c_struct_map = std::map<std::string, c_struct>;
+ using c_func_map = std::map<std::string, c_func>;
+
+ struct state {
+ std::string interface_schema;
+ c_struct_map struct_map;
+ c_func_map func_map;
+ std::string prefix;
+ std::string encoding;
+ };
+};
+
+/**
+ * Helper to determine if we are dealing with primitive types
+ */
+template<typename Schema>
+struct c_is_primitive {
+ static constexpr bool value = false;
+};
+
+template<typename T, size_t N>
+struct c_is_primitive<schema::Primitive<T,N>> {
+ static constexpr bool value = true;
+};
template<typename Schema>
struct c_primitive_string {
@@ -74,8 +137,11 @@ struct c_data_translater {
template<typename T, size_t N>
struct c_data_translater<schema::Primitive<T,N>> {
+ using StructMap = typename c_types::c_struct_map;
using Schema = schema::Primitive<T,N>;
- static error_or<void> generate(std::map<std::string,std::string>& map_str, std::string& str, const std::string& prefix){
+
+ static error_or<void> generate(c_types::state& c_state, std::string& str){
+ (void) c_state;
str += c_primitive_string<Schema>::value;
return void_t{};
}
@@ -83,12 +149,15 @@ struct c_data_translater<schema::Primitive<T,N>> {
template<typename T, size_t Dim>
struct c_data_translater<schema::Array<T,Dim>> {
- static error_or<void> generate(std::map<std::string, std::string>& map_str, std::string& type_str, const std::string& prefix){
- type_str = prefix + "_";
+ using Schema = schema::Array<T,Dim>;
+ using StructMap = typename c_types::c_struct_map;
+
+ static error_or<void> generate(c_types::state& c_state, std::string& type_str){
+ type_str = c_state.prefix + "_";
type_str += "array_";
std::string inner_type_str;
- auto eov = impl::c_data_translater<T>::generate(map_str, inner_type_str, prefix);
+ auto eov = impl::c_data_translater<T>::generate(c_state, inner_type_str);
if(eov.is_error()){
return eov;
}
@@ -101,77 +170,199 @@ struct c_data_translater<schema::Array<T,Dim>> {
type_str += "d";
}
- if(map_str.find(type_str) != map_str.end()){
+ if(c_state.struct_map.find(type_str) != c_state.struct_map.end()){
return void_t{};
}
- std::string str = "struct ";
- str += type_str;
+ c_types::c_struct str;
+
+ try {
+ std::stringstream iss;
+ schema_stringify<Schema>::apply(iss);
+ str.cpp_schema = iss.str();
+ }catch(const std::exception& e){
+ return make_error<err::critical>();
+ }
+
+ {
+ c_types::c_member memb;
+ memb.key = inner_type_str;
+ memb.name = "data";
+ memb.is_primitive
+ fn.members.emplace_back(std::move(memb));
+ }
- str += " {\n";
+ str.def = "struct ";
+ str.def += type_str;
- str += "\t" + inner_type_str + "* data;\n";
- str += "\tsize_t size;\n";
+ str.def += " {\n";
+
+ str.def += "\t" + inner_type_str + "* data;\n";
+ str.def += "\tsize_t size;\n";
if( Dim > 1 ){
- str += "\tsize_t dims["+std::to_string(Dim)+"];\n";
+ str.def += "\tsize_t dims["+std::to_string(Dim)+"];\n";
}
- str += "};\n";
+ str.def += "};\n";
- map_str.insert(std::make_pair(std::move(type_str), std::move(str)));
+ c_state.struct_map.emplace(std::make_pair(type_str, std::move(str)));
return void_t{};
}
};
template<typename Interface>
-struct c_rpc_translater {
+struct c_iface_translater {
static_assert(always_false<Interface>,"Not supported");
};
-template<class Request, class Response>
-struct c_rpc_translater<schema::Function<Request, Response>> {
- using Map = std::map<std::string, std::string>;
+template<class... Request, class Response, string_literal... Lits>
+struct c_iface_translater<schema::Function<schema::Struct<schema::Member<Request, Lits>...>, Response>> {
+ using StructMap = typename c_types::c_struct_map;
+ using FuncMap = typename c_types::c_func_map;
+
+ template<size_t i>
+ static error_or<void> generate_request_member(c_types::state& c_state, std::array<std::string, sizeof...(Request)>& type_arr){
+ using Type = typename parameter_pack_type<i, Request...>::type;
+ // constexpr string_literal lit = parameter_key_pack_type<i, Lits...>::literal;
+
+ auto eov = c_data_translater<Type>::generate(c_state, type_arr.at(i));
+ if(eov.is_error()){
+ return eov;
+ }
- static error_or<void> generate(const std::string& prefix, Map& type_map, Map& func_map){
+ if constexpr ((i+1) < sizeof...(Request)){
+ auto eov = generate_request_member<i+1>(c_state, type_arr);
+ return eov;
+ }
+
+ return void_t{};
+ }
+
+ template<size_t i>
+ static error_or<void> generate_parameter(std::string& param_use, const std::array<std::string, sizeof...(Request)>& req_type_arr){
+ using Type = typename parameter_pack_type<i, Request...>::type;
+ constexpr string_literal lit = parameter_key_pack_type<i, Lits...>::literal;
+
+ std::string used_param;
+ if constexpr (c_is_primitive<Type>::value){
+ used_param += req_type_arr.at(i);
+ } else {
+ used_param += "const " + req_type_arr.at(i) + "*";
+ }
+ param_use += used_param + " " + std::string{lit.view()};
+
+ if constexpr ( (i+1) < sizeof...(Request) ){
+ param_use += ", ";
+ return generate_parameter<i+1>(param_use, req_type_arr);
+ }
+
+ return void_t{};
+ }
+
+ static error_or<void> generate(c_types::state& c_state, const std::string& func_name){
+ std::array<std::string, sizeof...(Request)> request_type_arr;
+
+ if constexpr (sizeof...(Request) > 0){
+ auto eov = generate_request_member<0>(c_state, request_type_arr);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ std::string response_type_str;
+ {
+ auto eov = c_data_translater<Response>::generate(c_state, response_type_str);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ std::string c_func_name = c_state.prefix + "_" + func_name;
+
+ c_types::c_func fn;
+ fn.cpp_name = func_name;
+ fn.def = "int";
+ std::string iface_ctx = c_state.prefix + "_iface_context* ctx";
+ fn.def += " " + c_func_name + "(" + iface_ctx;
+ fn.def += ", " + response_type_str + "* out";
+ if constexpr ( sizeof...(Request) > 0 ){
+ fn.def += ", ";
+ auto eov = generate_parameter<0>(fn.def, request_type_arr);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ fn.def += ")";
+
+ fn.source = "{\n";
+ // Check necessary pointers
+ fn.source += "\tassert(ctx);\n";
+ fn.source += "\tif(!ctx){return -1;}\n\n";
+ fn.source += "\tauto rmt = reinterpret_cast<interface<IfaceSchema, "
+ fn.source += c_state.encoding;
+ fn.source += ">*>(ctx);\n";
+
+ // translate the input data
+ if constexpr (sizeof...(Request) > 0){
+ // I need a recursive search for the types
+ }
+
+ // Call the remote interface
+ fn.source += "\tauto eov = rmt->template call<\"" + fn.cpp_name + "\">(std::move(input));";
+ fn.source += ");\n";
+
+ // translate the output data
+ fn.source += "";
+
+ // Close the brace
+
+ fn.source += "}\n";
+
+ c_state.func_map.emplace(std::make_pair(c_func_name, std::move(fn)));
return void_t{};
}
};
template<class... Requests, class... Responses, string_literal... Names>
-struct c_rpc_translater<schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>> {
- using Map = std::map<std::string, std::string>;
+struct c_iface_translater<schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>> {
+ using Schema = schema::Interface<schema::Member<schema::Function<Requests, Responses>, Names>...>;
template<size_t i>
- static error_or<void> generate_member(const std::string& prefix, Map& type_map, Map& func_map){
+ static error_or<void> generate_member(c_types::state& c_state){
using Req = typename parameter_pack_type<i,Requests...>::type;
using Resp = typename parameter_pack_type<i,Responses...>::type;
constexpr string_literal lit = parameter_key_pack_type<i, Names...>::literal;
- std::string func_name{lit.view()};
- if(func_map.find(func_name) != func_map.end()){
+ try{
+ std::stringstream iss;
+ schema_stringify<Schema>::apply(iss);
+ c_state.interface_schema = iss.str();
+ }catch(const std::exception& e){
+ (void) e;
+ return make_error<err::critical>();
+ }
+
+ std::string c_func_name = c_state.prefix + "_" + std::string{lit.view()};
+ if(c_state.func_map.find(c_func_name) != c_state.func_map.end()){
return make_error<err::already_exists>();
}
{
std::string type_str;
- auto eov = c_rpc_translater<schema::Function<Req, Resp>>::generate(prefix, type_map, func_map);
+ auto eov = c_iface_translater<schema::Function<Req, Resp>>::generate(c_state, std::string{lit.view()});
if(eov.is_error()){
return eov;
}
}
if constexpr ((i+1) < sizeof...(Requests) ){
- return generate_member<i+1>(prefix, type_map, func_map);
+ return generate_member<i+1>(c_state);
}
return void_t{};
}
- static error_or<void> generate(const std::string& prefix){
- Map type_map, func_map;
-
+ static error_or<void> generate(c_types::state& c_state){
if constexpr ( sizeof...(Requests) > 0 ){
- return generate_member<0>(prefix, type_map, func_map);
+ return generate_member<0>(c_state);
}
return void_t{};
@@ -180,59 +371,97 @@ struct c_rpc_translater<schema::Interface<schema::Member<schema::Function<Reques
}
template<typename Interface>
-error_or<std::string> generate_c_rpc_interface(){
- std::stringstream iss;
- auto eov = impl::c_rpc_translater<Interface>::generate(iss, "c_saw");
+error_or<void> generate_c_interface(typename impl::c_types::state& state){
+ auto eov = impl::c_iface_translater<Interface>::generate(state);
+ return eov;
+}
- if(eov.is_error()){
- return std::move(eov.get_error());
+error_or<void> generate_iface_example(){
+ using Request1 = schema::Struct<
+ schema::Member<schema::Int32, "foo">,
+ schema::Member<schema::Float64, "bar">,
+ schema::Member<schema::Array<schema::Float32,1>, "baz">
+ >;
+ using Response1 = schema::Int32;
+
+ using Func1 = schema::Function<Request1, Response1>;
+
+ using Iface = schema::Interface<
+ schema::Member<Func1, "func_one">
+ >;
+
+ impl::c_types::state c_state;
+ c_state.prefix = "c_saw";
+ c_state.encoding = "saw::encode::Native";
+
+ typename impl::c_types::c_struct_map& type_map = c_state.struct_map;
+ typename impl::c_types::c_func_map& func_map = c_state.func_map;
+ auto eov = generate_c_interface<Iface>(c_state);
+ if(eov.is_error()){
+ return eov;
}
+ std::cout<<"Interface: "<<c_state.interface_schema<<std::endl;
+ std::cout<<"Prefix: "<<c_state.prefix<<std::endl;
+ std::cout<<"\nTypes: "<<std::endl;
- try {
- return iss.str();
- }catch(const std::exception& e){
- // Do nothing for now
+ for(auto& iter : type_map){
+ std::cout<<"\nType: \""<<iter.first<<"\""<<std::endl;
+ std::cout<<"Definition:\n\"\"\"\n";
+ std::cout<<iter.second.def;
+ std::cout<<"\"\"\""<<std::endl;
+ std::cout<<"Schema: "<<iter.second.cpp_schema<<std::endl;
}
- return make_error<err::out_of_memory>();
+ std::cout<<"\nFunctions: "<<std::endl;
+
+ for(auto& iter : func_map){
+ std::cout<<"\nSymbol: \""<<iter.first<<"\""<<std::endl;
+ std::cout<<"Definition:\n\"\"\"\n";
+ std::cout<<iter.second.def<<";\n";
+ std::cout<<"\"\"\""<<std::endl;
+ std::cout<<"\nSource:\n"<<iter.second.source<<std::endl;
+ }
+
+ return eov;
}
error_or<void> generate_array_example(){
- using Schema = schema::Array<schema::Int32,2>;
+ using Schema1 = schema::Array<schema::Int32,2>;
using Schema2 = schema::Array<schema::Float64,5>;
using Schema3 = schema::Array<schema::UInt16,1>;
std::string prefix = "c_saw";
- std::map<std::string,std::string> map_str;
+ impl::c_types::state c_state;
+ c_state.prefix = prefix;
{
std::string type_str;
- auto eov = impl::c_data_translater<Schema>::generate(map_str, type_str, prefix);
+ auto eov = impl::c_data_translater<Schema1>::generate(c_state, type_str);
if(eov.is_error()){
return eov;
}
}
{
std::string type_str;
- auto eov = impl::c_data_translater<Schema2>::generate(map_str, type_str, prefix);
+ auto eov = impl::c_data_translater<Schema2>::generate(c_state, type_str);
if(eov.is_error()){
return eov;
}
}
{
std::string type_str;
- auto eov = impl::c_data_translater<Schema3>::generate(map_str, type_str, prefix);
+ auto eov = impl::c_data_translater<Schema3>::generate(c_state, type_str);
if(eov.is_error()){
return eov;
}
}
- std::cout<<"Prefix: "<<prefix<<std::endl;
+ std::cout<<"Prefix: "<<c_state.prefix<<std::endl;
- for(auto& iter : map_str){
+ for(auto& iter : c_state.struct_map){
std::cout<<"\nType: \""<<iter.first<<"\""<<std::endl;
std::cout<<"Definition:\n\"\"\"\n";
- std::cout<<iter.second;
+ std::cout<<iter.second.def;
std::cout<<"\"\"\""<<std::endl;
}