init.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright David Abrahams 2002, Joel de Guzman, 2002.
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #ifndef INIT_JDG20020820_HPP
  10. #define INIT_JDG20020820_HPP
  11. # include <boost/python/detail/prefix.hpp>
  12. #include <boost/python/detail/type_list.hpp>
  13. #include <boost/python/args_fwd.hpp>
  14. #include <boost/python/detail/make_keyword_range_fn.hpp>
  15. #include <boost/python/def_visitor.hpp>
  16. #include <boost/mpl/if.hpp>
  17. #include <boost/mpl/eval_if.hpp>
  18. #include <boost/mpl/size.hpp>
  19. #include <boost/mpl/iterator_range.hpp>
  20. #include <boost/mpl/empty.hpp>
  21. #include <boost/mpl/begin_end.hpp>
  22. #include <boost/mpl/bool.hpp>
  23. #include <boost/mpl/prior.hpp>
  24. #include <boost/mpl/joint_view.hpp>
  25. #include <boost/mpl/back.hpp>
  26. #include <boost/type_traits/is_same.hpp>
  27. #include <boost/preprocessor/enum_params_with_a_default.hpp>
  28. #include <boost/preprocessor/enum_params.hpp>
  29. #include <utility>
  30. ///////////////////////////////////////////////////////////////////////////////
  31. #define BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT \
  32. BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( \
  33. BOOST_PYTHON_MAX_ARITY, \
  34. class T, \
  35. mpl::void_) \
  36. #define BOOST_PYTHON_OVERLOAD_TYPES \
  37. BOOST_PP_ENUM_PARAMS_Z(1, \
  38. BOOST_PYTHON_MAX_ARITY, \
  39. class T) \
  40. #define BOOST_PYTHON_OVERLOAD_ARGS \
  41. BOOST_PP_ENUM_PARAMS_Z(1, \
  42. BOOST_PYTHON_MAX_ARITY, \
  43. T) \
  44. ///////////////////////////////////////////////////////////////////////////////
  45. namespace boost { namespace python {
  46. template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT>
  47. class init; // forward declaration
  48. template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT>
  49. struct optional; // forward declaration
  50. namespace detail
  51. {
  52. namespace error
  53. {
  54. template <int keywords, int init_args>
  55. struct more_keywords_than_init_arguments
  56. {
  57. typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1];
  58. };
  59. }
  60. // is_optional<T>::value
  61. //
  62. // This metaprogram checks if T is an optional
  63. //
  64. #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
  65. template <class T>
  66. struct is_optional {
  67. private:
  68. template <BOOST_PYTHON_OVERLOAD_TYPES>
  69. static boost::type_traits::yes_type f(optional<BOOST_PYTHON_OVERLOAD_ARGS>);
  70. static boost::type_traits::no_type f(...);
  71. static T t();
  72. public:
  73. BOOST_STATIC_CONSTANT(
  74. bool, value =
  75. sizeof(f(t())) == sizeof(::boost::type_traits::yes_type));
  76. typedef mpl::bool_<value> type;
  77. };
  78. #else
  79. template <class T>
  80. struct is_optional
  81. : mpl::false_
  82. {};
  83. template <BOOST_PYTHON_OVERLOAD_TYPES>
  84. struct is_optional<optional<BOOST_PYTHON_OVERLOAD_ARGS> >
  85. : mpl::true_
  86. {};
  87. #endif
  88. template <int NDefaults>
  89. struct define_class_init_helper;
  90. } // namespace detail
  91. template <class DerivedT>
  92. struct init_base : def_visitor<DerivedT>
  93. {
  94. init_base(char const* doc_, detail::keyword_range const& keywords_)
  95. : m_doc(doc_), m_keywords(keywords_)
  96. {}
  97. init_base(char const* doc_)
  98. : m_doc(doc_)
  99. {}
  100. DerivedT const& derived() const
  101. {
  102. return *static_cast<DerivedT const*>(this);
  103. }
  104. char const* doc_string() const
  105. {
  106. return m_doc;
  107. }
  108. detail::keyword_range const& keywords() const
  109. {
  110. return m_keywords;
  111. }
  112. static default_call_policies call_policies()
  113. {
  114. return default_call_policies();
  115. }
  116. private:
  117. // visit
  118. //
  119. // Defines a set of n_defaults + 1 constructors for its
  120. // class_<...> argument. Each constructor after the first has
  121. // one less argument to its right. Example:
  122. //
  123. // init<int, optional<char, long, double> >
  124. //
  125. // Defines:
  126. //
  127. // __init__(int, char, long, double)
  128. // __init__(int, char, long)
  129. // __init__(int, char)
  130. // __init__(int)
  131. template <class classT>
  132. void visit(classT& cl) const
  133. {
  134. typedef typename DerivedT::signature signature;
  135. typedef typename DerivedT::n_arguments n_arguments;
  136. typedef typename DerivedT::n_defaults n_defaults;
  137. detail::define_class_init_helper<n_defaults::value>::apply(
  138. cl
  139. , derived().call_policies()
  140. , signature()
  141. , n_arguments()
  142. , derived().doc_string()
  143. , derived().keywords());
  144. }
  145. friend class python::def_visitor_access;
  146. private: // data members
  147. char const* m_doc;
  148. detail::keyword_range m_keywords;
  149. };
  150. template <class CallPoliciesT, class InitT>
  151. class init_with_call_policies
  152. : public init_base<init_with_call_policies<CallPoliciesT, InitT> >
  153. {
  154. typedef init_base<init_with_call_policies<CallPoliciesT, InitT> > base;
  155. public:
  156. typedef typename InitT::n_arguments n_arguments;
  157. typedef typename InitT::n_defaults n_defaults;
  158. typedef typename InitT::signature signature;
  159. init_with_call_policies(
  160. CallPoliciesT const& policies_
  161. , char const* doc_
  162. , detail::keyword_range const& keywords
  163. )
  164. : base(doc_, keywords)
  165. , m_policies(policies_)
  166. {}
  167. CallPoliciesT const& call_policies() const
  168. {
  169. return this->m_policies;
  170. }
  171. private: // data members
  172. CallPoliciesT m_policies;
  173. };
  174. //
  175. // drop1<S> is the initial length(S) elements of S
  176. //
  177. namespace detail
  178. {
  179. template <class S>
  180. struct drop1
  181. : mpl::iterator_range<
  182. typename mpl::begin<S>::type
  183. , typename mpl::prior<
  184. typename mpl::end<S>::type
  185. >::type
  186. >
  187. {};
  188. }
  189. template <BOOST_PYTHON_OVERLOAD_TYPES>
  190. class init : public init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> >
  191. {
  192. typedef init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > base;
  193. public:
  194. typedef init<BOOST_PYTHON_OVERLOAD_ARGS> self_t;
  195. init(char const* doc_ = 0)
  196. : base(doc_)
  197. {
  198. }
  199. template <std::size_t N>
  200. init(char const* doc_, detail::keywords<N> const& kw)
  201. : base(doc_, kw.range())
  202. {
  203. typedef typename detail::error::more_keywords_than_init_arguments<
  204. N, n_arguments::value + 1
  205. >::too_many_keywords assertion;
  206. }
  207. template <std::size_t N>
  208. init(detail::keywords<N> const& kw, char const* doc_ = 0)
  209. : base(doc_, kw.range())
  210. {
  211. typedef typename detail::error::more_keywords_than_init_arguments<
  212. N, n_arguments::value + 1
  213. >::too_many_keywords assertion;
  214. }
  215. template <class CallPoliciesT>
  216. init_with_call_policies<CallPoliciesT, self_t>
  217. operator[](CallPoliciesT const& policies) const
  218. {
  219. return init_with_call_policies<CallPoliciesT, self_t>(
  220. policies, this->doc_string(), this->keywords());
  221. }
  222. typedef detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> signature_;
  223. typedef detail::is_optional<
  224. typename mpl::eval_if<
  225. mpl::empty<signature_>
  226. , mpl::false_
  227. , mpl::back<signature_>
  228. >::type
  229. > back_is_optional;
  230. typedef typename mpl::eval_if<
  231. back_is_optional
  232. , mpl::back<signature_>
  233. , mpl::vector0<>
  234. >::type optional_args;
  235. typedef typename mpl::eval_if<
  236. back_is_optional
  237. , mpl::if_<
  238. mpl::empty<optional_args>
  239. , detail::drop1<signature_>
  240. , mpl::joint_view<
  241. detail::drop1<signature_>
  242. , optional_args
  243. >
  244. >
  245. , signature_
  246. >::type signature;
  247. // TODO: static assert to make sure there are no other optional elements
  248. // Count the number of default args
  249. typedef mpl::size<optional_args> n_defaults;
  250. typedef mpl::size<signature> n_arguments;
  251. };
  252. ///////////////////////////////////////////////////////////////////////////////
  253. //
  254. // optional
  255. //
  256. // optional<T0...TN>::type returns a typelist.
  257. //
  258. ///////////////////////////////////////////////////////////////////////////////
  259. template <BOOST_PYTHON_OVERLOAD_TYPES>
  260. struct optional
  261. : detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS>
  262. {
  263. };
  264. namespace detail
  265. {
  266. template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
  267. inline void def_init_aux(
  268. ClassT& cl
  269. , Signature const&
  270. , NArgs
  271. , CallPoliciesT const& policies
  272. , char const* doc
  273. , detail::keyword_range const& keywords_
  274. )
  275. {
  276. cl.def(
  277. "__init__"
  278. , detail::make_keyword_range_constructor<Signature,NArgs>(
  279. policies
  280. , keywords_
  281. , (typename ClassT::metadata::holder*)0
  282. )
  283. , doc
  284. );
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////
  287. //
  288. // define_class_init_helper<N>::apply
  289. //
  290. // General case
  291. //
  292. // Accepts a class_ and an arguments list. Defines a constructor
  293. // for the class given the arguments and recursively calls
  294. // define_class_init_helper<N-1>::apply with one fewer argument (the
  295. // rightmost argument is shaved off)
  296. //
  297. ///////////////////////////////////////////////////////////////////////////////
  298. template <int NDefaults>
  299. struct define_class_init_helper
  300. {
  301. template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
  302. static void apply(
  303. ClassT& cl
  304. , CallPoliciesT const& policies
  305. , Signature const& args
  306. , NArgs
  307. , char const* doc
  308. , detail::keyword_range keywords)
  309. {
  310. detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords);
  311. if (keywords.second > keywords.first)
  312. --keywords.second;
  313. typedef typename mpl::prior<NArgs>::type next_nargs;
  314. define_class_init_helper<NDefaults-1>::apply(
  315. cl, policies, Signature(), next_nargs(), doc, keywords);
  316. }
  317. };
  318. ///////////////////////////////////////////////////////////////////////////////
  319. //
  320. // define_class_init_helper<0>::apply
  321. //
  322. // Terminal case
  323. //
  324. // Accepts a class_ and an arguments list. Defines a constructor
  325. // for the class given the arguments.
  326. //
  327. ///////////////////////////////////////////////////////////////////////////////
  328. template <>
  329. struct define_class_init_helper<0> {
  330. template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
  331. static void apply(
  332. ClassT& cl
  333. , CallPoliciesT const& policies
  334. , Signature const& args
  335. , NArgs
  336. , char const* doc
  337. , detail::keyword_range const& keywords)
  338. {
  339. detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords);
  340. }
  341. };
  342. }
  343. }} // namespace boost::python
  344. #undef BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT
  345. #undef BOOST_PYTHON_OVERLOAD_TYPES
  346. #undef BOOST_PYTHON_OVERLOAD_ARGS
  347. #undef BOOST_PYTHON_IS_OPTIONAL_VALUE
  348. #undef BOOST_PYTHON_APPEND_TO_INIT
  349. ///////////////////////////////////////////////////////////////////////////////
  350. #endif // INIT_JDG20020820_HPP