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