BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
api.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <fc/thread/future.hpp>
3 #include <functional>
4 #include <boost/any.hpp>
5 #include <boost/config.hpp>
6 
7 // ms visual c++ (as of 2013) doesn't accept the standard syntax for calling a
8 // templated member function (foo->template bar();)
9 #ifdef _MSC_VER
10 # define FC_CALL_MEMBER_TEMPLATE_KEYWORD
11 #else
12 # define FC_CALL_MEMBER_TEMPLATE_KEYWORD template
13 #endif
14 
15 namespace fc {
16  namespace detail {
18  template<typename T> struct is_optional : public std::false_type {};
19  template<typename T> struct is_optional<fc::optional<T>> : public std::true_type {};
21  template<typename... Ts> struct all_optionals;
22  template<> struct all_optionals<> : public std::true_type {};
23  template<typename T, typename... Ts> struct all_optionals<T, Ts...> : public std::false_type {};
24  template<typename T, typename... Ts> struct all_optionals<fc::optional<T>, Ts...> : public all_optionals<Ts...> {};
25 
34  template<typename R, typename... Parameters>
35  struct optionals_callable : public std::function<R(Parameters...)> {
36  using std::function<R(Parameters...)>::operator();
37 
38  template<typename... CutList>
39  struct short_pack {};
44  template<unsigned RemoveCount, typename... Types>
45  struct pack_cutter;
46  template<unsigned RemoveCount, typename, typename... Types>
48  template<typename... Types>
49  struct pack_cutter_impl<0, void, Types...> {
50  static_assert(all_optionals<Types...>::value, "All omitted arguments must correspond to optional parameters.");
51  using type = short_pack<Types...>;
52  };
53  template<unsigned RemoveCount, typename T, typename... Types>
54  struct pack_cutter_impl<RemoveCount, std::enable_if_t<RemoveCount != 0>, T, Types...>
55  : public pack_cutter_impl<RemoveCount - 1, void, Types...> {};
56  template<unsigned RemoveCount, typename... Types>
57  struct pack_cutter : public pack_cutter_impl<RemoveCount, void, Types...> {};
58  template<unsigned RemoveCount, typename... Types>
59  using pack_cutter_t = typename pack_cutter<RemoveCount, Types...>::type;
60 
61  template<typename F, typename... OptionalTypes>
63  return f(OptionalTypes()...);
64  }
65 
68  template<class... Args>
69  std::enable_if_t<sizeof...(Args) < sizeof...(Parameters), R> operator()(Args... args) {
70  // Partially apply with the arguments provided
71  auto partial_function = [this, &args...](auto&&... rest) {
72  return (*this)(std::forward<decltype(args)>(args)..., std::move(rest)...);
73  };
74  // Cut the provided arguments' types out of the Parameters list, and store the rest in a dummy type
75  pack_cutter_t<sizeof...(Args), std::decay_t<Parameters>...> dummy;
76  // Pass the partially applied function and the dummy type to another function which can deduce the optional
77  // types and call the function with default instantiations of those types
78  return call_function(std::move(partial_function), dummy);
79  }
80  };
81  }
82 
83  // This is no longer used and probably no longer can be used without generalizing the infrastructure around it, but I
84  // kept it because it is informative.
85 // struct identity_member {
86 // template<typename R, typename C, typename P, typename... Args>
87 // static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...) );
88 // template<typename R, typename C, typename P, typename... Args>
89 // static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const );
90 // };
95  template<typename R, typename C, typename P, typename... Args>
96  static detail::optionals_callable<R, Args...> functor( P&& p, R (C::*mem_func)(Args...) );
97  template<typename R, typename C, typename P, typename... Args>
98  static detail::optionals_callable<R, Args...> functor( P&& p, R (C::*mem_func)(Args...)const );
99  };
100 
101  template< typename Interface, typename Transform >
102  struct vtable : public std::enable_shared_from_this<vtable<Interface,Transform>>
103  { private: vtable(); };
104 
105  template<typename OtherType>
107  typedef OtherType other_type;
108 
109  vtable_copy_visitor( OtherType& s):_source( s ){}
110 
111  template<typename R, typename MemberPtr, typename... Args>
112  void operator()( const char* name, std::function<R(Args...)>& memb, MemberPtr m )const {
113  OtherType* src = &_source;
114  memb = [src,m]( Args... args ){ return (src->*m)(args...); };
115  }
116  OtherType& _source;
117  };
118 
119  template<typename Interface, typename Transform >
120  class api;
121 
123 
124  typedef uint32_t api_id_type;
125 
126  class api_base
127  {
128  public:
129  api_base() {}
130  virtual ~api_base() {}
131 
132  virtual uint64_t get_handle()const = 0;
133 
134  virtual api_id_type register_api( api_connection& conn )const = 0;
135 
136  // defined in api_connection.hpp
137  template< typename T >
139  };
140  typedef std::shared_ptr< api_base > api_ptr;
141 
142  class api_connection;
143 
144  template<typename Interface, typename Transform = identity_member_with_optionals >
145  class api : public api_base {
146  public:
148 
149  api():_vtable( std::make_shared<vtable_type>() ) {}
150 
152  template<typename T >
153  api( const T& p )
154  :_vtable( std::make_shared<vtable_type>() )
155  {
156  _data = std::make_shared<boost::any>(p);
157  T& ptr = boost::any_cast<T&>(*_data);
158  auto& pointed_at = *ptr;
159  typedef typename std::remove_reference<decltype(pointed_at)>::type source_vtable_type;
160  _vtable->FC_CALL_MEMBER_TEMPLATE_KEYWORD visit_other( vtable_copy_visitor<source_vtable_type>(pointed_at) );
161  }
162 
163  api( const api& cpy ):_vtable(cpy._vtable),_data(cpy._data) {}
164  virtual ~api() {}
165 
166  friend bool operator == ( const api& a, const api& b ) { return a._data == b._data && a._vtable == b._vtable; }
167  friend bool operator != ( const api& a, const api& b ) { return !(a._data == b._data && a._vtable == b._vtable); }
168  virtual uint64_t get_handle()const override { return uint64_t(_data.get()); }
169  virtual api_id_type register_api( api_connection& conn )const override; // defined in api_connection.hpp
170 
171  vtable_type& operator*()const { FC_ASSERT( _vtable ); return *_vtable; }
172  vtable_type* operator->()const { FC_ASSERT( _vtable ); return _vtable.get(); }
173 
174  protected:
175  std::shared_ptr<vtable_type> _vtable;
176  std::shared_ptr<boost::any> _data;
177  };
178 
179 } // namespace fc
180 
181 #include <boost/preprocessor/repeat.hpp>
182 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
183 #include <boost/preprocessor/repetition/enum_params.hpp>
184 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
185 #include <boost/preprocessor/facilities/empty.hpp>
186 #include <boost/preprocessor/seq/for_each.hpp>
187 #include <boost/preprocessor/stringize.hpp>
188 
189 #define FC_API_VTABLE_DEFINE_MEMBER( r, data, elem ) \
190  decltype(Transform::functor( (data*)nullptr, &data::elem)) elem;
191 #define FC_API_VTABLE_DEFINE_VISIT_OTHER( r, data, elem ) \
192  { typedef typename Visitor::other_type OtherType; \
193  v( BOOST_PP_STRINGIZE(elem), elem, &OtherType::elem ); }
194 #define FC_API_VTABLE_DEFINE_VISIT( r, data, elem ) \
195  v( BOOST_PP_STRINGIZE(elem), elem );
196 
197 #define FC_API( CLASS, METHODS ) \
198 namespace fc { \
199  template<typename Transform> \
200  struct vtable<CLASS,Transform> : public std::enable_shared_from_this<vtable<CLASS,Transform>> { \
201  BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_MEMBER, CLASS, METHODS ) \
202  template<typename Visitor> \
203  void visit_other( Visitor&& v ){ \
204  BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT_OTHER, CLASS, METHODS ) \
205  } \
206  template<typename Visitor> \
207  void visit( Visitor&& v ){ \
208  BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT, CLASS, METHODS ) \
209  } \
210  }; \
211 }
212 
fc::vtable_copy_visitor::vtable_copy_visitor
vtable_copy_visitor(OtherType &s)
Definition: api.hpp:109
fc::api_base::get_handle
virtual uint64_t get_handle() const =0
fc::api_base::as
api< T, identity_member_with_optionals > as()
fc::detail::is_optional
This metafunction determines whether its template argument is an instantiation of fc::optional.
Definition: api.hpp:18
fc::detail::optionals_callable::call_function
R call_function(F &&f, short_pack< OptionalTypes... >)
Definition: api.hpp:62
fc::detail::optionals_callable::pack_cutter_t
typename pack_cutter< RemoveCount, Types... >::type pack_cutter_t
Definition: api.hpp:59
fc::vtable_copy_visitor::other_type
OtherType other_type
Definition: api.hpp:107
fc
Definition: api.hpp:15
fc::api_id_type
uint32_t api_id_type
Definition: api.hpp:122
fc::vtable_copy_visitor::operator()
void operator()(const char *name, std::function< R(Args...)> &memb, MemberPtr m) const
Definition: api.hpp:112
fc::api::operator!=
friend bool operator!=(const api &a, const api &b)
Definition: api.hpp:167
fc::api_base
Definition: api.hpp:126
fc::api::operator==
friend bool operator==(const api &a, const api &b)
Definition: api.hpp:166
fc::api::_data
std::shared_ptr< boost::any > _data
Definition: api.hpp:176
fc::vtable_copy_visitor
Definition: api.hpp:106
fc::detail::all_optionals
This metafunction determines whether all of its template arguments are instantiations of fc::optional...
Definition: api.hpp:21
fc::api::api
api()
Definition: api.hpp:149
fc::detail::optionals_callable
Definition: api.hpp:35
fc::vtable
Definition: api.hpp:102
fc::api::operator->
vtable_type * operator->() const
Definition: api.hpp:172
fc::api::api
api(const T &p)
Definition: api.hpp:153
fc::api::get_handle
virtual uint64_t get_handle() const override
Definition: api.hpp:168
fc::api_base::api_base
api_base()
Definition: api.hpp:129
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
fc::identity_member_with_optionals
Definition: api.hpp:94
fc::api_ptr
std::shared_ptr< api_base > api_ptr
Definition: api.hpp:140
future.hpp
fc::api::operator*
vtable_type & operator*() const
Definition: api.hpp:171
fc::api::api
api(const api &cpy)
Definition: api.hpp:163
std
Definition: zeroed_array.hpp:76
fc::api::_vtable
std::shared_ptr< vtable_type > _vtable
Definition: api.hpp:175
fc::identity_member_with_optionals::functor
static detail::optionals_callable< R, Args... > functor(P &&p, R(C::*mem_func)(Args...))
fc::api::vtable_type
vtable< Interface, Transform > vtable_type
Definition: api.hpp:147
fc::detail::optionals_callable::pack_cutter
Definition: api.hpp:45
fc::optional
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
fc::api::register_api
virtual api_id_type register_api(api_connection &conn) const override
Definition: api_connection.hpp:508
fc::vtable_copy_visitor::_source
OtherType & _source
Definition: api.hpp:116
fc::api_base::~api_base
virtual ~api_base()
Definition: api.hpp:130
fc::api_connection
Definition: api_connection.hpp:240
fc::api_base::register_api
virtual api_id_type register_api(api_connection &conn) const =0
fc::detail::optionals_callable::pack_cutter_impl
Definition: api.hpp:47
fc::api
Definition: api.hpp:120
fc::detail::optionals_callable::short_pack
Definition: api.hpp:39
fc::api::~api
virtual ~api()
Definition: api.hpp:164