diff --git a/include/cpphibernate.h b/include/cpphibernate.h index e69de29..e899e4d 100644 --- a/include/cpphibernate.h +++ b/include/cpphibernate.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include +#include +#include \ No newline at end of file diff --git a/include/cpphibernate/.gitdir b/include/cpphibernate/.gitdir deleted file mode 100644 index e69de29..0000000 diff --git a/include/cpphibernate/config.h b/include/cpphibernate/config.h new file mode 100644 index 0000000..fa4a015 --- /dev/null +++ b/include/cpphibernate/config.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +#define cpphibernate_equality_comparable() \ + template \ + constexpr decltype(auto) operator==(T_other&&) const \ + { \ + return ::boost::hana::type<::utl::mp::decay_t> { } == \ + ::boost::hana::type<::utl::mp::decay_t> { }; \ + } \ + \ + template \ + constexpr decltype(auto) operator!=(T_other&&) const \ + { \ + return ::boost::hana::type<::utl::mp::decay_t> { } != \ + ::boost::hana::type<::utl::mp::decay_t> { }; \ + } + +#define cpphibernate_constructable(name, value) \ + name() = value + +#define cpphibernate_copyable(name, value) \ + name(const name&) = value; \ + name& operator=(const name&) = value + +#define cpphibernate_moveable(name, value) \ + name(name&&) = value; \ + name& operator=(name&&) = value + +#define cpphibernate_define_namespace_beg(parent, name) \ + parent { \ + namespace name + +#define cpphibernate_define_namespace_end(parent) \ + } \ + parent + +#define beg_namespace_cpphibernate namespace cpphibernate +#define end_namespace_cpphibernate + +#define beg_namespace_cpphibernate_schema cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, schema) +#define end_namespace_cpphibernate_schema cpphibernate_define_namespace_end(end_namespace_cpphibernate) + +#define beg_namespace_cpphibernate_misc cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, misc) +#define end_namespace_cpphibernate_misc cpphibernate_define_namespace_end(end_namespace_cpphibernate) + +beg_namespace_cpphibernate +{ + + namespace mp = ::utl::mp; + namespace hana = ::boost::hana; + +} +end_namespace_cpphibernate diff --git a/include/cpphibernate/misc.h b/include/cpphibernate/misc.h new file mode 100644 index 0000000..ae02dec --- /dev/null +++ b/include/cpphibernate/misc.h @@ -0,0 +1,5 @@ +#pragma once + +#include +#include +#include \ No newline at end of file diff --git a/include/cpphibernate/misc/general.h b/include/cpphibernate/misc/general.h new file mode 100644 index 0000000..c79ff0d --- /dev/null +++ b/include/cpphibernate/misc/general.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_misc +{ + + /* make_generic_predicate */ + + template class T_builder> + struct make_generic_predicate + { + template + constexpr decltype(auto) operator()(T_args&&... args) const + { return T_builder>::apply(std::forward(args)...); } + }; + +} +end_namespace_cpphibernate_misc \ No newline at end of file diff --git a/include/cpphibernate/misc/meta.h b/include/cpphibernate/misc/meta.h new file mode 100644 index 0000000..c4e8dde --- /dev/null +++ b/include/cpphibernate/misc/meta.h @@ -0,0 +1,130 @@ +#pragma once + +#include +#include +#include + +#include + +#include + +beg_namespace_cpphibernate_misc +{ + + namespace __impl + { + + /* is_container_impl */ + + template + struct is_container_impl + : public mp::c_false_t + { }; + + template + struct is_container_impl> + : public mp::c_true_t + { }; + + template + struct is_container_impl> + : public mp::c_true_t + { }; + + /* is_nullable_impl */ + + template + struct is_nullable_impl + : public mp::c_false_t + { }; + + template + struct is_nullable_impl> + : public mp::c_true_t + { }; + + template + struct is_nullable_impl> + : public mp::c_true_t + { }; + + template + struct is_nullable_impl> + : public mp::c_true_t + { }; + + /* is_pointer_impl */ + + template + struct is_pointer_impl + : public mp::c_false_t + { }; + + template + struct is_pointer_impl> + : public mp::c_true_t + { }; + + template + struct is_pointer_impl> + : public mp::c_true_t + { }; + + /* real_dataset_impl */ + + template + struct real_dataset_impl + { using type = T; }; + + template + struct real_dataset_impl, void> + { using type = typename real_dataset_impl::type; }; + + template + struct real_dataset_impl, void> + { using type = typename real_dataset_impl::type; }; + + template + struct real_dataset_impl, void> + { using type = typename real_dataset_impl::type; }; + + template + struct real_dataset_impl, void> + { using type = typename real_dataset_impl::type; }; + + template + struct real_dataset_impl, void> + { using type = typename real_dataset_impl::type; }; + + template + struct change_dataset_type_impl + { using type = T_to; }; + + template class X, typename T_from, typename T_to> + struct change_dataset_type_impl, T_to, void> + { using type = X; }; + + } + + /* meta */ + + template + struct is_container + : public __impl::is_container_impl + { }; + + template + struct is_nullable + : public __impl::is_nullable_impl + { }; + + template + struct is_pointer + : public __impl::is_pointer_impl + { }; + + template + using real_dataset_t = typename __impl::real_dataset_impl::type; + +} +end_namespace_cpphibernate_misc \ No newline at end of file diff --git a/include/cpphibernate/misc/wrap.h b/include/cpphibernate/misc/wrap.h new file mode 100644 index 0000000..f5126f2 --- /dev/null +++ b/include/cpphibernate/misc/wrap.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +#include + +#include + +beg_namespace_cpphibernate_misc +{ + + template + using unwrap_t = typename T::type; + + template + using decay_unwrap_t = typename mp::decay_t::type; + + namespace __impl + { + + struct wrap_t + { + template + constexpr decltype(auto) operator()(T) const noexcept + { return hana::type_c; } + }; + + struct unwrapped_t + { + template + constexpr decltype(auto) operator()(T) const noexcept + { return unwrap_t { }; } + }; + + } + + constexpr decltype(auto) wrap = __impl::wrap_t { }; + + constexpr decltype(auto) unwrap = __impl::unwrapped_t { }; + +} +end_namespace_cpphibernate_misc \ No newline at end of file diff --git a/include/cpphibernate/schema.h b/include/cpphibernate/schema.h new file mode 100644 index 0000000..19d699c --- /dev/null +++ b/include/cpphibernate/schema.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/include/cpphibernate/schema/attribute.h b/include/cpphibernate/schema/attribute.h new file mode 100644 index 0000000..b0df517 --- /dev/null +++ b/include/cpphibernate/schema/attribute.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* attribute_t */ + + template + struct attribute_t + : public T_inner + { + using inner_type = T_inner; + using this_type = attribute_t; + + cpphibernate_equality_comparable(); + }; + + struct hex_t { static constexpr decltype(auto) name = "hex"; }; + struct compress_t { static constexpr decltype(auto) name = "compress"; }; + struct primary_key_t { static constexpr decltype(auto) name = "primary_key"; }; + + } + + namespace attribute + { + + using hex_type = __impl::attribute_t<__impl::hex_t>; + using compress_type = __impl::attribute_t<__impl::compress_t>; + using primary_key_type = __impl::attribute_t<__impl::primary_key_t>; + + /** value is stored as hexadecimal string, and will be converted to its binary form on read */ + constexpr hex_type hex { }; + + /** value is stored as compressed binary, and will be uncompressed on read */ + constexpr compress_type compress { }; + + /** this value represents a primary key (it must be stored in the dataset to be able to do the operations on the database) */ + constexpr primary_key_type primary_key { }; + + } + + /* meta */ + + template + struct is_attribute + : public mp::is_specialization_of + { }; + + template + struct all_are_attribures + : public mp::all_true::value...> + { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/attributes.h b/include/cpphibernate/schema/attributes.h new file mode 100644 index 0000000..78ca0a4 --- /dev/null +++ b/include/cpphibernate/schema/attributes.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* attributes_t */ + + template + using attributes_t = hana::basic_tuple; + + /* is_attributes_impl */ + + template + struct is_attributes_impl + : mp::c_false_t + { }; + + template + struct is_attributes_impl, mp::enable_if>> + : mp::c_true_t + { }; + + /* attributes_builder */ + + template + struct attributes_builder + { + template + static constexpr decltype(auto) apply(T_args&&...) + { static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::make_attributes(...)!"); } + }; + + template + struct attributes_builder, mp::enable_if_c< + all_are_attribures...>::value>> + { + template + static constexpr decltype(auto) apply(T_args&&...) + { return attributes_t...> { }; } + }; + + } + + /* meta */ + + template + struct is_attributes + : public __impl::is_attributes_impl + { }; + + /* make */ + + constexpr decltype(auto) make_attributes = misc::make_generic_predicate<__impl::attributes_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/field.h b/include/cpphibernate/schema/field.h new file mode 100644 index 0000000..90deaef --- /dev/null +++ b/include/cpphibernate/schema/field.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* field_t */ + + template + struct field_t + { + using name_type = T_name; + using getter_type = T_getter; + using setter_type = T_setter; + using attributes_type = T_attributes; + using this_type = field_t; + + name_type name; + getter_type getter; + setter_type setter; + attributes_type attributes; + + constexpr field_t( + T_name&& p_name, + T_getter&& p_getter, + T_setter&& p_setter, + T_attributes&& p_attributes) + : name (std::forward (p_name)) + , getter (std::forward (p_getter)) + , setter (std::forward (p_setter)) + , attributes (std::forward(p_attributes)) + { } + + cpphibernate_copyable(field_t, delete); + cpphibernate_moveable(field_t, default); + + cpphibernate_equality_comparable(); + + inline void print(std::ostream& os) const + { + using namespace ::utl; + using value_type = typename mp::decay_t::value_type; + using dataset_type = misc::real_dataset_t; + size_t index = 0; + os << indent << '{' + << incindent + << indent << "\"name\": \"" << name << "\"," + << indent << "\"value_type\": \"" << utl::type_helper::name() << "\"" + << indent << "\"dataset_type\": \"" << utl::type_helper::name() << "\"" + << indent << "\"attributes\": " + << indent << '[' + << incindent; + hana::for_each(attributes, [&](auto& attrib){ + if (index++ > 0) os << ","; + os << indent << attrib.name; + }); + os << decindent + << indent << ']' + << decindent + << indent << '}'; + } + }; + + /* field_builder */ + + template + struct field_builder + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_field(...)!"); } + }; + + template + struct field_builder, mp::enable_if_c< + is_getter>::value + && is_setter>::value + && is_attributes>::value>> + { + using field_type = field_t; + + static constexpr decltype(auto) apply(T_name&& name, T_getter&& getter, T_setter&& setter, T_attributes&& attributes) + { return field_type(std::forward(name), std::forward(getter), std::forward(setter), std::forward(attributes)); } + }; + + } + + /* meta */ + + template + struct is_field + : public mp::is_specialization_of + { }; + + template + struct all_are_fields + : public mp::all_true::value...> + { }; + + /* make */ + + constexpr decltype(auto) make_field = misc::make_generic_predicate<__impl::field_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/fields.h b/include/cpphibernate/schema/fields.h new file mode 100644 index 0000000..8944a9d --- /dev/null +++ b/include/cpphibernate/schema/fields.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* fields_t */ + + template + using fields_t = hana::basic_tuple; + + /* is_fields_impl */ + + template + struct is_fields_impl + : public mp::c_false_t + { }; + + template + struct is_fields_impl, mp::enable_if>> + : public mp::c_true_t + { }; + + /* fields_builder */ + + template + struct fields_builder + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_fields(...)!"); } + }; + + template + struct fields_builder, mp::enable_if>> + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { return fields_t(std::forward(args)...); } + }; + + } + + /* meta */ + + template + struct is_fields : + public __impl::is_fields_impl + { }; + + /* constructors */ + + constexpr decltype(auto) make_fields = misc::make_generic_predicate<__impl::fields_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/getter.h b/include/cpphibernate/schema/getter.h new file mode 100644 index 0000000..b0e3759 --- /dev/null +++ b/include/cpphibernate/schema/getter.h @@ -0,0 +1,206 @@ +#pragma once + +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* getter_t */ + + template + struct getter_t + { + using value_type = T_value; + }; + + + /* getter_none_t */ + + struct getter_none_t + : public getter_t + { + using base_type = getter_t; + using value_type = typename base_type::value_type; + + cpphibernate_constructable(getter_none_t, default); + cpphibernate_copyable (getter_none_t, delete); + cpphibernate_moveable (getter_none_t, default); + }; + + /* getter_member_var_t */ + + template + struct getter_member_var_t + : public getter_t + { + using base_type = getter_t; + using value_type = typename base_type::value_type; + using dataset_type = T_dataset; + using member_type = T_member; + + member_type member; + + template + constexpr getter_member_var_t(X_member&& p_member) + : member(std::forward(p_member)) + { } + + cpphibernate_copyable(getter_member_var_t, delete); + cpphibernate_moveable(getter_member_var_t, default); + + template + constexpr decltype(auto) operator()(X_dataset&& data) const + { return std::forward(data).*member; } + }; + + /* getter_member_func_t */ + + template + struct getter_member_func_t + : public getter_t + { + using base_type = getter_t; + using value_type = typename base_type::value_type; + using dataset_type = T_dataset; + using member_type = T_member; + + member_type member; + + template + constexpr getter_member_func_t(X_member&& p_member) + : member(std::forward(p_member)) + { }; + + cpphibernate_copyable(getter_member_func_t, delete); + cpphibernate_moveable(getter_member_func_t, default); + + template + constexpr decltype(auto) operator()(X_dataset&& data) const + { return (std::forward(data).*member)(); } + }; + + /* getter_lambda_t */ + + template + struct getter_lambda_t + : public getter_t()(std::declval()))> + { + using base_type = getter_t()(std::declval()))>; + using value_type = typename base_type::value_type; + using dataset_type = T_dataset; + using lambda_type = T_lambda; + + lambda_type lambda; + + template + constexpr getter_lambda_t(X_lambda&& p_lambda) + : lambda(std::forward(p_lambda)) + { } + + cpphibernate_copyable(getter_lambda_t, delete); + cpphibernate_moveable(getter_lambda_t, default); + + template + constexpr decltype(auto) operator()(X_dataset&& data) const + { return lambda(std::forward(data)); } + }; + + /* is_getter_impl */ + + template + struct is_getter_impl + : public mp::c_false_t + { }; + + template + struct is_getter_impl, T>::value>> + : public mp::c_true_t + { }; + + } + + /* meta */ + + template + struct is_getter : + public __impl::is_getter_impl + { }; + + /* make */ + + constexpr decltype(auto) make_getter_none() + { return __impl::getter_none_t(); } + + template + constexpr decltype(auto) make_getter_member_var(T_value T_dataset::* member) + { return __impl::getter_member_var_t(member); } + + template + constexpr decltype(auto) make_getter_member_func(T_value (T_dataset::*member)()) + { return __impl::getter_member_func_t(member); } + + template + constexpr decltype(auto) make_getter_member_func(T_value (T_dataset::*member)() const) + { return __impl::getter_member_func_t(member); } + + template + constexpr decltype(auto) make_getter_lambda(T_lambda&& lambda, boost::hana::basic_type) + { return __impl::getter_lambda_t(std::forward(lambda)); } + + + namespace __impl + { + + /* getter_buildser */ + + template + struct getter_builder + { + template + static constexpr decltype(auto) apply(Args&&...) + { return make_getter_none(); } + }; + + template + struct getter_builder, void> + { + static constexpr decltype(auto) apply(T_value T_dataset::*member) + { return make_getter_member_var(member); } + }; + + template + struct getter_builder, void> + { + static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void)) + { return make_getter_member_func(member); } + }; + + template + struct getter_builder, void> + { + static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const) + { return make_getter_member_func(member); } + }; + + template + struct getter_builder, mp::enable_if_c< + hana::is_a> + && hana::is_a>>> + { + static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type) + { return make_getter_lambda(std::forward(func), std::forward(dataset_type), std::forward(value_type)); } + }; + + } + + /* make */ + + constexpr decltype(auto) make_getter = misc::make_generic_predicate<__impl::getter_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/macros.h b/include/cpphibernate/schema/macros.h new file mode 100644 index 0000000..0f4d720 --- /dev/null +++ b/include/cpphibernate/schema/macros.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#define cpphibernate_make_string(str) \ + #str + +#define cpphibernate_make_schema(name, ...) \ + cpphibernate::schema::make_schema( \ + cpphibernate_make_string(name), \ + cpphibernate::schema::make_tables(__VA_ARGS__)) + +#define cpphibernate_make_table_name(name, type, id, ...) \ + cpphibernate::schema::make_table( \ + cpphibernate_make_string(name), \ + boost::hana::type_c, \ + boost::hana::size_c, \ + cpphibernate::schema::make_fields(__VA_ARGS__)) + +#define cpphibernate_make_table(name, id, ...) \ + cpphibernate_make_table_name(name, name, id, __VA_ARGS__) + +#define cpphibernate_make_field_custom(name, getter, setter, ...) \ + cpphibernate::schema::make_field( \ + cpphibernate_make_string(name), \ + cpphibernate::schema::make_getter(getter), \ + cpphibernate::schema::make_setter(setter), \ + cpphibernate::schema::make_attributes(__VA_ARGS__)) + +#define cpphibernate_make_field_name(name, member_ptr, ...) \ + cpphibernate_make_field_custom( \ + name, member_ptr, member_ptr, __VA_ARGS__) + +#define cpphibernate_make_field(type, member, ...) \ + cpphibernate_make_field_name( \ + member, &type::member, __VA_ARGS__) + +#define cpphibernate_make_id(member_ptr) \ + cpphibernate_make_field_name( \ + null, \ + member_ptr, \ + cpphibernate::schema::attribute::primary_key) \ No newline at end of file diff --git a/include/cpphibernate/schema/print.h b/include/cpphibernate/schema/print.h new file mode 100644 index 0000000..42ba7e1 --- /dev/null +++ b/include/cpphibernate/schema/print.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace std +{ + + template + inline auto operator <<(basic_ostream& os, X&& x) + -> ::utl::mp::enable_if< + utl::mp::is_valid(x).print(os))>, + basic_ostream&> + { + std::forward(x).print(os); + return os; + } + +} \ No newline at end of file diff --git a/include/cpphibernate/schema/schema.h b/include/cpphibernate/schema/schema.h new file mode 100644 index 0000000..ce49b5b --- /dev/null +++ b/include/cpphibernate/schema/schema.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* schema_t */ + + template + struct schema_t + { + using name_type = T_name; + using tables_type = T_tables; + + name_type name; + tables_type tables; + + constexpr schema_t( + T_name&& p_name, + T_tables&& p_tables) + : name (std::forward (p_name)) + , tables(std::forward(p_tables)) + { } + + cpphibernate_copyable(schema_t, delete); + cpphibernate_moveable(schema_t, default); + + inline void print(std::ostream& os) const + { + using namespace ::utl; + size_t index = 0; + os << indent << '{' + << incindent + << indent << "\"name\": \"" << name << "\"," + << indent << "\"tables\": " + << indent << '[' + << incindent; + hana::for_each(tables, [&](auto& table){ + if (index++ > 0) os << ","; + table.print(os); + }); + os << decindent + << indent << ']' + << decindent + << indent << '}'; + } + }; + + /* schema_builder */ + + template + struct schema_builder + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_schema(...)!"); } + }; + + template + struct schema_builder, mp::enable_if_c< + is_tables>::value>> + { + static constexpr decltype(auto) apply(T_name&& name, T_tables&& tables) + { return schema_t(std::forward(name), std::forward(tables)); } + }; + + } + + /* meta */ + + template + struct is_schema : mp::is_specialization_of { }; + + /* make */ + + constexpr decltype(auto) make_schema = misc::make_generic_predicate<__impl::schema_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/setter.h b/include/cpphibernate/schema/setter.h new file mode 100644 index 0000000..6f26af9 --- /dev/null +++ b/include/cpphibernate/schema/setter.h @@ -0,0 +1,206 @@ +#pragma once + +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* setter_t */ + + template + struct setter_t + { + using value_type = T_value; + }; + + + /* setter_none_t */ + + struct setter_none_t + : public setter_t + { + using base_type = setter_t; + using value_type = typename base_type::value_type; + + cpphibernate_constructable(setter_none_t, default); + cpphibernate_copyable (setter_none_t, delete); + cpphibernate_moveable (setter_none_t, default); + }; + + /* setter_member_var_t */ + + template + struct setter_member_var_t + : public setter_t + { + using base_type = setter_t; + using value_type = typename base_type::value_type; + using dataset_type = T_dataset; + using member_type = T_member; + + member_type member; + + template + constexpr setter_member_var_t(X_member&& p_member) + : member(std::forward(p_member)) + { } + + cpphibernate_copyable(setter_member_var_t, delete); + cpphibernate_moveable(setter_member_var_t, default); + + template + constexpr decltype(auto) operator()(X_dataset&& data, X_value&& value) const + { return std::forward(data).*member = std::forward(value); } + }; + + /* setter_member_func_t */ + + template + struct setter_member_func_t + : public setter_t + { + using base_type = setter_t; + using value_type = typename base_type::value_type; + using dataset_type = T_dataset; + using member_type = T_member; + + member_type member; + + template + constexpr setter_member_func_t(X_member&& p_member) + : member(std::forward(p_member)) + { }; + + cpphibernate_copyable(setter_member_func_t, delete); + cpphibernate_moveable(setter_member_func_t, default); + + template + constexpr decltype(auto) operator()(X_dataset&& data, X_value&& value) const + { return (std::forward(data).*member)(std::forward(value)); } + }; + + /* setter_lambda_t */ + + template + struct setter_lambda_t + : public setter_t + { + using base_type = setter_t; + using value_type = typename base_type::value_type; + using dataset_type = T_dataset; + using lambda_type = T_lambda; + + lambda_type lambda; + + template + constexpr setter_lambda_t(X_lambda&& p_lambda) + : lambda(std::forward(p_lambda)) + { } + + cpphibernate_copyable(setter_lambda_t, delete); + cpphibernate_moveable(setter_lambda_t, default); + + template + constexpr decltype(auto) operator()(X_dataset&& data, X_value&& value) const + { return lambda(std::forward(data), std::forward(value)); } + }; + + /* is_setter_impl */ + + template + struct is_setter_impl + : public mp::c_false_t + { }; + + template + struct is_setter_impl, T>::value>> + : public mp::c_true_t + { }; + + } + + /* meta */ + + template + struct is_setter : + public __impl::is_setter_impl + { }; + + /* make */ + + constexpr decltype(auto) make_setter_none() + { return __impl::setter_none_t(); } + + template + constexpr decltype(auto) make_setter_member_var(T_value T_dataset::* member) + { return __impl::setter_member_var_t(member); } + + template + constexpr decltype(auto) make_setter_member_func(T_return (T_dataset::*member)(T_value)) + { return __impl::setter_member_func_t(member); } + + template + constexpr decltype(auto) make_setter_member_func(T_return (T_dataset::*member)(T_value) const) + { return __impl::setter_member_func_t(member); } + + template + constexpr decltype(auto) make_setter_lambda(T_lambda&& lambda, boost::hana::basic_type, boost::hana::basic_type) + { return __impl::setter_lambda_t(std::forward(lambda)); } + + + namespace __impl + { + + /* setter_buildser */ + + template + struct setter_builder + { + template + static constexpr decltype(auto) apply(Args&&...) + { return make_setter_none(); } + }; + + template + struct setter_builder, void> + { + static constexpr decltype(auto) apply(T_value T_dataset::*member) + { return make_setter_member_var(member); } + }; + + template + struct setter_builder, void> + { + static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void)) + { return make_setter_member_func(member); } + }; + + template + struct setter_builder, void> + { + static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const) + { return make_setter_member_func(member); } + }; + + template + struct setter_builder, mp::enable_if_c< + hana::is_a> + && hana::is_a>>> + { + static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type) + { return make_setter_lambda(std::forward(func), std::forward(dataset_type), std::forward(value_type)); } + }; + + } + + /* make */ + + constexpr decltype(auto) make_setter = misc::make_generic_predicate<__impl::setter_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/table.h b/include/cpphibernate/schema/table.h new file mode 100644 index 0000000..47a7aa5 --- /dev/null +++ b/include/cpphibernate/schema/table.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* table_t */ + + template + struct table_t + { + using name_type = T_name; + using dataset_wrapped_type = mp::decay_t; + using table_id_type = T_table_id; + using fields_type = T_fields; + using this_type = table_t; + + name_type name; + dataset_wrapped_type dataset_wrapped; + table_id_type table_id; + fields_type fields; + + constexpr table_t( + T_name p_name, + T_dataset_wrapped p_dataset_wrapped, + T_table_id p_table_id, + T_fields p_fields) + : name (std::forward (p_name)) + , dataset_wrapped (std::forward(p_dataset_wrapped)) + , table_id (std::forward (p_table_id)) + , fields (std::forward (p_fields)) + { } + + cpphibernate_copyable(table_t, delete); + cpphibernate_moveable(table_t, default); + + cpphibernate_equality_comparable(); + + inline void print(std::ostream& os) const + { + using namespace ::utl; + size_t index = 0; + os << indent << '{' + << incindent + << indent << "\"name\": \"" << name << "\"," + << indent << "\"dataset_wrapped\": \"" << utl::type_helper>::name() << "\"" + << indent << "\"table_id\": \"" << hana::value(table_id) << "\"" + << indent << "\"fields\": " + << indent << '[' + << incindent; + hana::for_each(fields, [&](auto& field){ + if (index++ > 0) os << ","; + field.print(os); + }); + os << decindent + << indent << ']' + << decindent + << indent << '}'; + } + }; + + /* table_builder */ + + template + struct table_builder + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_table(...)!"); } + }; + + template + struct table_builder, mp::enable_if_c< + hana::is_a + && is_fields>::value>> + { + static constexpr decltype(auto) apply(T_name&& name, T_dataset_wrapped&& dataset_wrapped, T_id&& id, T_fields&& fields) + { + return table_t( + std::forward (name), + std::forward (dataset_wrapped), + std::forward (id), + std::forward (fields)); + } + }; + + } + + /* meta */ + + template + struct is_table : mp::is_specialization_of { }; + + template + struct all_are_tables : mp::all_true::value...> { }; + + /* make */ + + constexpr decltype(auto) make_table = misc::make_generic_predicate<__impl::table_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/tables.h b/include/cpphibernate/schema/tables.h new file mode 100644 index 0000000..98df6a4 --- /dev/null +++ b/include/cpphibernate/schema/tables.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_schema +{ + + namespace __impl + { + + /* tables_t */ + + template + using tables_t = hana::tuple; + + /* is_tables_impl */ + + template + struct is_tables_impl + : mp::c_false_t + { }; + + template + struct is_tables_impl, mp::enable_if>> + : mp::c_true_t + { }; + + /* tables_builder */ + + template + struct tables_builder + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_tables(...)!"); } + }; + + template + struct tables_builder, mp::enable_if>> + { + template + static constexpr decltype(auto) apply(T_tables&&... tables) + { return tables_t(std::forward(tables)...); } + }; + + } + + /* meta */ + + template + struct is_tables + : public __impl::is_tables_impl + { }; + + /* make */ + + constexpr decltype(auto) make_tables = misc::make_generic_predicate<__impl::tables_builder> { }; + +} +end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/types.h b/include/cpphibernate/types.h new file mode 100644 index 0000000..95de8f5 --- /dev/null +++ b/include/cpphibernate/types.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#include + +#include + +beg_namespace_cpphibernate +{ + + /* string */ + + template + struct string + : public std::string + { + static constexpr decltype(auto) max_size = N; + using std::string::string; + using std::string::operator=; + }; + + /* uuid */ + + struct uuid + : public std::array + { + public: + inline uuid() + : std::array::array({ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }) + { } + + inline uuid(const std::string& str) + : std::array::array({ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }) + { + if (!from_string(str, *this)) + throw utl::argument_exception("str", "invalid uuid"); + } + + cpphibernate_copyable(uuid, default); + cpphibernate_moveable(uuid, default); + + void to_string(std::ostream& os) const; + + public: + static bool from_string(const std::string& str, uuid& val); + }; + +} +end_namespace_cpphibernate \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc616cb..a66730d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,10 @@ Set ( CMAKE_CXX_STANDARD 17 ) Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) +# Dependencies #################################################################################### + +Find_Package ( cpputils REQUIRED ) + # Project: cpphibernate ############################################################################### Project ( cpphibernate VERSION 1.0.0.0 LANGUAGES CXX ) @@ -20,6 +24,10 @@ Target_Include_Directories ( cpphibernate PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include ) +Target_Link_Libraries ( + cpphibernate + cpputils + ) If ( __COTIRE_INCLUDED ) Cotire ( cpphibernate ) EndIf ( ) diff --git a/src/types.cpp b/src/types.cpp new file mode 100644 index 0000000..7c39a8c --- /dev/null +++ b/src/types.cpp @@ -0,0 +1,54 @@ +#include + +#include + +using namespace ::cpphibernate;; + +void uuid::to_string(std::ostream& os) const +{ + os << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 0] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 1] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 2] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 3] + << '-' + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 4] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 5] + << '-' + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 6] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 7] + << '-' + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 8] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 9] + << '-' + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[10] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[11] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[12] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[13] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[14] + << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[15]; +} + +bool uuid::from_string(const std::string& str, uuid& val) +{ + const char* c = str.data(); + const char* e = c + str.size(); + size_t i = 0; + val.fill(0); + while(i < 32 && c < e) + { + if (*c >= '0' && *c <= '9') + val[i >> 1] |= ((*c - '0') << (4 * (1 - (i & 1)))); + else if (*c >= 'a' && *c <= 'f') + val[i >> 1] |= ((*c - 'a' + 10) << (4 * (1 - (i & 1)))); + else if (*c >= 'A' && *c <= 'F') + val[i >> 1] |= ((*c - 'A' + 10) << (4 * (1 - (i & 1)))); + else if (*c != '-') + return false; + if (*c != '-') + ++i; + ++c; + } + if (i != 32 || c != e) + return false; + return true; +} \ No newline at end of file diff --git a/test/cpphibernate.cpp b/test/cpphibernate.cpp new file mode 100644 index 0000000..4292225 --- /dev/null +++ b/test/cpphibernate.cpp @@ -0,0 +1,128 @@ +#include +#include + +using namespace ::cpphibernate; + +struct test1 +{ + uuid id; + std::string str_data; + string<64> str64_data; +}; + +struct test2 +{ + uuid id; + uint8_t u8_data; + int8_t i8_data; + uint16_t u16_data; + int16_t i16_data; +}; + +struct test3 +{ + uuid id; + uint32_t u32_data; + int32_t i32_data; + uint64_t u64_data; + int64_t i64_data; +}; + +struct base +{ + uuid id; + std::string name; +}; + +struct derived1 + : public base +{ + uuid derived1_id; + test1 test1_data; +}; + +struct derived2 + : public base +{ + uuid derived2_id; + utl::nullable test2_nullable; + std::unique_ptr test2_ptr_u; + std::shared_ptr test2_ptr_s; +}; + +struct derived3 + : public derived1 +{ + uuid derived3_id; + std::list test3_list; + std::vector test3_vector; +}; + +constexpr decltype(auto) test_schema = cpphibernate_make_schema( + test, + cpphibernate_make_table_name( + tbl_test1, + test1, + 1, + cpphibernate_make_id (&test1::id), + cpphibernate_make_field (test1, str_data), + cpphibernate_make_field (test1, str64_data) + ), + cpphibernate_make_table_name( + tbl_test2, + test2, + 2, + cpphibernate_make_id (&test2::id), + cpphibernate_make_field (test2, u8_data), + cpphibernate_make_field (test2, i8_data), + cpphibernate_make_field (test2, u16_data), + cpphibernate_make_field (test2, i16_data) + ), + cpphibernate_make_table_name( + tbl_test3, + test3, + 3, + cpphibernate_make_id (&test3::id), + cpphibernate_make_field (test3, u32_data), + cpphibernate_make_field (test3, i32_data), + cpphibernate_make_field (test3, u64_data), + cpphibernate_make_field (test3, i64_data) + ), + + cpphibernate_make_table_name( + tbl_base, + base, + 10, + cpphibernate_make_id (&base::id), + cpphibernate_make_field (base, name) + ), + cpphibernate_make_table_name( + tbl_derived1, + derived1, + 11, + cpphibernate_make_id (&derived1::derived1_id), + cpphibernate_make_field (derived1, test1_data) + ), + cpphibernate_make_table_name( + tbl_derived2, + derived2, + 12, + cpphibernate_make_id (&derived2::derived2_id), + cpphibernate_make_field (derived2, test2_nullable), + cpphibernate_make_field (derived2, test2_ptr_u), + cpphibernate_make_field (derived2, test2_ptr_s) + ), + cpphibernate_make_table_name( + tbl_derived3, + derived3, + 13, + cpphibernate_make_id (&derived3::derived3_id), + cpphibernate_make_field (derived3, test3_list), + cpphibernate_make_field (derived3, test3_vector) + ) +); + +TEST(CppHibernateTests, fuuu) +{ + std::cout << test_schema << std::endl; +} \ No newline at end of file