From d5d03ea3e7591d0d10803dbbd63245494ba1ab95 Mon Sep 17 00:00:00 2001 From: stefanseefeld Date: Fri, 25 Dec 2020 18:34:38 +0000 Subject: [PATCH] deploy: 45e28cc0346f7c1c7588a860c218426cbc1cb05b --- doc/develop/html/HTML.manifest | 31 + doc/develop/html/article.html | 929 ++ doc/develop/html/boostbook.css | 716 ++ doc/develop/html/building.html | 61 + doc/develop/html/building/background.html | 70 + .../choosing_a_boost_python_library_.html | 128 + .../building/configuring_boost_build.html | 264 + doc/develop/html/building/include_issues.html | 53 + .../installing_boost_python_on_your_.html | 52 + .../html/building/no_install_quickstart.html | 318 + .../notes_for_mingw_and_cygwin_with_.html | 47 + .../building/python_debugging_builds.html | 78 + .../html/building/testing_boost_python.html | 42 + doc/develop/html/configuration.html | 340 + doc/develop/html/faq.html | 84 + .../faq/compilation_takes_too_much_time_.html | 42 + .../faq/does_boost_python_work_with_mac_.html | 93 + .../faq/error_c2064_term_does_not_evalua.html | 77 + .../faq/fatal_error_c1204_compiler_limit.html | 96 + .../faq/how_can_i_automatically_convert_.html | 146 + .../faq/how_can_i_find_the_existing_pyob.html | 103 + .../faq/how_can_i_wrap_a_function_which0.html | 86 + .../faq/how_can_i_wrap_functions_which_t.html | 124 + .../faq/how_do_i_create_sub_packages_usi.html | 41 + .../faq/how_do_i_debug_my_python_extensi.html | 151 + .../faq/i_m_getting_the_attempt_to_retur.html | 67 + .../faq/is_boost_python_thread_aware_com.html | 60 + .../faq/is_return_internal_reference_eff.html | 62 + .../faq/why_doesn_t_my_operator_work.html | 63 + .../faq/why_is_my_automatic_to_python_co.html | 67 + doc/develop/html/glossary.html | 81 + doc/develop/html/images/alert.png | Bin 0 -> 603 bytes doc/develop/html/images/blank.png | Bin 0 -> 374 bytes doc/develop/html/images/boost.png | Bin 0 -> 6308 bytes doc/develop/html/images/bpl.png | Bin 0 -> 21289 bytes doc/develop/html/images/bpl.svg | 224 + doc/develop/html/images/callouts/1.png | Bin 0 -> 391 bytes doc/develop/html/images/callouts/1.svg | 15 + doc/develop/html/images/callouts/10.png | Bin 0 -> 485 bytes doc/develop/html/images/callouts/10.svg | 18 + doc/develop/html/images/callouts/11.png | Bin 0 -> 410 bytes doc/develop/html/images/callouts/11.svg | 16 + doc/develop/html/images/callouts/12.png | Bin 0 -> 488 bytes doc/develop/html/images/callouts/12.svg | 18 + doc/develop/html/images/callouts/13.png | Bin 0 -> 509 bytes doc/develop/html/images/callouts/13.svg | 20 + doc/develop/html/images/callouts/14.png | Bin 0 -> 499 bytes doc/develop/html/images/callouts/14.svg | 17 + doc/develop/html/images/callouts/15.png | Bin 0 -> 507 bytes doc/develop/html/images/callouts/15.svg | 19 + doc/develop/html/images/callouts/16.svg | 20 + doc/develop/html/images/callouts/17.svg | 17 + doc/develop/html/images/callouts/18.svg | 21 + doc/develop/html/images/callouts/19.svg | 20 + doc/develop/html/images/callouts/2.png | Bin 0 -> 446 bytes doc/develop/html/images/callouts/2.svg | 17 + doc/develop/html/images/callouts/20.svg | 20 + doc/develop/html/images/callouts/21.svg | 18 + doc/develop/html/images/callouts/22.svg | 20 + doc/develop/html/images/callouts/23.svg | 22 + doc/develop/html/images/callouts/24.svg | 19 + doc/develop/html/images/callouts/25.svg | 21 + doc/develop/html/images/callouts/26.svg | 22 + doc/develop/html/images/callouts/27.svg | 19 + doc/develop/html/images/callouts/28.svg | 23 + doc/develop/html/images/callouts/29.svg | 22 + doc/develop/html/images/callouts/3.png | Bin 0 -> 431 bytes doc/develop/html/images/callouts/3.svg | 19 + doc/develop/html/images/callouts/30.svg | 22 + doc/develop/html/images/callouts/4.png | Bin 0 -> 441 bytes doc/develop/html/images/callouts/4.svg | 16 + doc/develop/html/images/callouts/5.png | Bin 0 -> 423 bytes doc/develop/html/images/callouts/5.svg | 18 + doc/develop/html/images/callouts/6.png | Bin 0 -> 431 bytes doc/develop/html/images/callouts/6.svg | 19 + doc/develop/html/images/callouts/7.png | Bin 0 -> 397 bytes doc/develop/html/images/callouts/7.svg | 16 + doc/develop/html/images/callouts/8.png | Bin 0 -> 434 bytes doc/develop/html/images/callouts/8.svg | 20 + doc/develop/html/images/callouts/9.png | Bin 0 -> 420 bytes doc/develop/html/images/callouts/9.svg | 19 + doc/develop/html/images/caution.png | Bin 0 -> 1250 bytes doc/develop/html/images/caution.svg | 68 + doc/develop/html/images/draft.png | Bin 0 -> 17454 bytes doc/develop/html/images/home.png | Bin 0 -> 358 bytes doc/develop/html/images/home.svg | 26 + doc/develop/html/images/important.png | Bin 0 -> 722 bytes doc/develop/html/images/important.svg | 25 + doc/develop/html/images/jam.png | Bin 0 -> 3884 bytes doc/develop/html/images/next.png | Bin 0 -> 336 bytes doc/develop/html/images/next.svg | 19 + doc/develop/html/images/next_disabled.png | Bin 0 -> 1110 bytes doc/develop/html/images/note.png | Bin 0 -> 490 bytes doc/develop/html/images/note.svg | 33 + doc/develop/html/images/prev.png | Bin 0 -> 334 bytes doc/develop/html/images/prev.svg | 19 + doc/develop/html/images/prev_disabled.png | Bin 0 -> 1109 bytes doc/develop/html/images/smiley.png | Bin 0 -> 867 bytes doc/develop/html/images/tip.png | Bin 0 -> 449 bytes doc/develop/html/images/tip.svg | 84 + doc/develop/html/images/toc-blank.png | Bin 0 -> 318 bytes doc/develop/html/images/toc-minus.png | Bin 0 -> 259 bytes doc/develop/html/images/toc-plus.png | Bin 0 -> 264 bytes doc/develop/html/images/up.png | Bin 0 -> 370 bytes doc/develop/html/images/up.svg | 19 + doc/develop/html/images/up_disabled.png | Bin 0 -> 1115 bytes doc/develop/html/images/warning.png | Bin 0 -> 1241 bytes doc/develop/html/images/warning.svg | 23 + doc/develop/html/index.html | 135 + doc/develop/html/numpy/.buildinfo | 4 + .../html/numpy/.doctrees/environment.pickle | Bin 0 -> 27164 bytes .../html/numpy/.doctrees/index.doctree | Bin 0 -> 3428 bytes .../.doctrees/reference/binary_ufunc.doctree | Bin 0 -> 16921 bytes .../numpy/.doctrees/reference/dtype.doctree | Bin 0 -> 13370 bytes .../numpy/.doctrees/reference/index.doctree | Bin 0 -> 2836 bytes .../.doctrees/reference/multi_iter.doctree | Bin 0 -> 12284 bytes .../numpy/.doctrees/reference/ndarray.doctree | Bin 0 -> 61651 bytes .../.doctrees/reference/unary_ufunc.doctree | Bin 0 -> 15587 bytes .../numpy/.doctrees/tutorial/dtype.doctree | Bin 0 -> 9323 bytes .../numpy/.doctrees/tutorial/fromdata.doctree | Bin 0 -> 8007 bytes .../numpy/.doctrees/tutorial/index.doctree | Bin 0 -> 2811 bytes .../numpy/.doctrees/tutorial/ndarray.doctree | Bin 0 -> 15759 bytes .../numpy/.doctrees/tutorial/simple.doctree | Bin 0 -> 6522 bytes .../numpy/.doctrees/tutorial/ufunc.doctree | Bin 0 -> 14292 bytes doc/develop/html/numpy/_sources/index.rst.txt | 14 + .../_sources/reference/binary_ufunc.rst.txt | 110 + .../numpy/_sources/reference/dtype.rst.txt | 92 + .../numpy/_sources/reference/index.rst.txt | 12 + .../_sources/reference/multi_iter.rst.txt | 94 + .../numpy/_sources/reference/ndarray.rst.txt | 382 + .../_sources/reference/unary_ufunc.rst.txt | 103 + .../numpy/_sources/tutorial/dtype.rst.txt | 54 + .../numpy/_sources/tutorial/fromdata.rst.txt | 56 + .../numpy/_sources/tutorial/index.rst.txt | 12 + .../numpy/_sources/tutorial/ndarray.rst.txt | 99 + .../numpy/_sources/tutorial/simple.rst.txt | 41 + .../numpy/_sources/tutorial/ufunc.rst.txt | 120 + doc/develop/html/numpy/_static/basic.css | 676 + doc/develop/html/numpy/_static/boost.css | 716 ++ doc/develop/html/numpy/_static/boost.png | Bin 0 -> 6308 bytes doc/develop/html/numpy/_static/bpl.png | Bin 0 -> 21289 bytes doc/develop/html/numpy/_static/classic.css | 261 + doc/develop/html/numpy/_static/default.css | 1 + doc/develop/html/numpy/_static/doctools.js | 315 + .../numpy/_static/documentation_options.js | 10 + doc/develop/html/numpy/_static/file.png | Bin 0 -> 286 bytes doc/develop/html/numpy/_static/home.png | Bin 0 -> 358 bytes doc/develop/html/numpy/_static/jquery.js | 10365 ++++++++++++++++ .../html/numpy/_static/language_data.js | 297 + doc/develop/html/numpy/_static/minus.png | Bin 0 -> 90 bytes doc/develop/html/numpy/_static/next.png | Bin 0 -> 336 bytes doc/develop/html/numpy/_static/plus.png | Bin 0 -> 90 bytes doc/develop/html/numpy/_static/prev.png | Bin 0 -> 334 bytes doc/develop/html/numpy/_static/pygments.css | 69 + doc/develop/html/numpy/_static/searchtools.js | 481 + doc/develop/html/numpy/_static/sidebar.js | 159 + doc/develop/html/numpy/_static/style.css | 38 + doc/develop/html/numpy/_static/underscore.js | 1692 +++ doc/develop/html/numpy/_static/up.png | Bin 0 -> 370 bytes doc/develop/html/numpy/genindex.html | 80 + doc/develop/html/numpy/index.html | 99 + doc/develop/html/numpy/objects.inv | Bin 0 -> 483 bytes .../html/numpy/reference/binary_ufunc.html | 212 + doc/develop/html/numpy/reference/dtype.html | 196 + doc/develop/html/numpy/reference/index.html | 120 + .../html/numpy/reference/multi_iter.html | 212 + doc/develop/html/numpy/reference/ndarray.html | 629 + .../html/numpy/reference/unary_ufunc.html | 203 + doc/develop/html/numpy/search.html | 93 + doc/develop/html/numpy/searchindex.js | 1 + doc/develop/html/numpy/tutorial/dtype.html | 133 + doc/develop/html/numpy/tutorial/fromdata.html | 136 + doc/develop/html/numpy/tutorial/index.html | 91 + doc/develop/html/numpy/tutorial/ndarray.html | 179 + doc/develop/html/numpy/tutorial/simple.html | 121 + doc/develop/html/numpy/tutorial/ufunc.html | 199 + doc/develop/html/reference/HTML.manifest | 58 + doc/develop/html/reference/concepts.html | 261 + .../reference/concepts/dereferenceable.html | 104 + .../html/reference/concepts/extractor.html | 135 + .../reference/concepts/holdergenerator.html | 92 + .../reference/concepts/objectwrapper.html | 132 + .../reference/concepts/resultconverter.html | 210 + doc/develop/html/reference/embedding.html | 205 + .../embedding/boost_python_import_hpp.html | 94 + .../function_invocation_and_creation.html | 287 + .../boost_python_call_hpp.html | 96 + .../boost_python_call_method_hpp.html | 156 + .../boost_python_data_members_hpp.html | 215 + .../boost_python_make_function_hpp.html | 194 + .../boost_python_overloads_hpp.html | 208 + .../boost_python_ptr_hpp.html | 287 + .../boost_python_raw_function_hpp.html | 111 + .../function_documentation.html | 458 + .../models_of_callpolicies.html | 1098 ++ .../models_of_resultconverter.html | 308 + .../models_of_resultconvertergenerat.html | 683 + doc/develop/html/reference/glossary.html | 80 + .../html/reference/high_level_components.html | 1090 ++ .../boost_python_def_hpp.html | 220 + .../boost_python_def_visitor_hpp.html | 208 + .../boost_python_docstring_options_h.html | 363 + .../boost_python_enum_hpp.html | 217 + .../boost_python_errors_hpp.html | 278 + .../boost_python_exception_translato.html | 130 + .../boost_python_init_hpp.html | 233 + .../boost_python_iterator_hpp.html | 398 + .../boost_python_module_hpp.html | 111 + .../boost_python_operators_hpp.html | 1558 +++ .../boost_python_scope_hpp.html | 160 + .../boost_python_stl_iterator_hpp.html | 311 + .../boost_python_wrapper_hpp.html | 222 + doc/develop/html/reference/index.html | 136 + .../html/reference/object_wrappers.html | 249 + .../boost_python_list_hpp.html | 120 + .../boost_python_long_hpp.html | 97 + .../boost_python_object_hpp.html | 1148 ++ .../boost_python_slice_hpp.html | 297 + .../object_wrappers/boost_python_str_hpp.html | 211 + .../boost_python_tuple_hpp.html | 119 + .../to_from_python_type_conversion.html | 287 + .../boost_python_implicit_hpp.html | 181 + .../boost_python_lvalue_from_pytype_.html | 305 + .../boost_python_opaque_pointer_conv.html | 118 + .../boost_python_register_ptr_to_pyt.html | 166 + .../boost_python_to_python_converter.html | 252 + doc/develop/html/reference/topics.html | 332 + .../reference/topics/indexing_support.html | 832 ++ .../html/reference/topics/pickle_support.html | 356 + .../reference/utility_and_infrastructure.html | 240 + .../boost_python_handle_hpp.html | 363 + .../boost_python_instance_holder_hpp.html | 212 + .../boost_python_pointee_hpp.html | 106 + .../boost_python_ssize_t_hpp.html | 90 + .../boost_python_type_id_hpp.html | 234 + doc/develop/html/rn.html | 47 + doc/develop/html/support.html | 85 + doc/develop/html/tutorial/HTML.manifest | 9 + doc/develop/html/tutorial/index.html | 149 + .../html/tutorial/tutorial/embedding.html | 273 + .../html/tutorial/tutorial/exception.html | 56 + .../html/tutorial/tutorial/exposing.html | 601 + .../html/tutorial/tutorial/functions.html | 587 + doc/develop/html/tutorial/tutorial/hello.html | 191 + .../html/tutorial/tutorial/iterators.html | 180 + .../html/tutorial/tutorial/object.html | 366 + .../html/tutorial/tutorial/techniques.html | 397 + 247 files changed, 45160 insertions(+) create mode 100644 doc/develop/html/HTML.manifest create mode 100644 doc/develop/html/article.html create mode 100644 doc/develop/html/boostbook.css create mode 100644 doc/develop/html/building.html create mode 100644 doc/develop/html/building/background.html create mode 100644 doc/develop/html/building/choosing_a_boost_python_library_.html create mode 100644 doc/develop/html/building/configuring_boost_build.html create mode 100644 doc/develop/html/building/include_issues.html create mode 100644 doc/develop/html/building/installing_boost_python_on_your_.html create mode 100644 doc/develop/html/building/no_install_quickstart.html create mode 100644 doc/develop/html/building/notes_for_mingw_and_cygwin_with_.html create mode 100644 doc/develop/html/building/python_debugging_builds.html create mode 100644 doc/develop/html/building/testing_boost_python.html create mode 100644 doc/develop/html/configuration.html create mode 100644 doc/develop/html/faq.html create mode 100644 doc/develop/html/faq/compilation_takes_too_much_time_.html create mode 100644 doc/develop/html/faq/does_boost_python_work_with_mac_.html create mode 100644 doc/develop/html/faq/error_c2064_term_does_not_evalua.html create mode 100644 doc/develop/html/faq/fatal_error_c1204_compiler_limit.html create mode 100644 doc/develop/html/faq/how_can_i_automatically_convert_.html create mode 100644 doc/develop/html/faq/how_can_i_find_the_existing_pyob.html create mode 100644 doc/develop/html/faq/how_can_i_wrap_a_function_which0.html create mode 100644 doc/develop/html/faq/how_can_i_wrap_functions_which_t.html create mode 100644 doc/develop/html/faq/how_do_i_create_sub_packages_usi.html create mode 100644 doc/develop/html/faq/how_do_i_debug_my_python_extensi.html create mode 100644 doc/develop/html/faq/i_m_getting_the_attempt_to_retur.html create mode 100644 doc/develop/html/faq/is_boost_python_thread_aware_com.html create mode 100644 doc/develop/html/faq/is_return_internal_reference_eff.html create mode 100644 doc/develop/html/faq/why_doesn_t_my_operator_work.html create mode 100644 doc/develop/html/faq/why_is_my_automatic_to_python_co.html create mode 100644 doc/develop/html/glossary.html create mode 100644 doc/develop/html/images/alert.png create mode 100644 doc/develop/html/images/blank.png create mode 100644 doc/develop/html/images/boost.png create mode 100644 doc/develop/html/images/bpl.png create mode 100644 doc/develop/html/images/bpl.svg create mode 100644 doc/develop/html/images/callouts/1.png create mode 100644 doc/develop/html/images/callouts/1.svg create mode 100644 doc/develop/html/images/callouts/10.png create mode 100644 doc/develop/html/images/callouts/10.svg create mode 100644 doc/develop/html/images/callouts/11.png create mode 100644 doc/develop/html/images/callouts/11.svg create mode 100644 doc/develop/html/images/callouts/12.png create mode 100644 doc/develop/html/images/callouts/12.svg create mode 100644 doc/develop/html/images/callouts/13.png create mode 100644 doc/develop/html/images/callouts/13.svg create mode 100644 doc/develop/html/images/callouts/14.png create mode 100644 doc/develop/html/images/callouts/14.svg create mode 100644 doc/develop/html/images/callouts/15.png create mode 100644 doc/develop/html/images/callouts/15.svg create mode 100644 doc/develop/html/images/callouts/16.svg create mode 100644 doc/develop/html/images/callouts/17.svg create mode 100644 doc/develop/html/images/callouts/18.svg create mode 100644 doc/develop/html/images/callouts/19.svg create mode 100644 doc/develop/html/images/callouts/2.png create mode 100644 doc/develop/html/images/callouts/2.svg create mode 100644 doc/develop/html/images/callouts/20.svg create mode 100644 doc/develop/html/images/callouts/21.svg create mode 100644 doc/develop/html/images/callouts/22.svg create mode 100644 doc/develop/html/images/callouts/23.svg create mode 100644 doc/develop/html/images/callouts/24.svg create mode 100644 doc/develop/html/images/callouts/25.svg create mode 100644 doc/develop/html/images/callouts/26.svg create mode 100644 doc/develop/html/images/callouts/27.svg create mode 100644 doc/develop/html/images/callouts/28.svg create mode 100644 doc/develop/html/images/callouts/29.svg create mode 100644 doc/develop/html/images/callouts/3.png create mode 100644 doc/develop/html/images/callouts/3.svg create mode 100644 doc/develop/html/images/callouts/30.svg create mode 100644 doc/develop/html/images/callouts/4.png create mode 100644 doc/develop/html/images/callouts/4.svg create mode 100644 doc/develop/html/images/callouts/5.png create mode 100644 doc/develop/html/images/callouts/5.svg create mode 100644 doc/develop/html/images/callouts/6.png create mode 100644 doc/develop/html/images/callouts/6.svg create mode 100644 doc/develop/html/images/callouts/7.png create mode 100644 doc/develop/html/images/callouts/7.svg create mode 100644 doc/develop/html/images/callouts/8.png create mode 100644 doc/develop/html/images/callouts/8.svg create mode 100644 doc/develop/html/images/callouts/9.png create mode 100644 doc/develop/html/images/callouts/9.svg create mode 100644 doc/develop/html/images/caution.png create mode 100644 doc/develop/html/images/caution.svg create mode 100644 doc/develop/html/images/draft.png create mode 100644 doc/develop/html/images/home.png create mode 100644 doc/develop/html/images/home.svg create mode 100644 doc/develop/html/images/important.png create mode 100644 doc/develop/html/images/important.svg create mode 100644 doc/develop/html/images/jam.png create mode 100644 doc/develop/html/images/next.png create mode 100644 doc/develop/html/images/next.svg create mode 100644 doc/develop/html/images/next_disabled.png create mode 100644 doc/develop/html/images/note.png create mode 100644 doc/develop/html/images/note.svg create mode 100644 doc/develop/html/images/prev.png create mode 100644 doc/develop/html/images/prev.svg create mode 100644 doc/develop/html/images/prev_disabled.png create mode 100644 doc/develop/html/images/smiley.png create mode 100644 doc/develop/html/images/tip.png create mode 100644 doc/develop/html/images/tip.svg create mode 100644 doc/develop/html/images/toc-blank.png create mode 100644 doc/develop/html/images/toc-minus.png create mode 100644 doc/develop/html/images/toc-plus.png create mode 100644 doc/develop/html/images/up.png create mode 100644 doc/develop/html/images/up.svg create mode 100644 doc/develop/html/images/up_disabled.png create mode 100644 doc/develop/html/images/warning.png create mode 100644 doc/develop/html/images/warning.svg create mode 100644 doc/develop/html/index.html create mode 100644 doc/develop/html/numpy/.buildinfo create mode 100644 doc/develop/html/numpy/.doctrees/environment.pickle create mode 100644 doc/develop/html/numpy/.doctrees/index.doctree create mode 100644 doc/develop/html/numpy/.doctrees/reference/binary_ufunc.doctree create mode 100644 doc/develop/html/numpy/.doctrees/reference/dtype.doctree create mode 100644 doc/develop/html/numpy/.doctrees/reference/index.doctree create mode 100644 doc/develop/html/numpy/.doctrees/reference/multi_iter.doctree create mode 100644 doc/develop/html/numpy/.doctrees/reference/ndarray.doctree create mode 100644 doc/develop/html/numpy/.doctrees/reference/unary_ufunc.doctree create mode 100644 doc/develop/html/numpy/.doctrees/tutorial/dtype.doctree create mode 100644 doc/develop/html/numpy/.doctrees/tutorial/fromdata.doctree create mode 100644 doc/develop/html/numpy/.doctrees/tutorial/index.doctree create mode 100644 doc/develop/html/numpy/.doctrees/tutorial/ndarray.doctree create mode 100644 doc/develop/html/numpy/.doctrees/tutorial/simple.doctree create mode 100644 doc/develop/html/numpy/.doctrees/tutorial/ufunc.doctree create mode 100644 doc/develop/html/numpy/_sources/index.rst.txt create mode 100644 doc/develop/html/numpy/_sources/reference/binary_ufunc.rst.txt create mode 100644 doc/develop/html/numpy/_sources/reference/dtype.rst.txt create mode 100644 doc/develop/html/numpy/_sources/reference/index.rst.txt create mode 100644 doc/develop/html/numpy/_sources/reference/multi_iter.rst.txt create mode 100644 doc/develop/html/numpy/_sources/reference/ndarray.rst.txt create mode 100644 doc/develop/html/numpy/_sources/reference/unary_ufunc.rst.txt create mode 100644 doc/develop/html/numpy/_sources/tutorial/dtype.rst.txt create mode 100644 doc/develop/html/numpy/_sources/tutorial/fromdata.rst.txt create mode 100644 doc/develop/html/numpy/_sources/tutorial/index.rst.txt create mode 100644 doc/develop/html/numpy/_sources/tutorial/ndarray.rst.txt create mode 100644 doc/develop/html/numpy/_sources/tutorial/simple.rst.txt create mode 100644 doc/develop/html/numpy/_sources/tutorial/ufunc.rst.txt create mode 100644 doc/develop/html/numpy/_static/basic.css create mode 100644 doc/develop/html/numpy/_static/boost.css create mode 100644 doc/develop/html/numpy/_static/boost.png create mode 100644 doc/develop/html/numpy/_static/bpl.png create mode 100644 doc/develop/html/numpy/_static/classic.css create mode 100644 doc/develop/html/numpy/_static/default.css create mode 100644 doc/develop/html/numpy/_static/doctools.js create mode 100644 doc/develop/html/numpy/_static/documentation_options.js create mode 100644 doc/develop/html/numpy/_static/file.png create mode 100644 doc/develop/html/numpy/_static/home.png create mode 100644 doc/develop/html/numpy/_static/jquery.js create mode 100644 doc/develop/html/numpy/_static/language_data.js create mode 100644 doc/develop/html/numpy/_static/minus.png create mode 100644 doc/develop/html/numpy/_static/next.png create mode 100644 doc/develop/html/numpy/_static/plus.png create mode 100644 doc/develop/html/numpy/_static/prev.png create mode 100644 doc/develop/html/numpy/_static/pygments.css create mode 100644 doc/develop/html/numpy/_static/searchtools.js create mode 100644 doc/develop/html/numpy/_static/sidebar.js create mode 100644 doc/develop/html/numpy/_static/style.css create mode 100644 doc/develop/html/numpy/_static/underscore.js create mode 100644 doc/develop/html/numpy/_static/up.png create mode 100644 doc/develop/html/numpy/genindex.html create mode 100644 doc/develop/html/numpy/index.html create mode 100644 doc/develop/html/numpy/objects.inv create mode 100644 doc/develop/html/numpy/reference/binary_ufunc.html create mode 100644 doc/develop/html/numpy/reference/dtype.html create mode 100644 doc/develop/html/numpy/reference/index.html create mode 100644 doc/develop/html/numpy/reference/multi_iter.html create mode 100644 doc/develop/html/numpy/reference/ndarray.html create mode 100644 doc/develop/html/numpy/reference/unary_ufunc.html create mode 100644 doc/develop/html/numpy/search.html create mode 100644 doc/develop/html/numpy/searchindex.js create mode 100644 doc/develop/html/numpy/tutorial/dtype.html create mode 100644 doc/develop/html/numpy/tutorial/fromdata.html create mode 100644 doc/develop/html/numpy/tutorial/index.html create mode 100644 doc/develop/html/numpy/tutorial/ndarray.html create mode 100644 doc/develop/html/numpy/tutorial/simple.html create mode 100644 doc/develop/html/numpy/tutorial/ufunc.html create mode 100644 doc/develop/html/reference/HTML.manifest create mode 100644 doc/develop/html/reference/concepts.html create mode 100644 doc/develop/html/reference/concepts/dereferenceable.html create mode 100644 doc/develop/html/reference/concepts/extractor.html create mode 100644 doc/develop/html/reference/concepts/holdergenerator.html create mode 100644 doc/develop/html/reference/concepts/objectwrapper.html create mode 100644 doc/develop/html/reference/concepts/resultconverter.html create mode 100644 doc/develop/html/reference/embedding.html create mode 100644 doc/develop/html/reference/embedding/boost_python_import_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_call_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_call_method_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_data_members_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_make_function_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_overloads_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_ptr_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/boost_python_raw_function_hpp.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/function_documentation.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/models_of_callpolicies.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/models_of_resultconverter.html create mode 100644 doc/develop/html/reference/function_invocation_and_creation/models_of_resultconvertergenerat.html create mode 100644 doc/develop/html/reference/glossary.html create mode 100644 doc/develop/html/reference/high_level_components.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_def_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_def_visitor_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_docstring_options_h.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_enum_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_errors_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_exception_translato.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_init_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_iterator_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_module_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_operators_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_scope_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_stl_iterator_hpp.html create mode 100644 doc/develop/html/reference/high_level_components/boost_python_wrapper_hpp.html create mode 100644 doc/develop/html/reference/index.html create mode 100644 doc/develop/html/reference/object_wrappers.html create mode 100644 doc/develop/html/reference/object_wrappers/boost_python_list_hpp.html create mode 100644 doc/develop/html/reference/object_wrappers/boost_python_long_hpp.html create mode 100644 doc/develop/html/reference/object_wrappers/boost_python_object_hpp.html create mode 100644 doc/develop/html/reference/object_wrappers/boost_python_slice_hpp.html create mode 100644 doc/develop/html/reference/object_wrappers/boost_python_str_hpp.html create mode 100644 doc/develop/html/reference/object_wrappers/boost_python_tuple_hpp.html create mode 100644 doc/develop/html/reference/to_from_python_type_conversion.html create mode 100644 doc/develop/html/reference/to_from_python_type_conversion/boost_python_implicit_hpp.html create mode 100644 doc/develop/html/reference/to_from_python_type_conversion/boost_python_lvalue_from_pytype_.html create mode 100644 doc/develop/html/reference/to_from_python_type_conversion/boost_python_opaque_pointer_conv.html create mode 100644 doc/develop/html/reference/to_from_python_type_conversion/boost_python_register_ptr_to_pyt.html create mode 100644 doc/develop/html/reference/to_from_python_type_conversion/boost_python_to_python_converter.html create mode 100644 doc/develop/html/reference/topics.html create mode 100644 doc/develop/html/reference/topics/indexing_support.html create mode 100644 doc/develop/html/reference/topics/pickle_support.html create mode 100644 doc/develop/html/reference/utility_and_infrastructure.html create mode 100644 doc/develop/html/reference/utility_and_infrastructure/boost_python_handle_hpp.html create mode 100644 doc/develop/html/reference/utility_and_infrastructure/boost_python_instance_holder_hpp.html create mode 100644 doc/develop/html/reference/utility_and_infrastructure/boost_python_pointee_hpp.html create mode 100644 doc/develop/html/reference/utility_and_infrastructure/boost_python_ssize_t_hpp.html create mode 100644 doc/develop/html/reference/utility_and_infrastructure/boost_python_type_id_hpp.html create mode 100644 doc/develop/html/rn.html create mode 100644 doc/develop/html/support.html create mode 100644 doc/develop/html/tutorial/HTML.manifest create mode 100644 doc/develop/html/tutorial/index.html create mode 100644 doc/develop/html/tutorial/tutorial/embedding.html create mode 100644 doc/develop/html/tutorial/tutorial/exception.html create mode 100644 doc/develop/html/tutorial/tutorial/exposing.html create mode 100644 doc/develop/html/tutorial/tutorial/functions.html create mode 100644 doc/develop/html/tutorial/tutorial/hello.html create mode 100644 doc/develop/html/tutorial/tutorial/iterators.html create mode 100644 doc/develop/html/tutorial/tutorial/object.html create mode 100644 doc/develop/html/tutorial/tutorial/techniques.html diff --git a/doc/develop/html/HTML.manifest b/doc/develop/html/HTML.manifest new file mode 100644 index 00000000..edde06ad --- /dev/null +++ b/doc/develop/html/HTML.manifest @@ -0,0 +1,31 @@ +index.html +rn.html +building.html +building/background.html +building/no_install_quickstart.html +building/installing_boost_python_on_your_.html +building/configuring_boost_build.html +building/choosing_a_boost_python_library_.html +building/include_issues.html +building/python_debugging_builds.html +building/testing_boost_python.html +building/notes_for_mingw_and_cygwin_with_.html +configuration.html +support.html +faq.html +faq/i_m_getting_the_attempt_to_retur.html +faq/is_return_internal_reference_eff.html +faq/how_can_i_wrap_functions_which_t.html +faq/fatal_error_c1204_compiler_limit.html +faq/how_do_i_debug_my_python_extensi.html +faq/why_doesn_t_my_operator_work.html +faq/does_boost_python_work_with_mac_.html +faq/how_can_i_find_the_existing_pyob.html +faq/how_can_i_wrap_a_function_which0.html +faq/compilation_takes_too_much_time_.html +faq/how_do_i_create_sub_packages_usi.html +faq/error_c2064_term_does_not_evalua.html +faq/how_can_i_automatically_convert_.html +faq/why_is_my_automatic_to_python_co.html +faq/is_boost_python_thread_aware_com.html +glossary.html diff --git a/doc/develop/html/article.html b/doc/develop/html/article.html new file mode 100644 index 00000000..bd0ad6e6 --- /dev/null +++ b/doc/develop/html/article.html @@ -0,0 +1,929 @@ + + + + + + +Building Hybrid Systems with Boost.Python + + + + + +<--- Cannot embed stylesheet '/rst.css': No such file or directory. ---> + + +
+

Building Hybrid Systems with Boost.Python

+ +++ + + + + + + + + + + + + + +
Author:David Abrahams
Contact:dave@boost-consulting.com
Organization:Boost Consulting
Date:2003-05-14
Author:Ralf W. Grosse-Kunstleve
Copyright:Copyright David Abrahams and Ralf W. Grosse-Kunstleve 2003. All rights reserved
+ +
+

Abstract

+

Boost.Python is an open source C++ library which provides a concise +IDL-like interface for binding C++ classes and functions to +Python. Leveraging the full power of C++ compile-time introspection +and of recently developed metaprogramming techniques, this is achieved +entirely in pure C++, without introducing a new syntax. +Boost.Python's rich set of features and high-level interface make it +possible to engineer packages from the ground up as hybrid systems, +giving programmers easy and coherent access to both the efficient +compile-time polymorphism of C++ and the extremely convenient run-time +polymorphism of Python.

+
+
+

Introduction

+

Python and C++ are in many ways as different as two languages could +be: while C++ is usually compiled to machine-code, Python is +interpreted. Python's dynamic type system is often cited as the +foundation of its flexibility, while in C++ static typing is the +cornerstone of its efficiency. C++ has an intricate and difficult +compile-time meta-language, while in Python, practically everything +happens at runtime.

+

Yet for many programmers, these very differences mean that Python and +C++ complement one another perfectly. Performance bottlenecks in +Python programs can be rewritten in C++ for maximal speed, and +authors of powerful C++ libraries choose Python as a middleware +language for its flexible system integration capabilities. +Furthermore, the surface differences mask some strong similarities:

+
    +
  • 'C'-family control structures (if, while, for...)
  • +
  • Support for object-orientation, functional programming, and generic +programming (these are both multi-paradigm programming languages.)
  • +
  • Comprehensive operator overloading facilities, recognizing the +importance of syntactic variability for readability and +expressivity.
  • +
  • High-level concepts such as collections and iterators.
  • +
  • High-level encapsulation facilities (C++: namespaces, Python: modules) +to support the design of re-usable libraries.
  • +
  • Exception-handling for effective management of error conditions.
  • +
  • C++ idioms in common use, such as handle/body classes and +reference-counted smart pointers mirror Python reference semantics.
  • +
+

Given Python's rich 'C' interoperability API, it should in principle +be possible to expose C++ type and function interfaces to Python with +an analogous interface to their C++ counterparts. However, the +facilities provided by Python alone for integration with C++ are +relatively meager. Compared to C++ and Python, 'C' has only very +rudimentary abstraction facilities, and support for exception-handling +is completely missing. 'C' extension module writers are required to +manually manage Python reference counts, which is both annoyingly +tedious and extremely error-prone. Traditional extension modules also +tend to contain a great deal of boilerplate code repetition which +makes them difficult to maintain, especially when wrapping an evolving +API.

+

These limitations have lead to the development of a variety of wrapping +systems. SWIG is probably the most popular package for the +integration of C/C++ and Python. A more recent development is SIP, +which was specifically designed for interfacing Python with the Qt +graphical user interface library. Both SWIG and SIP introduce their +own specialized languages for customizing inter-language bindings. +This has certain advantages, but having to deal with three different +languages (Python, C/C++ and the interface language) also introduces +practical and mental difficulties. The CXX package demonstrates an +interesting alternative. It shows that at least some parts of +Python's 'C' API can be wrapped and presented through a much more +user-friendly C++ interface. However, unlike SWIG and SIP, CXX does +not include support for wrapping C++ classes as new Python types.

+

The features and goals of Boost.Python overlap significantly with +many of these other systems. That said, Boost.Python attempts to +maximize convenience and flexibility without introducing a separate +wrapping language. Instead, it presents the user with a high-level +C++ interface for wrapping C++ classes and functions, managing much of +the complexity behind-the-scenes with static metaprogramming. +Boost.Python also goes beyond the scope of earlier systems by +providing:

+
    +
  • Support for C++ virtual functions that can be overridden in Python.
  • +
  • Comprehensive lifetime management facilities for low-level C++ +pointers and references.
  • +
  • Support for organizing extensions as Python packages, +with a central registry for inter-language type conversions.
  • +
  • A safe and convenient mechanism for tying into Python's powerful +serialization engine (pickle).
  • +
  • Coherence with the rules for handling C++ lvalues and rvalues that +can only come from a deep understanding of both the Python and C++ +type systems.
  • +
+

The key insight that sparked the development of Boost.Python is that +much of the boilerplate code in traditional extension modules could be +eliminated using C++ compile-time introspection. Each argument of a +wrapped C++ function must be extracted from a Python object using a +procedure that depends on the argument type. Similarly the function's +return type determines how the return value will be converted from C++ +to Python. Of course argument and return types are part of each +function's type, and this is exactly the source from which +Boost.Python deduces most of the information required.

+

This approach leads to user guided wrapping: as much information is +extracted directly from the source code to be wrapped as is possible +within the framework of pure C++, and some additional information is +supplied explicitly by the user. Mostly the guidance is mechanical +and little real intervention is required. Because the interface +specification is written in the same full-featured language as the +code being exposed, the user has unprecedented power available when +she does need to take control.

+
+
+

Boost.Python Design Goals

+

The primary goal of Boost.Python is to allow users to expose C++ +classes and functions to Python using nothing more than a C++ +compiler. In broad strokes, the user experience should be one of +directly manipulating C++ objects from Python.

+

However, it's also important not to translate all interfaces too +literally: the idioms of each language must be respected. For +example, though C++ and Python both have an iterator concept, they are +expressed very differently. Boost.Python has to be able to bridge the +interface gap.

+

It must be possible to insulate Python users from crashes resulting +from trivial misuses of C++ interfaces, such as accessing +already-deleted objects. By the same token the library should +insulate C++ users from low-level Python 'C' API, replacing +error-prone 'C' interfaces like manual reference-count management and +raw PyObject pointers with more-robust alternatives.

+

Support for component-based development is crucial, so that C++ types +exposed in one extension module can be passed to functions exposed in +another without loss of crucial information like C++ inheritance +relationships.

+

Finally, all wrapping must be non-intrusive, without modifying or +even seeing the original C++ source code. Existing C++ libraries have +to be wrappable by third parties who only have access to header files +and binaries.

+
+
+

Hello Boost.Python World

+

And now for a preview of Boost.Python, and how it improves on the raw +facilities offered by Python. Here's a function we might want to +expose:

+
+char const* greet(unsigned x)
+{
+   static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
+
+   if (x > 2)
+       throw std::range_error("greet: index out of range");
+
+   return msgs[x];
+}
+
+

To wrap this function in standard C++ using the Python 'C' API, we'd +need something like this:

+
+extern "C" // all Python interactions use 'C' linkage and calling convention
+{
+    // Wrapper to handle argument/result conversion and checking
+    PyObject* greet_wrap(PyObject* args, PyObject * keywords)
+    {
+         int x;
+         if (PyArg_ParseTuple(args, "i", &x))    // extract/check arguments
+         {
+             char const* result = greet(x);      // invoke wrapped function
+             return PyString_FromString(result); // convert result to Python
+         }
+         return 0;                               // error occurred
+    }
+
+    // Table of wrapped functions to be exposed by the module
+    static PyMethodDef methods[] = {
+        { "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" }
+        , { NULL, NULL, 0, NULL } // sentinel
+    };
+
+    // module initialization function
+    DL_EXPORT init_hello()
+    {
+        (void) Py_InitModule("hello", methods); // add the methods to the module
+    }
+}
+
+

Now here's the wrapping code we'd use to expose it with Boost.Python:

+
+#include <boost/python.hpp>
+using namespace boost::python;
+BOOST_PYTHON_MODULE(hello)
+{
+    def("greet", greet, "return one of 3 parts of a greeting");
+}
+
+

and here it is in action:

+
+>>> import hello
+>>> for x in range(3):
+...     print hello.greet(x)
+...
+hello
+Boost.Python
+world!
+
+

Aside from the fact that the 'C' API version is much more verbose, +it's worth noting a few things that it doesn't handle correctly:

+
    +
  • The original function accepts an unsigned integer, and the Python +'C' API only gives us a way of extracting signed integers. The +Boost.Python version will raise a Python exception if we try to pass +a negative number to hello.greet, but the other one will proceed +to do whatever the C++ implementation does when converting an +negative integer to unsigned (usually wrapping to some very large +number), and pass the incorrect translation on to the wrapped +function.
  • +
  • That brings us to the second problem: if the C++ greet() +function is called with a number greater than 2, it will throw an +exception. Typically, if a C++ exception propagates across the +boundary with code generated by a 'C' compiler, it will cause a +crash. As you can see in the first version, there's no C++ +scaffolding there to prevent this from happening. Functions wrapped +by Boost.Python automatically include an exception-handling layer +which protects Python users by translating unhandled C++ exceptions +into a corresponding Python exception.
  • +
  • A slightly more-subtle limitation is that the argument conversion +used in the Python 'C' API case can only get that integer x in +one way. PyArg_ParseTuple can't convert Python long objects +(arbitrary-precision integers) which happen to fit in an unsigned +int but not in a signed long, nor will it ever handle a +wrapped C++ class with a user-defined implicit operator unsigned +int() conversion. Boost.Python's dynamic type conversion +registry allows users to add arbitrary conversion methods.
  • +
+
+
+

Library Overview

+

This section outlines some of the library's major features. Except as +neccessary to avoid confusion, details of library implementation are +omitted.

+
+

Exposing Classes

+

C++ classes and structs are exposed with a similarly-terse interface. +Given:

+
+struct World
+{
+    void set(std::string msg) { this->msg = msg; }
+    std::string greet() { return msg; }
+    std::string msg;
+};
+
+

The following code will expose it in our extension module:

+
+#include <boost/python.hpp>
+BOOST_PYTHON_MODULE(hello)
+{
+    class_<World>("World")
+        .def("greet", &World::greet)
+        .def("set", &World::set)
+    ;
+}
+
+

Although this code has a certain pythonic familiarity, people +sometimes find the syntax bit confusing because it doesn't look like +most of the C++ code they're used to. All the same, this is just +standard C++. Because of their flexible syntax and operator +overloading, C++ and Python are great for defining domain-specific +(sub)languages +(DSLs), and that's what we've done in Boost.Python. To break it down:

+
+class_<World>("World")
+
+

constructs an unnamed object of type class_<World> and passes +"World" to its constructor. This creates a new-style Python class +called World in the extension module, and associates it with the +C++ type World in the Boost.Python type conversion registry. We +might have also written:

+
+class_<World> w("World");
+
+

but that would've been more verbose, since we'd have to name w +again to invoke its def() member function:

+
+w.def("greet", &World::greet)
+
+

There's nothing special about the location of the dot for member +access in the original example: C++ allows any amount of whitespace on +either side of a token, and placing the dot at the beginning of each +line allows us to chain as many successive calls to member functions +as we like with a uniform syntax. The other key fact that allows +chaining is that class_<> member functions all return a reference +to *this.

+

So the example is equivalent to:

+
+class_<World> w("World");
+w.def("greet", &World::greet);
+w.def("set", &World::set);
+
+

It's occasionally useful to be able to break down the components of a +Boost.Python class wrapper in this way, but the rest of this article +will stick to the terse syntax.

+

For completeness, here's the wrapped class in use:

+
+>>> import hello
+>>> planet = hello.World()
+>>> planet.set('howdy')
+>>> planet.greet()
+'howdy'
+
+
+

Constructors

+

Since our World class is just a plain struct, it has an +implicit no-argument (nullary) constructor. Boost.Python exposes the +nullary constructor by default, which is why we were able to write:

+
+>>> planet = hello.World()
+
+

However, well-designed classes in any language may require constructor +arguments in order to establish their invariants. Unlike Python, +where __init__ is just a specially-named method, In C++ +constructors cannot be handled like ordinary member functions. In +particular, we can't take their address: &World::World is an +error. The library provides a different interface for specifying +constructors. Given:

+
+struct World
+{
+    World(std::string msg); // added constructor
+    ...
+
+

we can modify our wrapping code as follows:

+
+class_<World>("World", init<std::string>())
+    ...
+
+

of course, a C++ class may have additional constructors, and we can +expose those as well by passing more instances of init<...> to +def():

+
+class_<World>("World", init<std::string>())
+    .def(init<double, double>())
+    ...
+
+

Boost.Python allows wrapped functions, member functions, and +constructors to be overloaded to mirror C++ overloading.

+
+
+

Data Members and Properties

+

Any publicly-accessible data members in a C++ class can be easily +exposed as either readonly or readwrite attributes:

+
+class_<World>("World", init<std::string>())
+    .def_readonly("msg", &World::msg)
+    ...
+
+

and can be used directly in Python:

+
+>>> planet = hello.World('howdy')
+>>> planet.msg
+'howdy'
+
+

This does not result in adding attributes to the World instance +__dict__, which can result in substantial memory savings when +wrapping large data structures. In fact, no instance __dict__ +will be created at all unless attributes are explicitly added from +Python. Boost.Python owes this capability to the new Python 2.2 type +system, in particular the descriptor interface and property type.

+

In C++, publicly-accessible data members are considered a sign of poor +design because they break encapsulation, and style guides usually +dictate the use of "getter" and "setter" functions instead. In +Python, however, __getattr__, __setattr__, and since 2.2, +property mean that attribute access is just one more +well-encapsulated syntactic tool at the programmer's disposal. +Boost.Python bridges this idiomatic gap by making Python property +creation directly available to users. If msg were private, we +could still expose it as attribute in Python as follows:

+
+class_<World>("World", init<std::string>())
+    .add_property("msg", &World::greet, &World::set)
+    ...
+
+

The example above mirrors the familiar usage of properties in Python +2.2+:

+
+>>> class World(object):
+...     __init__(self, msg):
+...         self.__msg = msg
+...     def greet(self):
+...         return self.__msg
+...     def set(self, msg):
+...         self.__msg = msg
+...     msg = property(greet, set)
+
+
+
+

Operator Overloading

+

The ability to write arithmetic operators for user-defined types has +been a major factor in the success of both languages for numerical +computation, and the success of packages like NumPy attests to the +power of exposing operators in extension modules. Boost.Python +provides a concise mechanism for wrapping operator overloads. The +example below shows a fragment from a wrapper for the Boost rational +number library:

+
+class_<rational<int> >("rational_int")
+  .def(init<int, int>()) // constructor, e.g. rational_int(3,4)
+  .def("numerator", &rational<int>::numerator)
+  .def("denominator", &rational<int>::denominator)
+  .def(-self)        // __neg__ (unary minus)
+  .def(self + self)  // __add__ (homogeneous)
+  .def(self * self)  // __mul__
+  .def(self + int()) // __add__ (heterogenous)
+  .def(int() + self) // __radd__
+  ...
+
+

The magic is performed using a simplified application of "expression +templates" [VELD1995], a technique originally developed for +optimization of high-performance matrix algebra expressions. The +essence is that instead of performing the computation immediately, +operators are overloaded to construct a type representing the +computation. In matrix algebra, dramatic optimizations are often +available when the structure of an entire expression can be taken into +account, rather than evaluating each operation "greedily". +Boost.Python uses the same technique to build an appropriate Python +method object based on expressions involving self.

+
+
+

Inheritance

+

C++ inheritance relationships can be represented to Boost.Python by adding +an optional bases<...> argument to the class_<...> template +parameter list as follows:

+
+class_<Derived, bases<Base1,Base2> >("Derived")
+     ...
+
+

This has two effects:

+
    +
  1. When the class_<...> is created, Python type objects +corresponding to Base1 and Base2 are looked up in +Boost.Python's registry, and are used as bases for the new Python +Derived type object, so methods exposed for the Python Base1 +and Base2 types are automatically members of the Derived +type. Because the registry is global, this works correctly even if +Derived is exposed in a different module from either of its +bases.
  2. +
  3. C++ conversions from Derived to its bases are added to the +Boost.Python registry. Thus wrapped C++ methods expecting (a +pointer or reference to) an object of either base type can be +called with an object wrapping a Derived instance. Wrapped +member functions of class T are treated as though they have an +implicit first argument of T&, so these conversions are +neccessary to allow the base class methods to be called for derived +objects.
  4. +
+

Of course it's possible to derive new Python classes from wrapped C++ +class instances. Because Boost.Python uses the new-style class +system, that works very much as for the Python built-in types. There +is one significant detail in which it differs: the built-in types +generally establish their invariants in their __new__ function, so +that derived classes do not need to call __init__ on the base +class before invoking its methods :

+
+>>> class L(list):
+...      def __init__(self):
+...          pass
+...
+>>> L().reverse()
+>>>
+
+

Because C++ object construction is a one-step operation, C++ instance +data cannot be constructed until the arguments are available, in the +__init__ function:

+
+>>> class D(SomeBoostPythonClass):
+...      def __init__(self):
+...          pass
+...
+>>> D().some_boost_python_method()
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+TypeError: bad argument type for built-in operation
+
+

This happened because Boost.Python couldn't find instance data of type +SomeBoostPythonClass within the D instance; D's __init__ +function masked construction of the base class. It could be corrected +by either removing D's __init__ function or having it call +SomeBoostPythonClass.__init__(...) explicitly.

+
+
+

Virtual Functions

+

Deriving new types in Python from extension classes is not very +interesting unless they can be used polymorphically from C++. In +other words, Python method implementations should appear to override +the implementation of C++ virtual functions when called through base +class pointers/references from C++. Since the only way to alter the +behavior of a virtual function is to override it in a derived class, +the user must build a special derived class to dispatch a polymorphic +class' virtual functions:

+
+//
+// interface to wrap:
+//
+class Base
+{
+ public:
+    virtual int f(std::string x) { return 42; }
+    virtual ~Base();
+};
+
+int calls_f(Base const& b, std::string x) { return b.f(x); }
+
+//
+// Wrapping Code
+//
+
+// Dispatcher class
+struct BaseWrap : Base
+{
+    // Store a pointer to the Python object
+    BaseWrap(PyObject* self_) : self(self_) {}
+    PyObject* self;
+
+    // Default implementation, for when f is not overridden
+    int f_default(std::string x) { return this->Base::f(x); }
+    // Dispatch implementation
+    int f(std::string x) { return call_method<int>(self, "f", x); }
+};
+
+...
+    def("calls_f", calls_f);
+    class_<Base, BaseWrap>("Base")
+        .def("f", &Base::f, &BaseWrap::f_default)
+        ;
+
+

Now here's some Python code which demonstrates:

+
+>>> class Derived(Base):
+...     def f(self, s):
+...          return len(s)
+...
+>>> calls_f(Base(), 'foo')
+42
+>>> calls_f(Derived(), 'forty-two')
+9
+
+

Things to notice about the dispatcher class:

+
    +
  • The key element which allows overriding in Python is the +call_method invocation, which uses the same global type +conversion registry as the C++ function wrapping does to convert its +arguments from C++ to Python and its return type from Python to C++.
  • +
  • Any constructor signatures you wish to wrap must be replicated with +an initial PyObject* argument
  • +
  • The dispatcher must store this argument so that it can be used to +invoke call_method
  • +
  • The f_default member function is needed when the function being +exposed is not pure virtual; there's no other way Base::f can be +called on an object of type BaseWrap, since it overrides f.
  • +
+
+
+

Deeper Reflection on the Horizon?

+

Admittedly, this formula is tedious to repeat, especially on a project +with many polymorphic classes. That it is neccessary reflects some +limitations in C++'s compile-time introspection capabilities: there's +no way to enumerate the members of a class and find out which are +virtual functions. At least one very promising project has been +started to write a front-end which can generate these dispatchers (and +other wrapping code) automatically from C++ headers.

+

Pyste is being developed by Bruno da Silva de Oliveira. It builds on +GCC_XML, which generates an XML version of GCC's internal program +representation. Since GCC is a highly-conformant C++ compiler, this +ensures correct handling of the most-sophisticated template code and +full access to the underlying type system. In keeping with the +Boost.Python philosophy, a Pyste interface description is neither +intrusive on the code being wrapped, nor expressed in some unfamiliar +language: instead it is a 100% pure Python script. If Pyste is +successful it will mark a move away from wrapping everything directly +in C++ for many of our users. It will also allow us the choice to +shift some of the metaprogram code from C++ to Python. We expect that +soon, not only our users but the Boost.Python developers themselves +will be "thinking hybrid" about their own code.

+
+
+
+

Serialization

+

Serialization is the process of converting objects in memory to a +form that can be stored on disk or sent over a network connection. The +serialized object (most often a plain string) can be retrieved and +converted back to the original object. A good serialization system will +automatically convert entire object hierarchies. Python's standard +pickle module is just such a system. It leverages the language's strong +runtime introspection facilities for serializing practically arbitrary +user-defined objects. With a few simple and unintrusive provisions this +powerful machinery can be extended to also work for wrapped C++ objects. +Here is an example:

+
+#include <string>
+
+struct World
+{
+    World(std::string a_msg) : msg(a_msg) {}
+    std::string greet() const { return msg; }
+    std::string msg;
+};
+
+#include <boost/python.hpp>
+using namespace boost::python;
+
+struct World_picklers : pickle_suite
+{
+  static tuple
+  getinitargs(World const& w) { return make_tuple(w.greet()); }
+};
+
+BOOST_PYTHON_MODULE(hello)
+{
+    class_<World>("World", init<std::string>())
+        .def("greet", &World::greet)
+        .def_pickle(World_picklers())
+    ;
+}
+
+

Now let's create a World object and put it to rest on disk:

+
+>>> import hello
+>>> import pickle
+>>> a_world = hello.World("howdy")
+>>> pickle.dump(a_world, open("my_world", "w"))
+
+

In a potentially different script on a potentially different +computer with a potentially different operating system:

+
+>>> import pickle
+>>> resurrected_world = pickle.load(open("my_world", "r"))
+>>> resurrected_world.greet()
+'howdy'
+
+

Of course the cPickle module can also be used for faster +processing.

+

Boost.Python's pickle_suite fully supports the pickle protocol +defined in the standard Python documentation. Like a __getinitargs__ +function in Python, the pickle_suite's getinitargs() is responsible for +creating the argument tuple that will be use to reconstruct the pickled +object. The other elements of the Python pickling protocol, +__getstate__ and __setstate__ can be optionally provided via C++ +getstate and setstate functions. C++'s static type system allows the +library to ensure at compile-time that nonsensical combinations of +functions (e.g. getstate without setstate) are not used.

+

Enabling serialization of more complex C++ objects requires a little +more work than is shown in the example above. Fortunately the +object interface (see next section) greatly helps in keeping the +code manageable.

+
+
+

Object interface

+

Experienced 'C' language extension module authors will be familiar +with the ubiquitous PyObject*, manual reference-counting, and the +need to remember which API calls return "new" (owned) references or +"borrowed" (raw) references. These constraints are not just +cumbersome but also a major source of errors, especially in the +presence of exceptions.

+

Boost.Python provides a class object which automates reference +counting and provides conversion to Python from C++ objects of +arbitrary type. This significantly reduces the learning effort for +prospective extension module writers.

+

Creating an object from any other type is extremely simple:

+
+object s("hello, world");  // s manages a Python string
+
+

object has templated interactions with all other types, with +automatic to-python conversions. It happens so naturally that it's +easily overlooked:

+
+object ten_Os = 10 * s[4]; // -> "oooooooooo"
+
+

In the example above, 4 and 10 are converted to Python objects +before the indexing and multiplication operations are invoked.

+

The extract<T> class template can be used to convert Python objects +to C++ types:

+
+double x = extract<double>(o);
+
+

If a conversion in either direction cannot be performed, an +appropriate exception is thrown at runtime.

+

The object type is accompanied by a set of derived types +that mirror the Python built-in types such as list, dict, +tuple, etc. as much as possible. This enables convenient +manipulation of these high-level types from C++:

+
+dict d;
+d["some"] = "thing";
+d["lucky_number"] = 13;
+list l = d.keys();
+
+

This almost looks and works like regular Python code, but it is pure +C++. Of course we can wrap C++ functions which accept or return +object instances.

+
+
+
+

Thinking hybrid

+

Because of the practical and mental difficulties of combining +programming languages, it is common to settle a single language at the +outset of any development effort. For many applications, performance +considerations dictate the use of a compiled language for the core +algorithms. Unfortunately, due to the complexity of the static type +system, the price we pay for runtime performance is often a +significant increase in development time. Experience shows that +writing maintainable C++ code usually takes longer and requires far +more hard-earned working experience than developing comparable Python +code. Even when developers are comfortable working exclusively in +compiled languages, they often augment their systems by some type of +ad hoc scripting layer for the benefit of their users without ever +availing themselves of the same advantages.

+

Boost.Python enables us to think hybrid. Python can be used for +rapidly prototyping a new application; its ease of use and the large +pool of standard libraries give us a head start on the way to a +working system. If necessary, the working code can be used to +discover rate-limiting hotspots. To maximize performance these can +be reimplemented in C++, together with the Boost.Python bindings +needed to tie them back into the existing higher-level procedure.

+

Of course, this top-down approach is less attractive if it is clear +from the start that many algorithms will eventually have to be +implemented in C++. Fortunately Boost.Python also enables us to +pursue a bottom-up approach. We have used this approach very +successfully in the development of a toolbox for scientific +applications. The toolbox started out mainly as a library of C++ +classes with Boost.Python bindings, and for a while the growth was +mainly concentrated on the C++ parts. However, as the toolbox is +becoming more complete, more and more newly added functionality can be +implemented in Python.

+images/python_cpp_mix.png +

This figure shows the estimated ratio of newly added C++ and Python +code over time as new algorithms are implemented. We expect this +ratio to level out near 70% Python. Being able to solve new problems +mostly in Python rather than a more difficult statically typed +language is the return on our investment in Boost.Python. The ability +to access all of our code from Python allows a broader group of +developers to use it in the rapid development of new applications.

+
+
+

Development history

+

The first version of Boost.Python was developed in 2000 by Dave +Abrahams at Dragon Systems, where he was privileged to have Tim Peters +as a guide to "The Zen of Python". One of Dave's jobs was to develop +a Python-based natural language processing system. Since it was +eventually going to be targeting embedded hardware, it was always +assumed that the compute-intensive core would be rewritten in C++ to +optimize speed and memory footprint1. The project also wanted to +test all of its C++ code using Python test scripts2. The only +tool we knew of for binding C++ and Python was SWIG, and at the time +its handling of C++ was weak. It would be false to claim any deep +insight into the possible advantages of Boost.Python's approach at +this point. Dave's interest and expertise in fancy C++ template +tricks had just reached the point where he could do some real damage, +and Boost.Python emerged as it did because it filled a need and +because it seemed like a cool thing to try.

+

This early version was aimed at many of the same basic goals we've +described in this paper, differing most-noticeably by having a +slightly more cumbersome syntax and by lack of special support for +operator overloading, pickling, and component-based development. +These last three features were quickly added by Ullrich Koethe and +Ralf Grosse-Kunstleve3, and other enthusiastic contributors arrived +on the scene to contribute enhancements like support for nested +modules and static member functions.

+

By early 2001 development had stabilized and few new features were +being added, however a disturbing new fact came to light: Ralf had +begun testing Boost.Python on pre-release versions of a compiler using +the EDG front-end, and the mechanism at the core of Boost.Python +responsible for handling conversions between Python and C++ types was +failing to compile. As it turned out, we had been exploiting a very +common bug in the implementation of all the C++ compilers we had +tested. We knew that as C++ compilers rapidly became more +standards-compliant, the library would begin failing on more +platforms. Unfortunately, because the mechanism was so central to the +functioning of the library, fixing the problem looked very difficult.

+

Fortunately, later that year Lawrence Berkeley and later Lawrence +Livermore National labs contracted with Boost Consulting for support +and development of Boost.Python, and there was a new opportunity to +address fundamental issues and ensure a future for the library. A +redesign effort began with the low level type conversion architecture, +building in standards-compliance and support for component-based +development (in contrast to version 1 where conversions had to be +explicitly imported and exported across module boundaries). A new +analysis of the relationship between the Python and C++ objects was +done, resulting in more intuitive handling for C++ lvalues and +rvalues.

+

The emergence of a powerful new type system in Python 2.2 made the +choice of whether to maintain compatibility with Python 1.5.2 easy: +the opportunity to throw away a great deal of elaborate code for +emulating classic Python classes alone was too good to pass up. In +addition, Python iterators and descriptors provided crucial and +elegant tools for representing similar C++ constructs. The +development of the generalized object interface allowed us to +further shield C++ programmers from the dangers and syntactic burdens +of the Python 'C' API. A great number of other features including C++ +exception translation, improved support for overloaded functions, and +most significantly, CallPolicies for handling pointers and +references, were added during this period.

+

In October 2002, version 2 of Boost.Python was released. Development +since then has concentrated on improved support for C++ runtime +polymorphism and smart pointers. Peter Dimov's ingenious +boost::shared_ptr design in particular has allowed us to give the +hybrid developer a consistent interface for moving objects back and +forth across the language barrier without loss of information. At +first, we were concerned that the sophistication and complexity of the +Boost.Python v2 implementation might discourage contributors, but the +emergence of Pyste and several other significant feature +contributions have laid those fears to rest. Daily questions on the +Python C++-sig and a backlog of desired improvements show that the +library is getting used. To us, the future looks bright.

+
+
+

Conclusions

+

Boost.Python achieves seamless interoperability between two rich and +complimentary language environments. Because it leverages template +metaprogramming to introspect about types and functions, the user +never has to learn a third syntax: the interface definitions are +written in concise and maintainable C++. Also, the wrapping system +doesn't have to parse C++ headers or represent the type system: the +compiler does that work for us.

+

Computationally intensive tasks play to the strengths of C++ and are +often impossible to implement efficiently in pure Python, while jobs +like serialization that are trivial in Python can be very difficult in +pure C++. Given the luxury of building a hybrid software system from +the ground up, we can approach design with new confidence and power.

+
+
+

Citations

+ + + + + +
[VELD1995]T. Veldhuizen, "Expression Templates," C++ Report, +Vol. 7 No. 5 June 1995, pp. 26-31. +http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html
+
+
+

Footnotes

+ + + + + +
[1]In retrospect, it seems that "thinking hybrid" from the +ground up might have been better for the NLP system: the +natural component boundaries defined by the pure python +prototype turned out to be inappropriate for getting the +desired performance and memory footprint out of the C++ core, +which eventually caused some redesign overhead on the Python +side when the core was moved to C++.
+ + + + + +
[2]We also have some reservations about driving all C++ +testing through a Python interface, unless that's the only way +it will be ultimately used. Any transition across language +boundaries with such different object models can inevitably +mask bugs.
+ + + + + +
[3]These features were expressed very differently in v1 of +Boost.Python
+
+
+ + diff --git a/doc/develop/html/boostbook.css b/doc/develop/html/boostbook.css new file mode 100644 index 00000000..28f89359 --- /dev/null +++ b/doc/develop/html/boostbook.css @@ -0,0 +1,716 @@ + +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= +Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= +Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= +Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 9pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= +Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= +Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= +Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= +Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= +Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= +Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= +Table of contents +=============================================================================*/ + + div.toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + +/*============================================================================= +Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= +Suppress margins in tables +=============================================================================*/ + + table th > *:first-child, + table td > *:first-child + { + margin-top: 0; + } + + table th > *:last-child, + table td > *:last-child + { + margin-bottom: 0; + } + +/*============================================================================= +Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= +Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= +Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= +Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Links */ + a, a .keyword, a .identifier, a .special, a .preprocessor + a .char, a .comment, a .string, a .number + { + color: #005a9c; + } + + a:visited, a:visited .keyword, a:visited .identifier, + a:visited .special, a:visited .preprocessor a:visited .char, + a:visited .comment, a:visited .string, a:visited .number + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= +Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; +} + +sup { +bottom: 1ex; +} + +sub { +top: .5ex; +} + +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ diff --git a/doc/develop/html/building.html b/doc/develop/html/building.html new file mode 100644 index 00000000..0d5c0571 --- /dev/null +++ b/doc/develop/html/building.html @@ -0,0 +1,61 @@ + + + +Chapter 2. Building and Testing + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+
+

+Chapter 2. Building and Testing

+

+David Abrahams +

+
+
+
+ +

+ Boost.Python requires Python 2.2 + [1] or newer. +

+
+
+

+

[1] + Note that although we tested earlier versions of Boost.Python with Python + 2.2, and we don't think we've done anything + to break compatibility, this release of Boost.Python may not have been + tested with versions of Python earlier than 2.4, so we're not 100% sure + that python 2.2 and 2.3 are supported. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/background.html b/doc/develop/html/building/background.html new file mode 100644 index 00000000..d1d85155 --- /dev/null +++ b/doc/develop/html/building/background.html @@ -0,0 +1,70 @@ + + + +Background + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ There are two basic models for combining C++ and Python: +

+
    +
  • + extending, + in which the end-user launches the Python interpreter executable and + imports Python “extension modules” written in C++. Think of taking + a library written in C++ and giving it a Python interface so Python programmers + can use it. From Python, these modules look just like regular Python + modules. +
  • +
  • + embedding, + in which the end-user launches a program written in C++ that in turn + invokes the Python interpreter as a library subroutine. Think of adding + scriptability to an existing application. +
  • +
+

+ The key distinction between extending and embedding is the location of the + C++ main() + function: in the Python interpreter executable, or in some other program, + respectively. Note that even when embedding Python in another program, extension + modules are often the best way to make C/C++ functionality accessible to + Python code, so the use of extension modules is really at the heart + of both models. +

+

+ Except in rare cases, extension modules are built as dynamically-loaded libraries + with a single entry point, which means you can change them without rebuilding + either the other extension modules or the executable containing main(). +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/choosing_a_boost_python_library_.html b/doc/develop/html/building/choosing_a_boost_python_library_.html new file mode 100644 index 00000000..58663404 --- /dev/null +++ b/doc/develop/html/building/choosing_a_boost_python_library_.html @@ -0,0 +1,128 @@ + + + +Choosing a Boost.Python Library Binary + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ If—instead of letting Boost.Build construct and link with the right libraries + automatically—you choose to use a pre-built Boost.Python library, you'll + need to think about which one to link with. The Boost.Python binary comes + in both static and dynamic flavors. Take care to choose the right flavor + for your application. [3] +

+
+ +

+ The dynamic library is the safest and most-versatile choice: +

+
    +
  • + A single copy of the library code is used by all extension modules + built with a given toolset. [4] +
  • +
  • + The library contains a type conversion registry. Because one registry + is shared among all extension modules, instances of a class exposed + to Python in one dynamically-loaded extension module can be passed + to functions exposed in another such module. +
  • +
+
+
+ +

+ It might be appropriate to use the static Boost.Python library in any of + the following cases: +

+
    +
  • + You are extending + python and the types exposed in your dynamically-loaded extension module + don't need to be used by any other Boost.Python extension modules, + and you don't care if the core library code is duplicated among them. +
  • +
  • + You are embedding + python in your application and either: +
      +
    • + You are targeting a Unix variant OS other than MacOS or AIX, + where the dynamically-loaded extension modules can “see” + the Boost.Python library symbols that are part of the executable. +
    • +
    • + Or, you have statically linked some Boost.Python extension modules + into your application and you don't care if any dynamically-loaded + Boost.Python extension modules are able to use the types exposed + by your statically-linked extension modules (and vice-versa). +
    • +
    +
  • +
+
+
+

+

[3] + Information about how to identify the static and dynamic builds of Boost.Python + on Windows + / Unix + variants +

+

[4] + Because of the way most *nix platforms share symbols among dynamically-loaded + objects, I'm not certain that extension modules built with different + compiler toolsets will always use different copies of the Boost.Python + library when loaded into the same Python instance. Not using different + libraries could be a good thing if the compilers have compatible + ABIs, because extension modules built with the two libraries would + be interoperable. Otherwise, it could spell disaster, since an extension + module and the Boost.Python library would have different ideas of + such things as class layout. I would appreciate someone doing the + experiment to find out what happens. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/configuring_boost_build.html b/doc/develop/html/building/configuring_boost_build.html new file mode 100644 index 00000000..e82a74e6 --- /dev/null +++ b/doc/develop/html/building/configuring_boost_build.html @@ -0,0 +1,264 @@ + + + +Configuring Boost.Build + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ As described in the Boost.Build + Reference Manual, a file called user-config.jam in + your home directory is used to specify the tools and libraries available + to the build system. You may need to create or edit user-config.jam to + tell Boost.Build how to invoke Python, #include + its headers, and link with its libraries. +

+
+ + + + + +
[Note]Note

+ If you are using a unix-variant OS and you ran Boost's configure + script, it may have generated a user-config.jam + for you. [2] If your configure/make sequence was successful and Boost.Python + binaries were built, your user-config.jam + file is probably already correct. +

+

+ If you have one fairly “standard” python installation for your platform, + you might not need to do anything special to describe it. If you haven't + configured python in user-config.jam (and + you don't specify --without-python + on the Boost.Build command line), Boost.Build will automatically execute + the equivalent of +

+
import toolset : using ;
+using python ;
+
+

+ which automatically looks for Python in the most likely places. However, + that only happens when using the Boost.Python project file (e.g. when referred + to by another project as in the quickstart method). If instead you are linking + against separately-compiled Boost.Python binaries, you should set up a user-config.jam file + with at least the minimal incantation above. +

+
+ +

+ If you have several versions of Python installed, or Python is installed + in an unusual way, you may want to supply any or all of the following optional + parameters to using python. +

+
+

+
+
version
+

+ the version of Python to use. Should be in Major.Minor format, for + example, 2.3. Do not + include the subminor version (i.e. not + 2.5.1). If you have multiple Python versions + installed, the version will usually be the only configuration argument + required. +

+
cmd-or-prefix
+

+ preferably, a command that invokes a Python interpreter. Alternatively, + the installation prefix for Python libraries and header files. Only + use the alternative formulation if there is no appropriate Python + executable available. +

+
includes
+

+ the #include paths + for Python headers. Normally the correct path(s) will be automatically + deduced from version + and/or cmd-or-prefix. +

+
libraries
+

+ the path to Python library binaries. On MacOS/Darwin, you can also + pass the path of the Python framework. Normally the correct path(s) + will be automatically deduced from version + and/or cmd-or-prefix. +

+
condition
+

+ if specified, should be a set of Boost.Build properties that are + matched against the build configuration when Boost.Build selects + a Python configuration to use. See examples below for details. +

+
extension-suffix
+

+ A string to append to the name of extension modules before the true + filename extension. You almost certainly don't need to use this. + Usually this suffix is only used when targeting a Windows debug build + of Python, and will be set automatically for you based on the value + of the <python-debugging> + feature. However, at least one Linux distribution (Ubuntu Feisty + Fawn) has a specially configured <python-dbg> + package that claims to use such a suffix. +

+
+
+
+
+ +

+ Note that in the examples below, case and especially + whitespace are significant. +

+
    +
  • +

    + If you have both python 2.5 and python 2.4 installed, user-config.jam might contain +

    +
    using python : 2.5 ;  # Make both versions of Python available
    +using python : 2.4 ;  # To build with python 2.4, add python=2.4
    +                      # to your command line.
    +
    +

    + The first version configured (2.5) becomes the default. To build against + python 2.4, add python=2.4 + to the bjam command + line. +

    +
  • +
  • +

    + If you have python installed in an unusual location, you might supply + the path to the interpreter in the cmd-or-prefix + parameter: +

    +
    using python : : /usr/local/python-2.6-beta/bin/python ;
    +
    +
  • +
  • +

    + If you have a separate build of Python for use with a particular toolset, + you might supply that toolset in the condition + parameter: +

    +
    using python ;  # use for most toolsets
    +
    +# Use with Intel C++ toolset
    +using python
    +     : # version
    +     : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix
    +     : # includes
    +     : # libraries
    +     : <toolset>intel # condition
    +     ;
    +
    +
  • +
  • +

    + If you have downloaded the Python sources and built both the normal + and the "python + debugging" builds from source on Windows, you might see: +

    +
    using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ;
    +using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d
    +  : # includes
    +  : # libs
    +  : <python-debugging>on ;
    +
    +
  • +
  • +

    + You can set up your user-config.jam so a bjam built under Windows can + build/test both Windows and Cygwin_ python extensions. Just pass <target-os>cygwin + in the condition parameter + for the cygwin python installation: +

    +
    # windows installation
    +using python ;
    +
    +# cygwin installation
    +using python : : c:\\cygwin\\bin\\python2.5 : : : <target-os>cygwin ;
    +
    +

    + when you put target-os=cygwin in your build request, it should build + with the cygwin version of python: _ +

    +
    bjam target-os=cygwin toolset=gcc
    +
    +

    + This is supposed to work the other way, too (targeting windows python + with a Cygwin bjam) but it seems + as though the support in Boost.Build's toolsets for building that way + is broken at the time of this writing. +

    +
  • +
  • +

    + Note that because of the + way Boost.Build currently selects target alternatives, you + might have be very explicit in your build requests. For example, given: +

    +
    using python : 2.5 ; # a regular windows build
    +using python : 2.4 : : : : <target-os>cygwin ;
    +
    +

    + building with +

    +
    bjam target-os=cygwin
    +
    +

    + will yield an error. Instead, you'll need to write +

    +
    bjam target-os=cygwin/python=2.4
    +
    +
  • +
+
+
+

+

[2] + configure overwrites + the existing user-config.jam in your home directory (if any) + after making a backup of the old version. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/include_issues.html b/doc/develop/html/building/include_issues.html new file mode 100644 index 00000000..6ba4d059 --- /dev/null +++ b/doc/develop/html/building/include_issues.html @@ -0,0 +1,53 @@ + + + +#include Issues + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ 1. If you should ever have occasion to #include + "python.h" directly in a + translation unit of a program using Boost.Python, use #include + "boost/python/detail/wrap_python.hpp" + instead. It handles several issues necessary for use with Boost.Python, one + of which is mentioned in the next section. +

+

+ 2. Be sure not to #include + any system headers before wrap_python.hpp. This + restriction is actually imposed by Python, or more properly, by Python's + interaction with your operating system. See http://docs.python.org/ext/simpleExample.html + for details. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/installing_boost_python_on_your_.html b/doc/develop/html/building/installing_boost_python_on_your_.html new file mode 100644 index 00000000..6ab4c4c3 --- /dev/null +++ b/doc/develop/html/building/installing_boost_python_on_your_.html @@ -0,0 +1,52 @@ + + + +Installing Boost.Python on your System + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Since Boost.Python is a separately-compiled (as opposed to header-only) library, its user relies on the services + of a Boost.Python library binary. +

+

+ If you need a regular installation of the Boost.Python library binaries on + your system, the Boost Getting + Started Guide will walk you through the steps of creating one. If + building binaries from source, you might want to supply the --with-python + argument to bjam (or the + --with-libraries=python + argument to configure), so + only the Boost.Python binary will be built, rather than all the Boost binaries. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/no_install_quickstart.html b/doc/develop/html/building/no_install_quickstart.html new file mode 100644 index 00000000..7273dee3 --- /dev/null +++ b/doc/develop/html/building/no_install_quickstart.html @@ -0,0 +1,318 @@ + + + +No-Install Quickstart + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ There is no need to “install Boost” in order to get started using Boost.Python. + These instructions use Boost.Build + projects, which will build those binaries as soon as they're needed. Your + first tests may take a little longer while you wait for Boost.Python to build, + but doing things this way will save you from worrying about build intricacies + like which library binaries to use for a specific compiler configuration + and figuring out the right compiler options to use yourself. +

+
+ + + + + +
[Note]Note
+

+ Of course it's possible to use other build systems to build Boost.Python + and its extensions, but they are not officially supported by Boost. Moreover + 99% of all “I can't build Boost.Python” problems + come from trying to use another build system without first following + these instructions. +

+

+ If you want to use another system anyway, we suggest that you follow these + instructions, and then invoke bjam + with the +

+

+ -a + -ofilename +

+

+ options to dump the build commands it executes to a file, so you can see + what your alternate build system needs to do. +

+
+
+ +

+ 1. Get Boost; see sections 1 and 2 of the Boost Getting + Started Guide. +

+

+ 2. Get the bjam build driver. + See section 5 of the Boost Getting + Started Guide. +

+

+ 3. cd into the example/quickstart/ directory of your Boost.Python installation, + which contains a small example project. +

+

+ 4. Invoke bjam. Replace + the “stage“ argument + from the example invocation from section 5 of the Boost Getting + Started Guide with “test,“ + to build all the test targets. Also add the argument “--verbose-test” to see the output generated by + the tests when they are run. On Windows, your bjam + invocation might look something like: +

+
C:\\...\\quickstart> bjam toolset=msvc --verbose-test test
+
+

+ and on Unix variants, perhaps, +

+
.../quickstart$ bjam toolset=gcc --verbose-test test
+
+
+ + + + + +
[Note]Note

+ For the sake of concision, the rest of this guide will use unix-style + forward slashes in pathnames instead of the backslashes with which Windows + users may be more familiar. The forward slashes should work everywhere + except in Command + Prompt windows, where you should use backslashes. +

+

+ If you followed this procedure successfully, you will have built an extension + module called extending + and tested it by running a Python script called test_extending.py. + You will also have built and run a simple application called embedding that embeds python. +

+
+
+ +

+ If you're seeing lots of compiler and/or linker error messages, it's probably + because Boost.Build is having trouble finding your Python installation. + You might want to pass the --debug-configuration option to bjam the first few times you invoke it, + to make sure that Boost.Build is correctly locating all the parts of your + Python installation. If it isn't, consider Configuring + Boost.Build as detailed below. +

+

+ If you're still having trouble, Someone on one of the following mailing + lists may be able to help: +

+
+
+
+ +

+ Rejoice! If you're new to Boost.Python, at this point it might be a good + idea to ignore build issues for a while and concentrate on learning the + library by going through the Tutorial + and perhaps some of the Reference Manual, + trying out what you've learned about the API by modifying the quickstart + project. +

+
+
+ + +

+ If you're content to keep your extension module forever in one source file + called extending.cpp, inside your Boost.Python distribution, + and import it forever as extending, + then you can stop here. However, it's likely that you will want to make + a few changes. There are a few things you can do without having to learn + Boost.Build in depth. +

+

+ The project you just built is specified in two files in the current directory: + boost-build.jam, which tells bjam + where it can find the interpreted code of the Boost build system, and + Jamroot, which describes + the targets you just built. These files are heavily commented, so they + should be easy to modify. Take care, however, to preserve whitespace. Punctuation + such as ; will not be recognized + as intended by bjam if + it is not surrounded by whitespace. +

+
+ +

+ You'll probably want to copy this project elsewhere so you can change + it without modifying your Boost distribution. To do that, simply +

+

+ a. copy the entire example/quickstart/ directory into a new directory. +

+

+ b. In the new copies of boost-build.jam + and Jamroot, locate the + relative path near the top of the file that is clearly marked by a comment, + and edit that path so that it refers to the same directory your Boost + distribution as it referred to when the file was in its original location + in the example/quickstart/ + directory. +

+

+ For example, if you moved the project from /home/dave/boost_1_34_0/libs/python/example/quickstart to /home/dave/my-project, you could change the first + path in boost-build.jam from +

+
../../../../tools/build/src
+
+

+ to +

+
/home/dave/boost_1_34_0/tools/build/src
+
+

+ and change the first path in Jamroot + from +

+
../../../..
+
+

+ to +

+
/home/dave/boost_1_34_0
+
+
+
+ +

+ The names of additional source files involved in building your extension + module or embedding application can be listed in Jamroot + right alongside extending.cpp + or embedding.cpp respectively. Just be sure to leave + whitespace around each filename: +

+
 file1.cpp file2.cpp file3.cpp 
+
+

+ Naturally, if you want to change the name of a source file you can tell + Boost.Build about it by editing the name in Jamroot. +

+
+
+ +

+ The name of the extension module is determined by two things: +

+
    +
  1. + the name in Jamroot + immediately following python-extension, + and +
  2. +
  3. + the name passed to BOOST_PYTHON_MODULE + in extending.cpp. +
  4. +
+

+ To change the name of the extension module from extending + to hello, you'd edit + Jamroot, changing +

+
python-extension extending : extending.cpp ;
+
+

+ to +

+
python-extension hello : extending.cpp ;
+
+

+ and you'd edit extending.cpp, changing +

+
BOOST_PYTHON_MODULE(extending)
+
+

+ to +

+
BOOST_PYTHON_MODULE(hello)
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/notes_for_mingw_and_cygwin_with_.html b/doc/develop/html/building/notes_for_mingw_and_cygwin_with_.html new file mode 100644 index 00000000..a51035d5 --- /dev/null +++ b/doc/develop/html/building/notes_for_mingw_and_cygwin_with_.html @@ -0,0 +1,47 @@ + + + +Notes for MinGW (and Cygwin with -mno-cygwin) GCC Users + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ If you are using a version of Python prior to 2.4.1 with a MinGW prior to + 3.0.0 (with binutils-2.13.90-20030111-1), you will need to create a MinGW-compatible + version of the Python library; the one shipped with Python will only work + with a Microsoft-compatible linker. Follow the instructions in the “Non-Microsoft” + section of the “Building Extensions: Tips And Tricks” chapter in Installing Python Modules + to create libpythonXX.a, where XX + corresponds to the major and minor version numbers of your Python installation. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/python_debugging_builds.html b/doc/develop/html/building/python_debugging_builds.html new file mode 100644 index 00000000..357d732d --- /dev/null +++ b/doc/develop/html/building/python_debugging_builds.html @@ -0,0 +1,78 @@ + + + +Python Debugging Builds + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Python can be built in a special “python debugging” configuration that + adds extra checks and instrumentation that can be very useful for developers + of extension modules. The data structures used by the debugging configuration + contain additional members, so a Python executable + built with python debugging enabled cannot be used with an extension module + or library compiled without it, and vice-versa. +

+

+ Since pre-built “python debugging” versions of the Python executable + and libraries are not supplied with most distributions of Python, [5] and we didn't want to force our users to build them, Boost.Build + does not automatically enable python debugging in its debug + build variant (which is the default). Instead there is a special build property + called python-debugging that, when used as a build property, + will define the right preprocessor symbols and select the right libraries + to link with. +

+

+ On unix-variant platforms, the debugging versions of Python's data structures + will only be used if the symbol Py_DEBUG + is defined. On many windows compilers, when extension modules are built with + the preprocessor symbol _DEBUG, + Python defaults to force linking with a special debugging version of the + Python DLL. Since that symbol is very commonly used even when Python is not + present, Boost.Python temporarily undefines _DEBUG + when Python.h is #included from boost/python/detail/wrap_python.hpp - + unless BOOST_DEBUG_PYTHON + is defined. The upshot is that if you want “python debugging”and you + aren't using Boost.Build, you should make sure BOOST_DEBUG_PYTHON + is defined, or python debugging will be suppressed. +

+
+

+

[5] + On Unix and similar platforms, a debugging python and associated libraries + are built by adding --with-pydebug when configuring the Python build. On + Windows, the debugging version of Python is generated by the "Win32 + Debug" target of the Visual Studio project in the PCBuild subdirectory + of a full Python source code distribution. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/building/testing_boost_python.html b/doc/develop/html/building/testing_boost_python.html new file mode 100644 index 00000000..cbe198d5 --- /dev/null +++ b/doc/develop/html/building/testing_boost_python.html @@ -0,0 +1,42 @@ + + + +Testing Boost.Python + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ To run the full test suite for Boost.Python, invoke bjam + in the test subdirectory + of your Boost.Python distribution. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/configuration.html b/doc/develop/html/configuration.html new file mode 100644 index 00000000..78faae48 --- /dev/null +++ b/doc/develop/html/configuration.html @@ -0,0 +1,340 @@ + + + +Chapter 3. Configuration + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+
+

+Chapter 3. Configuration

+

+David Abrahams +

+
+
+
+ + +
+ +

+ Boost.Python uses several configuration + macros in <boost/config.hpp>, as well as configuration macros meant + to be supplied by the application. These macros are documented here. +

+
+
+ +

+ These are the macros that may be defined by an application using Boost.Python. + Note that if you extend a strict interpretation of the C++ standard to + cover dynamic libraries, using different values of these macros when compiling + different libraries (including extension modules and the Boost.Python library + itself) is a violation of the ODR. However, + we know of no C++ implementations on which this particular violation is + detectable or causes any problems. +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Macro +

+
+

+ Default +

+
+

+ Meaning +

+
+

+ BOOST_PYTHON_MAX_ARITY +

+
+

+ 15 +

+
+

+ The maximum arity of any function, member function, or constructor + to be wrapped, invocation of a Boost.Python function wich is + specified as taking arguments x1, x2,...Xn. This includes, in + particular, callback mechanisms such as object::operator()(...) + or call_method<R>(... ). +

+
+

+ BOOST_PYTHON_MAX_BASES +

+
+

+ 10 +

+
+

+ The maximum number of template arguments to the bases<...> + class template, which is used to specify the bases of a wrapped + C++ class.. +

+
+

+ BOOST_PYTHON_STATIC_MODULE +

+
+

+ not defined +

+
+

+ If defined, prevents your module initialization function from + being treated as an exported symbol on platforms which support + that distinction in-code +

+
+

+ BOOST_PYTHON_ENABLE_CDECL +

+
+

+ not defined +

+
+

+ If defined, allows functions using the __cdecl + calling convention to be wrapped. +

+
+

+ BOOST_PYTHON_ENABLE_STDCALL +

+
+

+ not defined +

+
+

+ If defined, allows functions using the __stdcall + calling convention to be wrapped. +

+
+

+ BOOST_PYTHON_ENABLE_FASTCALL +

+
+

+ not defined +

+
+

+ If defined, allows functions using the __fastcall + calling convention to be wrapped. +

+
+
+
+ +

+ These macros are defined by Boost.Python + and are implementation details of interest only to implementors and those + porting to new platforms. +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Macro +

+
+

+ Default +

+
+

+ Meaning +

+
+

+ BOOST_PYTHON_TYPE_ID_NAME +

+
+

+ not defined +

+
+

+ If defined, this indicates that the type_info comparison across + shared library boundaries does not work on this platform. In + other words, if shared-lib-1 passes typeid(T) to a function in shared-lib-2 + which compares it to typeid(T), that comparison may return + false. If this macro + is #defined, Boost.Python uses and compares typeid(T).name() instead of using and comparing + the std::type_info objects directly. +

+
+

+ BOOST_PYTHON_NO_PY_SIGNATURES +

+
+

+ not defined +

+
+

+ If defined for a module no pythonic signatures are generated + for the docstrings of the module functions, and no python type + is associated with any of the converters registered by the module. + This also reduces the binary size of the module by about 14% + (gcc compiled). If defined for the boost_python runtime library, + the default for the docstring_options.enable_py_signatures() is set to false. +

+
+

+ BOOST_PYTHON_SUPPORTS_PY_SIGNATURES +

+
+

+ defined if BOOST_PYTHON_NO_PY_SIGNATURES + is undefined +

+
+

+ This macro is defined to enable a smooth transition from older + Boost.Python versions which do not support pythonic signatures. + For example usage see here. +

+
+

+ BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE +

+
+

+ not defined +

+
+

+ If defined the python type of __init__ + method "self" parameters is properly generated, otherwise + object is used. It is undefined by default because it increases + the binary size of the module by about 14% (gcc compiled). +

+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq.html b/doc/develop/html/faq.html new file mode 100644 index 00000000..1c921bca --- /dev/null +++ b/doc/develop/html/faq.html @@ -0,0 +1,84 @@ + + + +Chapter 5. Frequently Asked Questions (FAQs) + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 5. Frequently Asked Questions (FAQs)

+
+ +

+ If what you're trying to do is something like this: +

+
typedef boost::function<void (string s) > funcptr;
+
+void foo(funcptr fp)
+{
+  fp("hello,world!");
+}
+
+BOOST_PYTHON_MODULE(test)
+{
+  def("foo",foo);
+}
+
+

+ And then: +

+
>>> def hello(s):
+...    print s
+...
+>>> foo(hello)
+hello, world!
+
+

+ The short answer is: "you can't". This is not a Boost.Python limitation + so much as a limitation of C++. The problem is that a Python function is + actually data, and the only way of associating data with a C++ function pointer + is to store it in a static variable of the function. The problem with that + is that you can only associate one piece of data with every C++ function, + and we have no way of compiling a new C++ function on-the-fly for every Python + function you decide to pass to foo. + In other words, this could work if the C++ function is always going to invoke + the same Python function, but you probably don't want + that. +

+

+ If you have the luxury of changing the C++ code you're wrapping, pass it + an object instead and call + that; the overloaded function call operator will invoke the Python function + you pass it behind the object. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/compilation_takes_too_much_time_.html b/doc/develop/html/faq/compilation_takes_too_much_time_.html new file mode 100644 index 00000000..2fb2fcbe --- /dev/null +++ b/doc/develop/html/faq/compilation_takes_too_much_time_.html @@ -0,0 +1,42 @@ + + + +Compilation takes too much time and eats too much memory! What can I do to make it faster? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Please refer to the Reducing Compiling Time + section in the Tutorial. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/does_boost_python_work_with_mac_.html b/doc/develop/html/faq/does_boost_python_work_with_mac_.html new file mode 100644 index 00000000..3b09e519 --- /dev/null +++ b/doc/develop/html/faq/does_boost_python_work_with_mac_.html @@ -0,0 +1,93 @@ + + + +Does Boost.Python work with Mac OS X? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ It is known to work under 10.2.8 and 10.3 using Apple's gcc 3.3 compiler: +

+
gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1493)
+

+ Under 10.2.8 get the August 2003 gcc update (free at http://connect.apple.com). + Under 10.3 get the Xcode Tools v1.0 (also free). +

+

+ Python 2.3 is required. The Python that ships with 10.3 is fine. Under 10.2.8 + use these commands to install Python as a framework: +

+
./configure --enable-framework
+make
+make frameworkinstall
+

+ The last command requires root privileges because the target directory is + /Library/Frameworks/Python.framework/Versions/2.3. However, + the installation does not interfere with the Python version that ships with + 10.2.8. +

+

+ It is also crucial to increase the stacksize + before starting compilations, e.g.: +

+
limit stacksize 8192k
+

+ If the stacksize is too small + the build might crash with internal compiler errors. +

+

+ Sometimes Apple's compiler exhibits a bug by printing an error like the following + while compiling a boost::python::class_<your_type> + template instantiation: +

+
.../inheritance.hpp:44: error: cannot
+  dynamic_cast `p' (of type `struct cctbx::boost_python::<unnamed>::add_pair*
+  ') to type `void*' (source type is not polymorphic)
+
+

+ We do not know a general workaround, but if the definition of your_type can be modified the following + was found to work in all cases encountered so far: +

+
struct your_type
+{
+  // before defining any member data
+#if defined(__MACH__) &amp;&amp; defined(__APPLE_CC__) &amp;&amp; __APPLE_CC__ == 1493
+  bool dummy_;
+#endif
+  // now your member data, e.g.
+  double x;
+  int j;
+  // etc.
+};
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/error_c2064_term_does_not_evalua.html b/doc/develop/html/faq/error_c2064_term_does_not_evalua.html new file mode 100644 index 00000000..c03ff124 --- /dev/null +++ b/doc/develop/html/faq/error_c2064_term_does_not_evalua.html @@ -0,0 +1,77 @@ + + + +error C2064: term does not evaluate to a function taking 2 arguments + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Niall Douglas provides these notes: +

+

+ If you see Microsoft Visual C++ 7.1 (MS Visual Studio .NET 2003) issue an + error message like the following it is most likely due to a bug in the compiler: +

+
boost\boost\python\detail\invoke.hpp(76):
+error C2064: term does not evaluate to a function taking 2 arguments"
+
+

+ This message is triggered by code like the following: +

+
#include <boost/python.hpp>
+
+using namespace boost::python;
+
+class FXThread
+{
+public:
+  bool setAutoDelete(bool doso) throw();
+};
+
+void Export_FXThread()
+{
+  class_< FXThread >("FXThread")
+      .def("setAutoDelete", &amp;FXThread::setAutoDelete)
+  ;
+}
+
+

+ The bug is related to the throw() modifier. As a workaround cast off the + modifier. E.g.: +

+
.def("setAutoDelete", (bool (FXThread::*)(bool)) &FXThread::setAutoDelete)
+
+

+ (The bug has been reported to Microsoft.) +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/fatal_error_c1204_compiler_limit.html b/doc/develop/html/faq/fatal_error_c1204_compiler_limit.html new file mode 100644 index 00000000..9622393b --- /dev/null +++ b/doc/develop/html/faq/fatal_error_c1204_compiler_limit.html @@ -0,0 +1,96 @@ + + + +fatal error C1204:Compiler limit:internal structure overflow + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Q: I get this error message when + compiling a large source file. What can I do? +

+

+ A: You have two choices: +

+
    +
  1. + Upgrade your compiler (preferred) +
  2. +
  3. +

    + Break your source file up into multiple translation units. +

    +

    + my_module.cpp: +

    +
    ...
    +void more_of_my_module();
    +BOOST_PYTHON_MODULE(my_module)
    +{
    +  def("foo", foo);
    +  def("bar", bar);
    +  ...
    +  more_of_my_module();
    +}
    +
    +

    + more_of_my_module.cpp: +

    +
    void more_of_my_module()
    +{
    +  def("baz", baz);
    +  ...
    +}
    +
    +

    + If you find that a class_<...> declaration can't fit in a + single source file without triggering the error, you can always pass + a reference to the class_ + object to a function in another source file, and call some of its member + functions (e.g. .def(...)) in the auxilliary source file: +

    +

    + more_of_my_class.cpp: +

    +
    void more_of_my_class(class&lt;my_class&gt;&amp; x)
    +{
    +  x
    +   .def("baz", baz)
    +   .add_property("xx", &my_class::get_xx, &my_class::set_xx)
    +   ;
    +  ...
    +}
    +
    +
  4. +
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/how_can_i_automatically_convert_.html b/doc/develop/html/faq/how_can_i_automatically_convert_.html new file mode 100644 index 00000000..cc186764 --- /dev/null +++ b/doc/develop/html/faq/how_can_i_automatically_convert_.html @@ -0,0 +1,146 @@ + + + +How can I automatically convert my custom string type to and from a Python string? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Ralf W. Grosse-Kunstleve provides these notes: +

+

+ Below is a small, self-contained demo extension module that shows how to + do this. Here is the corresponding trivial test: +

+
import custom_string
+assert custom_string.hello() == "Hello world."
+assert custom_string.size("california") == 10
+
+

+ If you look at the code you will find: +

+
    +
  • + A custom to_python converter + (easy): custom_string_to_python_str +
  • +
  • + A custom lvalue converter (needs more code): custom_string_from_python_str +
  • +
+

+ The custom converters are registered in the global Boost.Python registry + near the top of the module initialization function. Once flow control has + passed through the registration code the automatic conversions from and to + Python strings will work in any module imported in the same process. +

+
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/to_python_converter.hpp>
+
+namespace sandbox { namespace {
+
+class custom_string
+{
+  public:
+    custom_string() {}
+    custom_string(std::string const &value) : value_(value) {}
+    std::string const &value() const { return value_; }
+  private:
+    std::string value_;
+};
+
+struct custom_string_to_python_str
+{
+  static PyObject* convert(custom_string const &s)
+  {
+    return boost::python::incref(boost::python::object(s.value()).ptr());
+  }
+};
+
+struct custom_string_from_python_str
+{
+  custom_string_from_python_str()
+  {
+    boost::python::converter::registry::push_back(
+      &convertible,
+      &construct,
+      boost::python::type_id<custom_string>());
+  }
+
+  static void* convertible(PyObject* obj_ptr)
+  {
+    if (!PyString_Check(obj_ptr)) return 0;
+    return obj_ptr;
+  }
+
+  static void construct(
+    PyObject* obj_ptr,
+    boost::python::converter::rvalue_from_python_stage1_data* data)
+  {
+    const char* value = PyString_AsString(obj_ptr);
+    if (value == 0) boost::python::throw_error_already_set();
+    void* storage = (
+      (boost::python::converter::rvalue_from_python_storage<custom_string>*)
+        data)->storage.bytes;
+    new (storage) custom_string(value);
+    data->convertible = storage;
+  }
+};
+
+custom_string hello() { return custom_string("Hello world."); }
+
+std::size_t size(custom_string const &s) { return s.value().size(); }
+
+void init_module()
+{
+  using namespace boost::python;
+
+  boost::python::to_python_converter<
+    custom_string,
+    custom_string_to_python_str>();
+
+  custom_string_from_python_str();
+
+  def("hello", hello);
+  def("size", size);
+}
+
+}} // namespace sandbox::<anonymous>
+
+BOOST_PYTHON_MODULE(custom_string)
+{
+  sandbox::init_module();
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/how_can_i_find_the_existing_pyob.html b/doc/develop/html/faq/how_can_i_find_the_existing_pyob.html new file mode 100644 index 00000000..d423fdd5 --- /dev/null +++ b/doc/develop/html/faq/how_can_i_find_the_existing_pyob.html @@ -0,0 +1,103 @@ + + + +How can I find the existing PyObject that holds a C++ object? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ "I am wrapping a function that always returns a pointer to an already-held + C++ object." +

+

+ One way to do that is to hijack the mechanisms used for wrapping a class + with virtual functions. If you make a wrapper class with an initial PyObject* + constructor argument and store that PyObject* as "self", you can + get back to it by casting down to that wrapper type in a thin wrapper function. + For example: +

+
class X { X(int); virtual ~X(); ... };
+X* f();  // known to return Xs that are managed by Python objects
+
+
+// wrapping code
+
+struct X_wrap : X
+{
+  X_wrap(PyObject* self, int v) : self(self), X(v) {}
+  PyObject* self;
+};
+
+handle<> f_wrap()
+{
+  X_wrap* xw = dynamic_cast<X_wrap*>(f());
+  assert(xw != 0);
+  return handle<>(borrowed(xw->self));
+}
+
+...
+
+def("f", f_wrap());
+class_<X,X_wrap,boost::noncopyable>("X", init<int>())
+ ...
+ ;
+
+

+ Of course, if X has no virtual functions you'll have to use static_cast instead of dynamic_cast + with no runtime check that it's valid. This approach also only works if the + X object was constructed + from Python, because Xs constructed + from C++ are of course never X_wrap + objects. +

+

+ Another approach to this requires you to change your C++ code a bit; if that's + an option for you it might be a better way to go. work we've been meaning + to get to anyway. When a shared_ptr<X> + is converted from Python, the shared_ptr actually manages a reference to + the containing Python object. When a shared_ptr<X> is converted back + to Python, the library checks to see if it's one of those "Python object + managers" and if so just returns the original Python object. So you + could just write object(p) to get + the Python object back. To exploit this you'd have to be able to change the + C++ code you're wrapping so that it deals with shared_ptr instead of raw + pointers. +

+

+ There are other approaches too. The functions that receive the Python object + that you eventually want to return could be wrapped with a thin wrapper that + records the correspondence between the object address and its containing + Python object, and you could have your f_wrap function look in that mapping + to get the Python object out. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/how_can_i_wrap_a_function_which0.html b/doc/develop/html/faq/how_can_i_wrap_a_function_which0.html new file mode 100644 index 00000000..b107a256 --- /dev/null +++ b/doc/develop/html/faq/how_can_i_wrap_a_function_which0.html @@ -0,0 +1,86 @@ + + + +How can I wrap a function which needs to take ownership of a raw pointer? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Q: Part of an API that I'm wrapping goes + something like this: +

+
struct A {}; struct B { void add( A* ); }
+where B::add() takes ownership of the pointer passed to it.
+
+

+ However: +

+
a = mod.A()
+b = mod.B()
+b.add( a )
+del a
+del b
+# python interpreter crashes
+# later due to memory corruption.
+
+

+ Even binding the lifetime of a to b via with_custodian_and_ward + doesn't prevent the python object a from ultimately trying to delete the + object it's pointing to. Is there a way to accomplish a 'transfer-of-ownership' + of a wrapped C++ object? +

+

+ --Bruce Lowery +

+

+ Yes: Make sure the C++ object is held by auto_ptr: +

+
class_<A, std::auto_ptr<A> >("A")
+  ...
+  ;
+
+

+ Then make a thin wrapper function which takes an auto_ptr parameter: +

+
void b_insert(B &b, std::auto_ptr<A> a)
+{
+  b.insert(a.get());
+  a.release();
+}
+
+

+ Wrap that as B.add. Note that pointers returned via manage_new_object + will also be held by auto_ptr, + so this transfer-of-ownership will also work correctly. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/how_can_i_wrap_functions_which_t.html b/doc/develop/html/faq/how_can_i_wrap_functions_which_t.html new file mode 100644 index 00000000..ba8e1b97 --- /dev/null +++ b/doc/develop/html/faq/how_can_i_wrap_functions_which_t.html @@ -0,0 +1,124 @@ + + + +How can I wrap functions which take C++ containers as arguments? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Ralf W. Grosse-Kunstleve provides these notes: +

+
    +
  1. +

    + Using the regular class_<> wrapper: +

    +
    class_<std::vector<double> >("std_vector_double")
    +  .def(...)
    +  ...
    +;
    +
    +

    + This can be moved to a template so that several types (double, int, + long, etc.) can be wrapped + with the same code. This technique is used in the file scitbx/include/scitbx/array_family/boost_python/flex_wrapper.h in the "scitbx" package. + The file could easily be modified for wrapping std::vector<> instantiations. This type of + C++/Python binding is most suitable for containers that may contain a + large number of elements (>10000). +

    +
  2. +
  3. +

    + Using custom rvalue converters. Boost.Python "rvalue converters" + match function signatures such as: +

    +
    void foo(std::vector<double> const &array); // pass by const-reference
    +void foo(std::vector<double> array); // pass by value
    +
    +

    + Some custom rvalue converters are implemented in the file scitbx/include/scitbx/boost_python/container_conversions.h This code can be used to convert + from C++ container types such as std::vector<> or std::list<> to Python tuples and vice versa. + A few simple examples can be found in the file scitbx/array_family/boost_python/regression_test_module.cpp + Automatic C++ container <-> Python tuple conversions are most suitable + for containers of moderate size. These converters generate significantly + less object code compared to alternative 1 above. +

    +
  4. +
+

+ A disadvantage of using alternative 2 is that operators such as arithmetic + +,-,*,/,% are not available. It would be useful to have custom rvalue converters + that convert to a "math_array" type instead of tuples. This is + currently not implemented but is possible within the framework of Boost.Python + V2 as it will be released in the next couple of weeks. [ed.: this was posted + on 2002/03/10] +

+

+ It would also be useful to also have "custom lvalue converters" + such as std::vector<> + <-> Python list. These converters would support the modification of + the Python list from C++. For example: +

+

+ C++: +

+
void foo(std::vector<double> &array)
+{
+  for(std::size_t i=0;i&lt;array.size();i++) {
+    array[i] *= 2;
+  }
+}
+
+

+ Python: +

+
>>> l = [1, 2, 3]
+>>> foo(l)
+>>> print l
+[2, 4, 6]
+
+

+ Custom lvalue converters require changes to the Boost.Python core library + and are currently not available. +

+

+ P.S.: +

+

+ The "scitbx" files referenced above are available via anonymous + CVS: +

+
cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login
+cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/how_do_i_create_sub_packages_usi.html b/doc/develop/html/faq/how_do_i_create_sub_packages_usi.html new file mode 100644 index 00000000..1a902b48 --- /dev/null +++ b/doc/develop/html/faq/how_do_i_create_sub_packages_usi.html @@ -0,0 +1,41 @@ + + + +How do I create sub-packages using Boost.Python? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Please refer to the Creating Packages section in the Tutorial. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/how_do_i_debug_my_python_extensi.html b/doc/develop/html/faq/how_do_i_debug_my_python_extensi.html new file mode 100644 index 00000000..b8099db9 --- /dev/null +++ b/doc/develop/html/faq/how_do_i_debug_my_python_extensi.html @@ -0,0 +1,151 @@ + + + +How do I debug my Python extensions? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Greg Burley gives the following answer for Unix GCC users: +

+
+

+ Once you have created a boost python extension for your c++ library or + class, you may need to debug the code. Afterall this is one of the reasons + for wrapping the library in python. An expected side-effect or benefit + of using BPL is that debugging should be isolated to the c++ library that + is under test, given that python code is minimal and boost::python either + works or it doesn't. (ie. While errors can occur when the wrapping method + is invalid, most errors are caught by the compiler ;-). +

+

+ The basic steps required to initiate a gdb session to debug a c++ library + via python are shown here. Note, however that you should start the gdb + session in the directory that contains your BPL my_ext.so module. +

+
(gdb) target exec python
+(gdb) run
+>>> from my_ext import *
+>>> [C-c]
+(gdb) break MyClass::MyBuggyFunction
+(gdb) cont
+>>> pyobj = MyClass()
+>>> pyobj.MyBuggyFunction()
+Breakpoint 1, MyClass::MyBuggyFunction ...
+Current language:  auto; currently c++
+(gdb) do debugging stuff
+
+
+

+ Greg's approach works even better using Emacs' "gdb" command, since + it will show you each line of source as you step through it. +

+

+ On Windows, my favorite debugging solution + is the debugger that comes with Microsoft Visual C++ 7. This debugger seems + to work with code generated by all versions of Microsoft and Metrowerks toolsets; + it's rock solid and "just works" without requiring any special + tricks from the user. +

+

+ Raoul Gough has provided the following for gdb on Windows: +

+
+

+ gdb support for Windows DLLs has improved lately, so it is now possible + to debug Python extensions using a few tricks. Firstly, you will need an + up-to-date gdb with support for minimal symbol extraction from a DLL. Any + gdb from version 6 onwards, or Cygwin gdb-20030214-1 and onwards should + do. A suitable release will have a section in the gdb.info file under Configuration + - Native - Cygwin Native - Non-debug DLL symbols. Refer to that info section + for more details of the procedures outlined here. +

+

+ Secondly, it seems necessary to set a breakpoint in the Python interpreter, + rather than using ^C to break execution. A good place to set this breakpoint + is PyOS_Readline, which will stop execution immediately before reading + each interactive Python command. You have to let Python start once under + the debugger, so that it loads its own DLL, before you can set the breakpoint: +

+
$ gdb python
+GNU gdb 2003-09-02-cvs (cygwin-special)
+[...]
+
+(gdb) run
+Starting program: /cygdrive/c/Python22/python.exe
+Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32
+Type "help", "copyright", "credits" or "license" for more information.
+>>> ^Z
+
+
+Program exited normally.
+(gdb) break *&PyOS_Readline
+Breakpoint 1 at 0x1e04eff0
+(gdb) run
+Starting program: /cygdrive/c/Python22/python.exe
+Python 2.2.2 (#37, Oct 14 2002, 17:02:34) [MSC 32 bit (Intel)] on win32
+Type "help", "copyright", "credits" or "license" for more information.
+
+Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline ()
+   from /cygdrive/c/WINNT/system32/python22.dll
+(gdb) cont
+Continuing.
+>>> from my_ext import *
+
+Breakpoint 1, 0x1e04eff0 in python22!PyOS_Readline ()
+   from /cygdrive/c/WINNT/system32/python22.dll
+(gdb) # my_ext now loaded (with any debugging symbols it contains)
+
+
+

+ + Debugging + extensions through Boost.Build +

+

+ If you are launching your extension module tests with Boost.Build + using the boost-python-runtest rule, you can ask it to launch + your debugger for you by adding "--debugger=debugger" + to your bjam command-line: +

+
bjam -sTOOLS=vc7.1 "--debugger=devenv /debugexe" test
+bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test
+
+

+ It can also be extremely useful to add the -d+2 + option when you run your test, because Boost.Build will then show you the + exact commands it uses to invoke it. This will invariably involve setting + up PYTHONPATH and other important environment variables such as LD_LIBRARY_PATH + which may be needed by your debugger in order to get things to work right. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/i_m_getting_the_attempt_to_retur.html b/doc/develop/html/faq/i_m_getting_the_attempt_to_retur.html new file mode 100644 index 00000000..7d1f857a --- /dev/null +++ b/doc/develop/html/faq/i_m_getting_the_attempt_to_retur.html @@ -0,0 +1,67 @@ + + + +I'm getting the "attempt to return dangling reference" error. What am I doing wrong? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ That exception is protecting you from causing a nasty crash. It usually happens + in response to some code like this: +

+
period const &get_floating_frequency() const
+{
+  return boost::python::call_method<period const &>(
+    m_self,"get_floating_frequency");
+}
+
+

+ And you get: +

+
ReferenceError: Attempt to return dangling reference to object of type:
+class period
+
+

+ In this case, the Python method invoked by call_method + constructs a new Python object. You're trying to return a reference to a + C++ object (an instance of class period) contained within and owned by that + Python object. Because the called method handed back a brand new object, + the only reference to it is held for the duration of get_floating_frequency() above. When the function returns, the Python + object will be destroyed, destroying the instance of class + period, and leaving the returned + reference dangling. That's already undefined behavior, and if you try to + do anything with that reference you're likely to cause a crash. Boost.Python + detects this situation at runtime and helpfully throws an exception instead + of letting you do that. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/is_boost_python_thread_aware_com.html b/doc/develop/html/faq/is_boost_python_thread_aware_com.html new file mode 100644 index 00000000..55662715 --- /dev/null +++ b/doc/develop/html/faq/is_boost_python_thread_aware_com.html @@ -0,0 +1,60 @@ + + + +Is Boost.Python thread-aware/compatible with multiple interpreters? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Niall Douglas provides these notes: +

+

+ The quick answer to this is: no. +

+

+ The longer answer is that it can be patched to be so, but it's complex. You + will need to add custom lock/unlock wrapping of every time your code enters + Boost.Python (particularly every virtual function override) plus heavily + modify boost/python/detail/invoke.hpp with custom unlock/lock wrapping of + every time Boost.Python enters your code. You must furthermore take care + to not unlock/lock when Boost.Python is invoking iterator + changes via invoke.hpp. +

+

+ There is a patched invoke.hpp posted + on the C++-SIG mailing list archives and you can find a real implementation + of all the machinery necessary to fully implement this in the TnFOX project + at this SourceForge + project location. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/is_return_internal_reference_eff.html b/doc/develop/html/faq/is_return_internal_reference_eff.html new file mode 100644 index 00000000..45133816 --- /dev/null +++ b/doc/develop/html/faq/is_return_internal_reference_eff.html @@ -0,0 +1,62 @@ + + + +Is return_internal_reference efficient? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Q: /I have an object composed of 12 doubles. + A const& + to this object is returned by a member function of another class. From the + viewpoint of using the returned object in Python I do not care if I get a + copy or a reference to the returned object. In Boost.Python I have the choice + of using copy_const_reference + or return_internal_reference. + Are there considerations that would lead me to prefer one over the other, + such as size of generated code or memory overhead?/ +

+

+ A: copy_const_reference + will make an instance with storage for one of your objects, size = base_size + 12 * sizeof(double). + return_internal_reference + will make an instance with storage for a pointer to one of your objects, + size = + base_size + + sizeof(void*). However, + it will also create a weak reference object which goes in the source object's + weakreflist and a special callback object to manage the lifetime of the internally-referenced + object. My guess? copy_const_reference + is your friend here, resulting in less overall memory use and less fragmentation, + also probably fewer total cycles. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/why_doesn_t_my_operator_work.html b/doc/develop/html/faq/why_doesn_t_my_operator_work.html new file mode 100644 index 00000000..d0be0be5 --- /dev/null +++ b/doc/develop/html/faq/why_doesn_t_my_operator_work.html @@ -0,0 +1,63 @@ + + + +Why doesn't my *= operator work? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Q: I have exported my class to + python, with many overloaded operators. it works fine for me except the + *= operator. It always tells + me "can't multiply sequence with non int type". If I use p1.__imul__(p2) + instead of p1 *= + p2, it successfully executes my + code. What's wrong with me? +

+

+ A: There's nothing wrong with you. This + is a bug in Python 2.2. You can see the same effect in Pure Python (you can + learn a lot about what's happening in Boost.Python by playing with new-style + classes in Pure Python). +

+
>>> class X(object):
+...     def __imul__(self, x):
+...         print 'imul'
+...
+>>> x = X()
+>>> x *= 1
+
+

+ To cure this problem, all you need to do is upgrade your Python to version + 2.2.1 or later. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/faq/why_is_my_automatic_to_python_co.html b/doc/develop/html/faq/why_is_my_automatic_to_python_co.html new file mode 100644 index 00000000..2efaf07a --- /dev/null +++ b/doc/develop/html/faq/why_is_my_automatic_to_python_co.html @@ -0,0 +1,67 @@ + + + +Why is my automatic to-python conversion not being found? + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ Niall Douglas provides these notes: +

+

+ If you define custom converters similar to the ones shown above the def_readonly() + and def_readwrite() + member functions provided by boost::python::class_ + for direct access to your member data will not work as expected. This is + because def_readonly("bar",&foo::bar) is equivalent to: +

+
.add_property("bar", make_getter(&foo::bar, return_internal_reference()))
+
+

+ Similarly, def_readwrite("bar",&foo::bar) + is equivalent to: +

+
.add_property("bar", make_getter(&foo::bar, return_internal_reference()),
+                   make_setter(&foo::bar, return_internal_reference())
+
+

+ In order to define return value policies compatible with the custom conversions + replace def_readonly() + and def_readwrite() + by add_property(). + E.g.: +

+
.add_property("bar", make_getter(&foo::bar, return_value_policy<return_by_value>()),
+                   make_setter(&foo::bar, return_value_policy<return_by_value>()))
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/glossary.html b/doc/develop/html/glossary.html new file mode 100644 index 00000000..63d0003d --- /dev/null +++ b/doc/develop/html/glossary.html @@ -0,0 +1,81 @@ + + + +Chapter 6. Glossary + + + + + + + +
+
+
+PrevUpHome +
+
+

+Chapter 6. Glossary

+
+

+
+
arity
+

+ The number of argumnts accepted by a function or member function. Unless + otherwise specified, the hidden this + argument to member functions is not counted when specifying arity. +

+
ntbs
+

+ Null-Terminated Byte String, or 'C'-string. C++ string literals are + ntbses. An ntbs + must never be null. +

+
raise
+

+ Exceptions in Python are "raised", not "thrown", + as they are in C++. When this documentation says that some Python exception + is "raised" in the context of C++ code, it means that the corresponding + Python exception is set via the Python/'C' + API, and throw_error_already_set() is called. +

+
POD
+

+ A technical term from the C++ standard. Short for "Plain Ol'Data": + A POD-struct is an aggregate class that has no non-static data members + of type pointer to member, non-POD-struct, non-POD-union (or array of + such types) or reference, and has no user-defined copy assign- ment operator + and no user-defined destructor. Similarly, a POD-union is an aggregate + union that has no non-static data members of type pointer to member, + non-POD-struct, non-POD-union (or array of such types) or reference, + and has no user-defined copy assignment operator and no user-defined + destructor. A POD class is a class that is either a POD-struct or a POD-union. + An aggregate is an array or a class (clause 9) with no user-declared + constructors (12.1), no private or protected non-static data members + (clause 11), no base classes (clause 10), and no virtual functions (10.3). +

+
ODR
+

+ The "One Definition Rule", which says that any entity in a + C++ program must have the same definition in all translation units (object + files) which make up a program. +

+
+
+
+ + + +
+
+
+PrevUpHome +
+ + diff --git a/doc/develop/html/images/alert.png b/doc/develop/html/images/alert.png new file mode 100644 index 0000000000000000000000000000000000000000..b4645bc7e7cd81f2818bf22aa898e95f89f7b154 GIT binary patch literal 603 zcmeAS@N?(olHy`uVBq!ia0y~yV31^BU=ZVAW?*1oN<7}ez`(#Bl2vQw%VQUVy#($c(b7<_!Z&&*`7 zwYIFTuIA!kP?6(!`t<3^g$y0J3{Q73WQH(YSjJ#(AQj-}VXe>LZ_gkv$q?hiVP&Xj ztS4or%^)MjpsB?1|Nnp9pi5p13=F0vL4Lvi$p8#BTQ7jZgtNdSvY3H^>jMZgI;}C8 z!N9FSxfgB=H7N+NC77H_+N#nawR{=RqTMBX)(LXL|IjinhDSdCyWWZ3S$0kBOZbahGm>{cU3L4X z*xaKNrl+L*2&>`tT{GF}sK6TCoSy58@94C>csZ@3se0z)OD!J`ePg?KNk!eRu!nuZ zwIuy5g5`UyU*2!`JMiPV^UIVvmW1t{f1*^~1#9h_jDIZO*R6JmbN8&QBXd?)zY=(& z`HG+Mis#k2-hNM1nwI_8efYU@yAuCZhY42|Be;Juo!svFUA16}A_D^hgQu&X%Q~lo FCIA+53ZVc1 literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/blank.png b/doc/develop/html/images/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..764bf4f0c3bb4a09960b04b6fa9c9024bca703bc GIT binary patch literal 374 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 literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/bpl.png b/doc/develop/html/images/bpl.png new file mode 100644 index 0000000000000000000000000000000000000000..c2d8c69e00ca3aada62024809e20d138a8906875 GIT binary patch literal 21289 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 +image/svg+xmlBoost.Python + \ No newline at end of file diff --git a/doc/develop/html/images/callouts/1.png b/doc/develop/html/images/callouts/1.png new file mode 100644 index 0000000000000000000000000000000000000000..6003ad3af44ecde89a963d5af6a4180217319dfb GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`*F|>EaktF{gKeVcsDJ z0oVU;*6~a;Smx2ZrsEQ?ZxM&ygvBnFE?nmtg94rky>!~x8m)3j$<^(USQPg)>&zq; zMi;kRX=V2=&tIr>`d!)XyUpL@9=UmHetuZ+!_#HmOU>-J$pS3-bN!ardIyAF-G1#? z>&)f7E`k#|4sWoP;JM|(l6I_WZ`%~1y>agujE%b%?TB9+mb}(fsxyPFgQGMy*=%;A z(aZyu>`GQPiY$*T-1gu1pAwY3_N%b5cB#xoiRPn8jf*q{Trb|_a%sui&dtzin6_r? zu}%d~p(mAmOGTO#c2u;xJ(}Y^?ex>t7XL(?7U+1p1hOa|ab;w%c)sCoo@_(^WX<=s zr#89B91nl^w~jx#=XQ?S<*?OXYm`>JmO9g8;`^U+STt2<{M7jt yFTo&UT%Db3I{*CoWB+`guig6oxB + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/10.png b/doc/develop/html/images/callouts/10.png new file mode 100644 index 0000000000000000000000000000000000000000..0426f516a497db7f9a989ae412c381123c882a59 GIT binary patch literal 485 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`(f1)5S5QVovKM!_~JE zMB47_a|Rw%VTn}{6Ibo_{>?on>HF_suX>mE-_|+p)}_VbyG%XWRxDs!Bbdb`rSkCf z_opQpQ)e&z9?Q3;X^2drllMU70&71c8CwuJm{abIp zeHPuYNTZJ3@x#oHxOW1*hRe1@t$mhYkYRMp!NudU$f{L`HtEbcpPpkT-Q%WwW82?% zC04fVjt$l>J1E5m&cv;Mo-ym249h`b!OT;yI|^kU z7g#)~+Iz@=rzNo?Z+rL2lqSFB&0ni{FPmfwyfr;gD5K)Z38R1FYejhuGSfQP|hTIvQJ?m5M8zE|_KJ2Ny0Fm1o>%kU%6J0MhalaBNL z`|XP~Ht29?&a!*3EqAew_mM&!z3HdD7hn7l!t9~x=u!|XzH8m#&o*bC7c(?GuT1E< zIxY74U)KBI?en(Zj`8vg@_IC9@{~!dRw-$!in=2h%i uo%h^T#Pz@K#3`Fjeg5 + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/11.png b/doc/develop/html/images/callouts/11.png new file mode 100644 index 0000000000000000000000000000000000000000..821afc4fa84787cc97485b71e9f2078f45c93dca GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`&U3>EaktF{gFX#;)5A z0&V{%irr-ME}D3(<3UjG?A^;f=DTxNc8JvRJ?~omN$9208L_ft0gE{24F|>2&Q_(X zyZRk}S@Y!IJLwtuX$cuSW9kad-E9>}+B4ar@B8JKU&IA}ZdvzvdHazWz|5Z1g ze)`Eh`){a=Ty&?>q6`CxFY1#$=XWS5S;+8pJeF8|am8VmFNNE0pWSjTLp3m4UCF?B z)v7}^cJ1H)wSBfZUSXp*CCGT~*L1 z!O^woK;8cKATG~IcM5iAPD}l8PyF`VZ_(}ou7b0cInG+vv8ev~-ZX{}_a4{SRWsNx zp57$DG;5jTyyy8w3^D7&C6fPqtf+bOwJP3 + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/12.png b/doc/develop/html/images/callouts/12.png new file mode 100644 index 0000000000000000000000000000000000000000..7cec72720fa9bb6f49fc4b405f7e36f20abe7fbd GIT binary patch literal 488 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`(fP)5S5QVovKM+tara zMB3h~S9S>cC`GVy&NA$7e!FZ3*ZX_(gMKMn{jgqg*t>n5-mVwdc+LxmI|e9UlrZu5 zQ({_ROHtjRNV$1z%lk=bT+YJ`-QVnLY|jT_oBf)`qRPnx(gN%Xx|4tEMdaVwoi3 z8lgAcLau*<4)^ratatOor+TqI{wNVS?clathJwW!uZ)j$%&5q+Ew{P&-MZ_q|3(_ifRH$!b{%@XfPPgvO) wR!x~yId8sr_tEzopr0G&e8k^lez literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/callouts/12.svg b/doc/develop/html/images/callouts/12.svg new file mode 100644 index 00000000..9794044c --- /dev/null +++ b/doc/develop/html/images/callouts/12.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/13.png b/doc/develop/html/images/callouts/13.png new file mode 100644 index 0000000000000000000000000000000000000000..5b41e02a670f020ae62b7854482c4ba1980d73cf GIT binary patch literal 509 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`%IK)5S5QVovKN`}4B` zMA$w&XL9s;aOlF(1%)YvneO4jm-o(&U;MKD#e?Mq8+>b)^R3G((>5$`ILflv=tsMT zqri^uWh?XJrteF)Ir(#L@uYSZ#}5m2PWL-;h`yh)YSr?%_21hCg6ylJ<~^TZ68k@M z*0PUs0U}2m4Zrz%{ru!$;?!{|$E-JRd$xd+!qOu@YuZ+=+K?-K{IOu7#Gy?(C029K zJuHwgKK8+3O1mEi<8zsP?~|?OE?SqZ;@R}Hh*OcJN#Q`=cIVYsi%fl`jgRf~&@_Gf zwzE(sdH3B%ReKL@(z)}#{LAm!8Ou74CNVNBn8MT`ef;AL!#4E;rLlAT)H7zW#a>U8 zU^AP|o3>d}=J>$`0|rHwDM43C-@g0)`~9hChd_}fnOvtgEzsbyc%HHSwnVR+$0Qaf z4hDzV>nAp?Vf*l#Q@}~VH~7Z3-c_p%=AWOKD!ECAd8tU(q6Mq8jughk>rJ2Tw)o@M zm#pV3mrVI!!@p|Pp+XrSHQ@j+Lm56tj!LO-Hu>!LzuT|B{(4Tap5^mRI^HKOr#o>( zhECmcH*b>$SLC#%J&RUEtqrq3WKa^{tg=+3a-Mjg$X|1pImHv7|6G6l?EhE#0)GDv Vq@B#jVqjok@O1TaS?83{1OO3{ + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/14.png b/doc/develop/html/images/callouts/14.png new file mode 100644 index 0000000000000000000000000000000000000000..de5bdbd3eb8be01d27b6f1a345d586d0c4d61b2a GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`(f6)5S5QVovL&ji+t} zh_HY7zn8PK$&+QbhfZH4OXk6oR~J^xFa4ru^@GK(LHCDmEpzN0DV1hDCj-+7ZjQ+v zYTxf&UV7^JrT0DT=ibj@uHP27{{Ga|pN^VKANF1{d3)jY*E+*vNA@lkcl~(Lphv#f zZSgm;g1vG7SsXu1?TCBVaZcj#*Q&kO-j-$e7zzmX9alE-b>4iFg+V~@k_l_W_wBcH zWmp*BaqNHHW9Xsz@VDKv%bG0$2|bO5Z6>~kGkrGPetRKrdu;6W&)@+-S^-5e@qWpx=%~ppu-*HbtcU?B((KtQse2TO*ZEl8Jswt zRO&J4%x73CvPq};vBd=w-op^F6<=oH98=hD0fB5^~^0#Ht9-5wBo~e + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/15.png b/doc/develop/html/images/callouts/15.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd6ac38603390bf6f9bbfdb85ddb203e2edc421 GIT binary patch literal 507 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`%IO)5S5QVovL&-F>$L z1lS(@e{k6MP=#(Q)65P&Df1-{87Bltt+Mf&((ZAvc!Ef@>!Js&9H9b5iNOkrjBYL6 zJ*_!sB>iV?h@ACiit<@=<+J)R*K4P%cxw9w^X5-kmdSp5TRo@ZmA&eVHGWMv{dC`S zuce2g9b}I0mp%UT(3$h)E?kO6N0T-NtiR6f#9?6EcU;-Tw>eSb#{2IdZ1@=hR$sjr zzyA8Z#}+%3XYST(VGvBTnww-G;h@R7RHW^&qTY1wDM1E2%vZCnP73-ad;I5-GeP_8 zE`G0F6Q(`qeEN%Bd`m@QuDc4b82Acr%ROx3%dny5{(I}bX7&S{bY%G0Jv1kte!3xU z{l(W`FJx^snCW9M|9s%ekN~~u3#V){n|<~=yTas?3Ovp)cJVPNC~di&>!G + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/16.svg b/doc/develop/html/images/callouts/16.svg new file mode 100644 index 00000000..01d6bf81 --- /dev/null +++ b/doc/develop/html/images/callouts/16.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/17.svg b/doc/develop/html/images/callouts/17.svg new file mode 100644 index 00000000..0a04c556 --- /dev/null +++ b/doc/develop/html/images/callouts/17.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/18.svg b/doc/develop/html/images/callouts/18.svg new file mode 100644 index 00000000..1cb891b3 --- /dev/null +++ b/doc/develop/html/images/callouts/18.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/19.svg b/doc/develop/html/images/callouts/19.svg new file mode 100644 index 00000000..e6fbb179 --- /dev/null +++ b/doc/develop/html/images/callouts/19.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/2.png b/doc/develop/html/images/callouts/2.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c1578846cd7e67f148e7bbe3178ec170050e48 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`)q*>EaktF{gFH!7eFB zfwuoy?SYP89?67Uc^u>7$ueKD;_TuU8yCKP?%y^nk6}6Q`Xb ztf|`>GH3mp6jYb?>^RdSfr%@^R!^go|6uIuQi$NDW>upBo%&=x}fma9VINW5Ly|Qkmm3JvHr(Hb1rr&)I%k zqW}1XsO0Up4@Uid#O=~jwU>`!u0>yZkk=jF7J(OKyBQi3I1HqEAMAR!+FC^5{Aa5( zf1b8B8nUgv%H`5>GKER;h_=JWcU60(815ha{H$oF%dBM*eC_{b&TZl;l$m|{>8A+2 z>GpSd7ik$I?GB%onzMHA^lP*F zk0)=tnX|7g@rLFCKI7=6AyTdvVl+z`(%Z>FVdQ I&MBb@0M`i8D*ylh literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/callouts/2.svg b/doc/develop/html/images/callouts/2.svg new file mode 100644 index 00000000..07d03395 --- /dev/null +++ b/doc/develop/html/images/callouts/2.svg @@ -0,0 +1,17 @@ + + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/20.svg b/doc/develop/html/images/callouts/20.svg new file mode 100644 index 00000000..ccbfd403 --- /dev/null +++ b/doc/develop/html/images/callouts/20.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/21.svg b/doc/develop/html/images/callouts/21.svg new file mode 100644 index 00000000..93ec53fd --- /dev/null +++ b/doc/develop/html/images/callouts/21.svg @@ -0,0 +1,18 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/22.svg b/doc/develop/html/images/callouts/22.svg new file mode 100644 index 00000000..f48c5f3f --- /dev/null +++ b/doc/develop/html/images/callouts/22.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/23.svg b/doc/develop/html/images/callouts/23.svg new file mode 100644 index 00000000..66242129 --- /dev/null +++ b/doc/develop/html/images/callouts/23.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/24.svg b/doc/develop/html/images/callouts/24.svg new file mode 100644 index 00000000..a3d55253 --- /dev/null +++ b/doc/develop/html/images/callouts/24.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/25.svg b/doc/develop/html/images/callouts/25.svg new file mode 100644 index 00000000..56614a97 --- /dev/null +++ b/doc/develop/html/images/callouts/25.svg @@ -0,0 +1,21 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/26.svg b/doc/develop/html/images/callouts/26.svg new file mode 100644 index 00000000..56faeaca --- /dev/null +++ b/doc/develop/html/images/callouts/26.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/27.svg b/doc/develop/html/images/callouts/27.svg new file mode 100644 index 00000000..a75c8121 --- /dev/null +++ b/doc/develop/html/images/callouts/27.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/28.svg b/doc/develop/html/images/callouts/28.svg new file mode 100644 index 00000000..7f8cf1a3 --- /dev/null +++ b/doc/develop/html/images/callouts/28.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/29.svg b/doc/develop/html/images/callouts/29.svg new file mode 100644 index 00000000..cb63adf1 --- /dev/null +++ b/doc/develop/html/images/callouts/29.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/3.png b/doc/develop/html/images/callouts/3.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff0a93931515bb97a045dfa61a8530d87e458fd GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`$7M>EaktF{gFH*{(+p zB5wOOu6l7m)8 z=-oKUH}V^&iJyB|uo8LF()AHB5)-MfO`N3nt zvX}OXM~sd8*9*0GtV!A!kzpdmy4F;zn{|?kqeR<^5G@5I1_ong&q>Sg=9!B)JHv7pU)=hauMINB3;oaL&ye>}mU!H{id4Bxig=9%^>^=*s?64R8I`k2o? pd-p8Ef~{sjr?y8+Fx+F*x_2OD_kw447#J8BJYD@<);T3K0RY@Tw*mkF literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/callouts/3.svg b/doc/develop/html/images/callouts/3.svg new file mode 100644 index 00000000..918be806 --- /dev/null +++ b/doc/develop/html/images/callouts/3.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/30.svg b/doc/develop/html/images/callouts/30.svg new file mode 100644 index 00000000..dc43ba1e --- /dev/null +++ b/doc/develop/html/images/callouts/30.svg @@ -0,0 +1,22 @@ + + + + +]> + + + + + + + + + diff --git a/doc/develop/html/images/callouts/4.png b/doc/develop/html/images/callouts/4.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa29fc0b48c17aa6ce5540e1af5c00510c33ff7 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`)qx>EaktF{gFH#x5mC zfwup%GG$o)=ergqP)_hu?Cbmc-FuV6=PTSkE z?z;W`K`XyJWKnY38^_LI-}iXo6rn{K^Ugm{NGsVLTQQIQc;ScrMIF~}*~{?xZ|}UC z)%voeOU2Vbu7Bb(%{5!g=daxAHc3V5z+>?E76HlSc>&q{{ zJgU5>EY^K=``x_dYqp*_vnNK+lE-=9auZ+6u0=XLho7HKd(8afJ98Qv1B>H_g?h*I z^7xt(_!*jJt_^x6<$Ce%iJd)$VVYl~OqdVEFZF#=7-s1t%fP_E;OXk;vd$@?2>|9n B#bp2h literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/callouts/4.svg b/doc/develop/html/images/callouts/4.svg new file mode 100644 index 00000000..8eb6a53b --- /dev/null +++ b/doc/develop/html/images/callouts/4.svg @@ -0,0 +1,16 @@ + + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/5.png b/doc/develop/html/images/callouts/5.png new file mode 100644 index 0000000000000000000000000000000000000000..36e785867ad9b06bb5da296fee61b67cd8159ded GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`&U2>EaktF{gFn*{nkj zBCY4o9LZ47@QCRUnZAf+N!}-g*k62kUh<2$=N}3cU-wJsu7~Tf`D?j51GwEfg_G2_ zuV#t97&qf=>*tSit#h_USr*FJFU!>WaGpbPU+ne2DLtw;&jomW^|@TLId}ILd4;Y; z`kGI<1$&J<4oW?f4p9*ch$x|rP+;KqSwET0Ksa~vKtM(>J91HOJ>EhB>xN^tsw+8di7uv`rMqUeL zJtlGLsS$%o&3$<<&56<(YY$o;PcU%UfB(F1o@3V5sOFBi;${Vo2fOrSjvstkva9-x zil;zZBGUt9^BXy4GknxI4hvj-p!#HTV6S6ePsEk3N^VkheYYwwc>v z!48gj&!5^CXy3`&YF5dr$YOKedHr?gg#ir$OfFx%f9Fdu@F;mr4Z2vhci-*k?73P? f@97_A_`n?SY~RWh)zCHu1_lOCS3j3^P6 + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/6.png b/doc/develop/html/images/callouts/6.png new file mode 100644 index 0000000000000000000000000000000000000000..c943676beafa0562916b058c169951febcd3cddb GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`$7M>EaktF{gFH{#8D;%7vjax1W#KXIAnv(J`n z&5VyM+63~m6_r{NIT!+`rAn_gmE-I&+!3QUA?T1q^ClfZ7RG!2%96cqg2wgyaq?lS zMX$X!U8LbO@45W6mvfv$L-`J@Z+FmS&DLGD$|-VMfY)E~efQs=*mUM;<-bcWOZM5Z zTz)B%D3P@Lt`d*4kJ{wr1(Q_j + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/7.png b/doc/develop/html/images/callouts/7.png new file mode 100644 index 0000000000000000000000000000000000000000..20940de30d2146b73118a08905955162fe985f68 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`z*d>EaktF{gLJ{wyX( zf%f{%yMM5|1Qs>DxO#n#YtRpleGYL4%{eMNMC?4cR!{jhN$+gat*(bhBwQW8eR)?F zba$a+^0L_vzt^7O@l~6=`|-z${Iyee1O}bTzyIC7L&Goql*H!=r=P}oFAaJ)O@ZgI z{@Sm`#{5B@N=kt`V%+OqiyeDxcc)!#?*L7k5+eADVIg?*L>hpfK3x*)1hCVBt; z;|%wV8@Gym{wcFIjN7SWb%BU0N0Y+6yzR|3cK@fSPF7(wKKyx4{o#4fYt#Iv1TDJ# z*2#-AZQqV>`4S8w#?i?>7PHU(+hgr1l-*Nl-OBiY{af+c^=0Sh`7 + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/8.png b/doc/develop/html/images/callouts/8.png new file mode 100644 index 0000000000000000000000000000000000000000..d8e34d4a09f6dca4f9c22e626d9f9d82b969b02c GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`$7P>EaktF{kyy#=ct) z0&EZJryZ5xyvdOv(510`p{HDvlxC~E$|>iVgULHQ3PYvrom?h2P4(>+k=FEToVfLb z-1}ul4-dV}J2m&O{aGGazV^u2>+);2+U^P78~6Tv*4AI1E_e2NCZAD1|9M}poAQ6# z2UUCjU5lzOJ!f0qp`v6c!}s@T(aY_*-6p<)(^RJf%{ZH;pv2Hn%$FKjXEE0=dabFI zOUbTczTJ2ED(5xNoT$P%L(+vssY!q-Q6kB1zW$Oa(QCh^Kc6#2_JRrTx8JslG@1mM zBBvdU`kln8=_3m^%&og1Cq^RrH#tzmz{IfafeFfcH9y85}Sb4q9e0BP^KrT_o{ literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/callouts/8.svg b/doc/develop/html/images/callouts/8.svg new file mode 100644 index 00000000..c1803a3c --- /dev/null +++ b/doc/develop/html/images/callouts/8.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/callouts/9.png b/doc/develop/html/images/callouts/9.png new file mode 100644 index 0000000000000000000000000000000000000000..abe636072b61306fbcd6157b95dfdf7e86a77e5d GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU=UznVBqFpV_;w?d&FzWz`&U8>EaktF{gEcf7T%f znb!OIl8YM`EC?0g)MK6LySsR*bBW@-#a{$sD|jaA?Rq5|BVw*<(2>_Fw2;L_Ls+eT z*=m-pP5G8*zMrjje*N{AqvqEc&v$lO8~PeQnNu$u7&XUG^XcT&$oGAZue{@YWbseb zX;0Q#doE68rNi6aM(w}9J~guKY8ESl1YdhX&(saqqyj~D?!KF+)#9L-_*{J2Y1Ks< zObjyp?mceG5^anO3Q8tYyaIvx98EzeZXaKe_`Z|7b6wRX+{3FhZAn{V<2dEM9+du_kptYsE+ z{WKfa2W_~S^T2{nZ8E1=H*3uG*3`)V4^%t_SRAV?Wb9U5edYbrW%=bs0jAGCWzMDv z&-uLjLxRB%P3bLBx;@8}pH%jFEoHiFvT*CZ6}7y~440#x2c4?eefQp-XqD5OV!VD< d@-ZKf|NC_Jf+y*vd<+Z>44$rjF6*2UngH>Mv>N~b literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/callouts/9.svg b/doc/develop/html/images/callouts/9.svg new file mode 100644 index 00000000..bc149d3c --- /dev/null +++ b/doc/develop/html/images/callouts/9.svg @@ -0,0 +1,19 @@ + + + + +]> + + + + + + + + diff --git a/doc/develop/html/images/caution.png b/doc/develop/html/images/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..5b7809ca4a9c8d778087522e5ce04b6e90099595 GIT binary patch literal 1250 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NW(e>Jab;j&;NV~o5MYpy zU{F+KFf?Rva$<;zVn|MA$j)XcE@r5%W@u?)XlW_#>0#*UDemd%nKFf8%9P?MQ>y38 zVVEwkZjIWyHF@jSt$X(}?A@Du?i|Cp zbLXyIW4Lzh+_h`h?%iX!chB(NJdh*`E$$X&!4}4&+z{J`|sZwzJC|^ z{$1kxcf;@BzyJTw@c+NS|Nj#IN5NBISn~R-X--a%afBxQ|J!3zMjr_SU zk_iHr)f*lf{$5^Qz}I)@3FlWvw(w~u=1P@VsTP+$RNGvxbHL-(%M6nc6`{zlU zjGQJeveps+!&Jb&mD)L@hA} z1_tL6*NBqf{Irtt#G+IN2MuLS&)mfHRNut(%;anZ6Fnn63k6F{eFF=914D)6qRirw zN{8Ia;*!i{z0_j8l+uFyyb`_S{M?DV6n8K%Fld2|%S_KpEGaEYWk@zRFt#waFg8d` zG)YZPF-fe)lBATd3a!N{b-$VA&f+n^|#(~yCI Ofx*+&&t;ucLK6T%G-N*j literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/caution.svg b/doc/develop/html/images/caution.svg new file mode 100644 index 00000000..4bd586a0 --- /dev/null +++ b/doc/develop/html/images/caution.svg @@ -0,0 +1,68 @@ + + + + + + Attenzione + + + + pulsante + + + + + Open Clip Art Library + + + + + Architetto Francesco Rollandin + + + + + Architetto Francesco Rollandin + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/develop/html/images/draft.png b/doc/develop/html/images/draft.png new file mode 100644 index 0000000000000000000000000000000000000000..0084708c9b8287c51efa6b40b8d492854191455e GIT binary patch literal 17454 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 YsPxZ;53A2HFfcH9y85}Sb4q9e0Fi|iga7~l literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/home.png b/doc/develop/html/images/home.png new file mode 100644 index 0000000000000000000000000000000000000000..5584aacb097a80e66a5320312b6e4eb017af1a06 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?WS z3GfMV6&Dfg?(A@OuseF>a6(*+nzF*onKLh6zO-%YmOy{sw6wJU|Nk%gvq74Hfq|za z$S?Rm0x$^OKX;CSfq}EYBeIx*fm;ZK886+f`@_J%pjzS@Q4*Y=R#Ki=l*-_nm|T>f zo0^iDsNj}alvU8YOY t9}F9JU6`43jMG5vNQA& + + + + + + + +]> + + + + + + + + + + + + + + diff --git a/doc/develop/html/images/important.png b/doc/develop/html/images/important.png new file mode 100644 index 0000000000000000000000000000000000000000..12c90f607a1b27ddde0a7d922ae255e8c90e883e GIT binary patch literal 722 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NcoN_f;wr$vARr(hAt9lu zscC6x>EvV>6{VS+EaBwj6ciMco$ZvI98_E!l$@NLot<4>UER|o(bHqOcQ41TYc{y!?kM?_wFg)yJvXsp5^oB z9Pi&Vyniq7|3Ab3{~Z7S3p{_W`TV)z`}cpO z$(;G%_wGG* z?AW<;=dNA5cJJQ3=g*(NfB*jb_wWDz|6hCQ@I3|w2F4_BcNgdM3%p4T42R|DNig) zWpL0?*7VFxOi%SqOwUZtRxr^s(z8&owA44S&^IttNG{4OE~#|Ltt>9dOx8;+)=McZ z$j>X$OU}=oxJz*d0|SE=*tpE}yu^~yqEv=t literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/important.svg b/doc/develop/html/images/important.svg new file mode 100644 index 00000000..dd84f3fe --- /dev/null +++ b/doc/develop/html/images/important.svg @@ -0,0 +1,25 @@ + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/doc/develop/html/images/jam.png b/doc/develop/html/images/jam.png new file mode 100644 index 0000000000000000000000000000000000000000..224ed7914bb5a31a407511093500aa1fe9d9e571 GIT binary patch literal 3884 zcmeAS@N?(olHy`uVBq!ia0y~yV5nzcU~uJNV_;xNjW#hE=bLrwBlWk7u9BNWG%WIzG^?ia{Jx0?d2cu65lo_tIq4R{ZpB|^Gj6) zSQHbUotHf@zxm;v$tNPW%s1Luc2<|6?FW0^VrZqF7Q%Y`1Ew|lr=xYj$EHQEz3mDMmMpd z>ejiX)97pynn`5kW z|CRi$_`uF-U0Tl!|N5S1TOOPDXU~o+TYOinI`YoqQ_`=^1)VOOpVS2UPMZHtf92(U zF(~lpmyJ~=b>FwfdM6w>w@64vPjkD9T!BlS8{-PeFW+C~FR$XwJ;(0LL4_y0b2(bBrxt6b;~fkM&QareVtIlX>mx{c)k=f}URyJiaR zcRjOF;pM%D1^TaQcvl$+gnzii-F1xrciDrp+t{xBlnQwM`lzw)`c>DOBDhY4PWZnt zR)FQek=PkocKsFVcH$fQ_AtJdIN(>n{=t*q-~sQq@h3+fzfG`F{L=O>KV|n{Gpl%-%i!=JgyXArJMZ($hYaT!{XP6Jj;Fo) z|Aw2nSEX5*73

m`0On#VPL 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 + + + + + +]> + + + + + + + + + + + diff --git a/doc/develop/html/images/next_disabled.png b/doc/develop/html/images/next_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..10a8c59d7b3741260b7bfe918b62d0670cad8433 GIT binary patch literal 1110 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj4rT@h2G_o0{}>n;SkfJR9T^xl_SO6joXo($ zppfhlZ{Pm>`SaViZ};!tyLt1*|NsBbojZ3P6EBL3=9l=JzX3_ zD&{0TNo#1Z_o+&KnDHU@)Rs;LG+GiER_Ffe$!`njxgN@xNAPfH=1 literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/note.png b/doc/develop/html/images/note.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c3c645ab9af6318035b026dd86944b9ddc9114 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4h9AWhNCh`Dhvz^OiAAEE({E-dXuv&t)U99M06BF~bt=lC3t1z!y3OU-_; z>3=1k>J3(3i_72APIz-IDqpqc+E%+vGv;(%KfZ!%@4A+C&xmZ75-RagX8L}A{%x+r zX<~gz))PX{awr=ezabJ<%O$qq%HpE?3}IarYhrI#g}e)4`)(-lYr?KO{@fm?UzpsD z&F7x?_G;CcbIZ>^o0GCAMe@{JfwtZgS9s0dn=t$|`IrrC3yU6#%a-U6G$wZz0 z>m`@($9HNPdGJ4#pEvb;3eT@>Ck6%v=MvY5lHmNblJdl&R0anPWlhiA#Pn3(#PrPM zYy}fNBRvZROG|wN3w;Aah2)~l;*v^-+{)sT%w)aPV!f2og8aM^z2yAdiMtecFfcG^ zfsM;d&r2*RElOoDPD(L1F;6y4H8Hg?FgGwTOER!DNJ%kHHBU4$OExhPxjgw70|Nse jNLN5&dMbmFNrjP#wt==mQ8cF^C=xwg{an^LB{Ts5w*0vf literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/note.svg b/doc/develop/html/images/note.svg new file mode 100644 index 00000000..648299d2 --- /dev/null +++ b/doc/develop/html/images/note.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + diff --git a/doc/develop/html/images/prev.png b/doc/develop/html/images/prev.png new file mode 100644 index 0000000000000000000000000000000000000000..d88a40f923e3c554125f01cd366707c60cfcad04 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?WS z3GfMV6&DdqOG`60Hr}>%%ZlYo1O0u~loc*tzSP~>;p||S5Et|R|Noh1c$yg)73T~N2spa`a*~JRJ5eh~I1}5!gYtAz;Fo=OPI2WZRmSpDVDTHL^rZN~B=o=X8 z8<-ql-^0nkz!2u?;uumfC;0|1OPoRyGxLNShYX~Tl_Wf9G1_imu)%RA9}mw<0X2^e zQioc&m}WXSvRw^OFi2qFa&lm1W^U?K=~^Ook|m{hVvche^Q6-g?(V)Vn8U=toEqFE UkjD9gfq{X+)78&qol`;+00?PtqyPW_ literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/prev.svg b/doc/develop/html/images/prev.svg new file mode 100644 index 00000000..6d88ffdd --- /dev/null +++ b/doc/develop/html/images/prev.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/develop/html/images/prev_disabled.png b/doc/develop/html/images/prev_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ab3c17e02d156e7494dbab2f9cd66af46af2358c GIT binary patch literal 1109 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj4rT@h2G_o0{}>n;SkfJR9T^xl_SO6joXo($ zppfhlO-<`D(~2b}=LHv2RC7dZWAVCrDh<7Ss(U_A1L-MNQRp<#x>RYL|A z0d8w%7gb?npBLs13>ys`SR)0#F|i0-(0!9|ZvFp)$&5@KPtr;p8yJ{=^Qv)(GIJ<+ zNI0-0Zew5(Fj?c!G-tyG77m3Osc(4d6PFVdQ&MBb@ E0L^J1b^rhX literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/smiley.png b/doc/develop/html/images/smiley.png new file mode 100644 index 0000000000000000000000000000000000000000..30a77f71ce16872d046a1a5d6fd698a2f65a3f62 GIT binary patch literal 867 zcmeAS@N?(olHy`uVBq!ia0y~yU=U|uV36QoW?*1YTQtp`fq{X!*vT`5gM;JtL;nX1 z42*&SJ|V8+B7&<|tz5IBw4@*~EXexT*H!m!O?Pp!sH>^CckiyDuKJ|Dl+(w%CQay1 zOYu8%=FGd73zHKgmoF}|u{3I~kKDVXVbQ_`9c`_Fz7{iQrl~4QMTGi1fByW=jcKLD z*?C#s*_rWAAIx@f)c16=+qAB-t1T`u&hzVsWjnTSn>lml<@5cSX&!B@jUfSci{|F_ z_w^KKXB!)+#6)_3`t<4gwQEt~&MzL%J+!ao-_JD<@64PzGws6Z-hv$8-Me=7btN{` zl~t96rKP3$c$&I9TcsogXQl?mL%y{W;-5&-92C)*?h!W?b)Wnj^{5*w_%-mE4Lj!$7BYguC zr{Y6*7#J8-K`Mgt(@M${i&7bU6O)Vbb5m0?6BXPti&D$;i?WLqd?OT$3=B-#%hsG{ zU|`huba4!+n3FrHHoVC|#v<-Y&ynX`2+ z)ci{*-@n^>-frGI_MA-9eHCQCFMs-NiTvCzJ8a&6h<9#D<(d3(^{E}JLTitR9GSK2 z$*O4*8tU!OHS*&Yg~mSMD)7~hd93j+u`cf5MM<4*zJ;yfFKhYEn9bv3Xeg3g;K-G= z;q?Q<5Qk-d*rznCncd{p+umG~t-YZ3L%_f9;YyrSd?k7nE}0j~xg-T!p1r_pXw_8J z^q9XtRP=q)pSk7_!?YePxacL!`8E4~v$oZii_iB4y^t?YSBana!LlH(Q{_whcc+EB z6^^opPM-68`QEg&=hc<^;brIeKBf1+k=uTZ@Aa)4^R8_EExPXM@|~g)-OB%bBP#i` ie0$=QHXfdLO8@!p%oni+1)dBH3=E#GelF{r5}E*N2(Kal literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/tip.png b/doc/develop/html/images/tip.png new file mode 100644 index 0000000000000000000000000000000000000000..5c4aab3bb3543191c360387c4af9a3cbaa051345 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0y~yV31^BV36QoU|?X-y2mNSz`($iDJ87yAgr${wU6ATeb^ycE^w7cIp z?_W?xU6%d(bb~@Shbi-aG=ETBbm~(ogOmrW&bwBIxdt+K+A3yD;V_t}R>0LF5GN)x zed{W(mq$!1ciVpPy1}W+9bm)Xrgda~bSbG?a3DdjluYV+O9SdLnMpASqX+9EZY3c7C@7#N&OTq83NAIrA4U>si~GJ7Ut&0mS)MRMrP)TsYwQg=9VeOrfC+2Nk)mu rLdL(;85kJ&K)M1F(^DCYOe>5`v<1B4~iR4S3j3^P6 + + + + + lamp + + + + office + + lamp + + + + + Open Clip Art Library + + + + + Sergio Luiz Araujo Silva + + + + + Public Domain + + + set 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/develop/html/images/toc-blank.png b/doc/develop/html/images/toc-blank.png new file mode 100644 index 0000000000000000000000000000000000000000..6ffad17a0c7a78deaae58716e8071cc40cb0b8e0 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0y~yVBlw9VBln7W?*2DUznZ3z`$S-;1lA?z`)P|#tmSq zfuVt+q2a)R0}Txg{}~t<{xkdsQ~$xN|NsB{3#)lDFfcGCdAqwXbg;^LFfcI4dAc}; zRNPAb@qhn+dx4sSAN-68Y+`}}843&7&M+`cx!`muLvG^(1_lP_64!{5;QX|b^2DN4 z1_upgP0!rK^itl1hi%%HopDWWCg4y_C{| z{JavqiARt`YJFJnVhX)qGzOMplv!L->5yAl zT#}irms+fsQd*FoSE84kpF44v;tmD|1}(60ndy0nC8b5F42emG<`xDZ$;L?r7Ky3J=GDKJX@I;2(iM=Hp2}coT4AYeplx7Y_5oxZgQu&X%Q~lo FCIGT9P(J_w literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/up.png b/doc/develop/html/images/up.png new file mode 100644 index 0000000000000000000000000000000000000000..17d9c3ec491ae1ba22188ce85985623c92ffa9be GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?X- z3h)VW6&DdqOG|Thu-mqE%ZlYoyE{8BU%nLR@2jS)FmvY2qel)W#Kk;%^zi@x|I?Un z*fKCM@RbDl1^-6|46X<6oM2#J;4JWnEM{Qf76M_$OLy!3FfcHvmbgZg1m~xflqVLY zGWaGY7v<-srer26xMdclmgg5`7c2NiC>R+Sn6#IzInThrAO_OlT$Gwvl9`{U5R#dj z%3x@qZ(yu%U~+tY4<`cyLy@P8V@SoEspmFwHW&!FJyeg_(XezvV9WvAI|r@_>dZZG zPW6aiOT!J--9O?NG0%AP;}ge|4lDQN4=-}8`?JGwx}?mMnO)OdyQdu$nQCjPRV}jm z$u!Qa8E-cQ-r3Nz>Y(YPTd#BPEH+&8GWqfD!}4*53%dA!%#3$cIv;a~fq{X+)78&q Iol`;+0POUaApigX literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/up.svg b/doc/develop/html/images/up.svg new file mode 100644 index 00000000..d31aa9c8 --- /dev/null +++ b/doc/develop/html/images/up.svg @@ -0,0 +1,19 @@ + + + + + + +]> + + + + + + + + + + + diff --git a/doc/develop/html/images/up_disabled.png b/doc/develop/html/images/up_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..e22bc8712192df3a8faa3264b0ec71ff3aaaa96c GIT binary patch literal 1115 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj4rT@h2G_o0{}>n;SkfJR9T^xl_SO6joXo($ zppfhl|Nrwy-~uYR zhzc&Dg3GAj3M#mY3a+7o>!{!cD!7RXZlQwPsNfDNxQhzzp@RFU-~lRlhzcH|g2$-f z2`YGs3Z9{Y=cwQXDtL(sUZH~5sNfAMc#8_&p@R3Q-~%f7hzdTTg3qYn3o7`E3cjI& z@2KDhD)@;CexZWjsNfGO_=^hup@RP~@T}IQi-CcGuO!GX7$yd$8C(zCIl;idaKO{W zF{ENn(v#GNhX4QTi=1XMFdktN{`IZ@p>>FWLcsvS9SfKMdlAq$6s7@ONV`8frfZ~QMdG-hBC2vApc;y96* zmcYQFpvLCIAmDK02m=$xYzYU3L}6wQg@_sdlHD~JI1CtW_~{utEVY`?z`(%Z>FVdQ I&MBb@06Fw0-2eap literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/warning.png b/doc/develop/html/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..1c33db8f34a8b42b373179b46a2d8d8a10e061a9 GIT binary patch literal 1241 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4rT@hhU+WOo?>8NW(e>JaphoO5CF?5GB9W| zFc>m0I59AIF)#!%FhnshWHT@nGcZ&$Ftji*^e`|?VPKe2T|Fl#Xiikroa*YO3=B&x zEth(EEp2I8I%UezrAyZ`FswB+TsvjTRtAQxnwndCdbZA)vvujxty{P5WnkF5cJ1D+ zTaPg?91{>YCLwX`*s*gA4Ce#{&Phm|)6~4iz;I1d^V+p*_ZS%N-Mjakf#JEL;`8Uv z-!m}0=iqq%{{43bhVS3M|7T$MKMF=efJz}yVEuRs0|NtNlDE4HLkFv@2Ll7c3r`ov zkcwNmlWOyu3izvS7ejxP>R-!INP5f(XN|IS^C^Iyp?`SUk1vQO?s(K&l| zi|Nkt0@~*ymDp65*E-HED6u(s{Mfrxmah{JrgAMTIq)Du?nC5nnYTRgThA|azEdIl zD^uvV>~q(b?>`Fd;xnAbe7so1I$-&keKN}|vNNOCvX<~g{)wp7{&hR__v^cBU*Gq* zV3YS!cBPWsl#eNWc|~nAXWMOB8tQWBuXo=4>}cytyX_5F^Az{bVJ>7~U~n#RjVKAu zPb(=;EJ|f?&`{R&%uP&B^-WCAOwLv?(KFJsP_VSrH?Yt*FjPn`$}BFabjYnNF3C*R zOD)z*DJ{s)E742N&z-nSaR&nfgBIAh%=Em(lG377hGY|?B=Z!b6jL*k#Ka_13kwTN zLrZf@a|7cv1EVApQ-8txlNlHo_&~Y>64O%|j7%zwOtcNO4T_>U4H+017(8A5T-G@y GGywozG)2h( literal 0 HcmV?d00001 diff --git a/doc/develop/html/images/warning.svg b/doc/develop/html/images/warning.svg new file mode 100644 index 00000000..fc8d7484 --- /dev/null +++ b/doc/develop/html/images/warning.svg @@ -0,0 +1,23 @@ + + + + + + + + +]> + + + + + + + + + + + + + diff --git a/doc/develop/html/index.html b/doc/develop/html/index.html new file mode 100644 index 00000000..31168cdc --- /dev/null +++ b/doc/develop/html/index.html @@ -0,0 +1,135 @@ + + + +Boost.Python + + + + + + +
+


+
Next
+
+
+
+

+Boost.Python

+
+

+David Abrahams +

+

+Stefan Seefeld +

+
+
+
+

+ Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +

+
+
+
+
+

+ + Synopsis +

+

+ Welcome to Boost.Python, a C++ library which enables seamless interoperability + between C++ and the Python programming language. The library includes support + for: +

+
    +
  • + References and Pointers +
  • +
  • + Globally Registered Type Coercions +
  • +
  • + Automatic Cross-Module Type Conversions +
  • +
  • + Efficient Function Overloading +
  • +
  • + C++ to Python Exception Translation +
  • +
  • + Default Arguments +
  • +
  • + Keyword Arguments +
  • +
  • + Manipulating Python objects in C++ +
  • +
  • + Exporting C++ Iterators as Python Iterators +
  • +
  • + Documentation Strings +
  • +
+

+ The development of these features was funded in part by grants to Boost Consulting + from the Lawrence Livermore National Laboratories + and by the Computational Crystallography Initiative + at Lawrence Berkeley National Laboratories. +

+ +

+ + Articles +

+

+ Building Hybrid Systems With Boost Python, + by Dave Abrahams and Ralf W. Grosse-Kunstleve +

+
+ + + +

Last revised: December 25, 2020 at 18:34:30 GMT

+
+
Next
+ + diff --git a/doc/develop/html/numpy/.buildinfo b/doc/develop/html/numpy/.buildinfo new file mode 100644 index 00000000..87310e9e --- /dev/null +++ b/doc/develop/html/numpy/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 374e3c15a89643f46322a816fc37dcdf +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/doc/develop/html/numpy/.doctrees/environment.pickle b/doc/develop/html/numpy/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..7ea30903b72cacb5b6e65ca87726613c432700db GIT binary patch literal 27164 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 E06LM2hX4Qo literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/index.doctree b/doc/develop/html/numpy/.doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0f07d220e153732d9324ffa10c804620342a68d2 GIT binary patch literal 3428 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 literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/reference/index.doctree b/doc/develop/html/numpy/.doctrees/reference/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..8e6c5b11a2e5bbb9cfe1fdb9e2276e58ec06f373 GIT binary patch literal 2836 zcmZo*oyy7000upLDf!8zC7C(JdU^RNsl`)zI6wlqsd*(+CQs39oKibQqldF7vAj6H zv?w`sN)N-79**RU%$$^>)VwLNQ!*HO*o#w>OEUBG;OaA2GuSfNW2b0jF!ZpNWR~Ql zB1!eAIpyaUm*@plmSp7TDfpG<22?7fR+OaX6=&w>DFmgar52^;C8tgSnUKNI!xEBO z0dfk_`dX)e9i73NA=JZGkXQurNrpfMV+L~%8`KkiJuEqyd8t$UN|O?MxDrcBiZYW* zOHzx$o@LHVDV`ELrH4H^C$YFV70hPMOU#9^I8sUr5S*mM`!5-J}LzYh| zsVqpH(l*7fM-ZVYFD0?4D6tYOEQ$~=%}Xq*j4w?q%}WMLi6NwtGSTEj5OTStIVG9# znI)-3Q`)Aa_V8rpCFhi;q^4!&K-`mIpW&F{oZ*_`p4!8an^=*OT2PWP#ha;zJvp%e zoE-gnSkiOylcsd`uw`VXq@?Ce>FnW!8Uq*L$SciFN-auFnc~gR!v#*P#rb(Tl~X!P zGc+>{Go&-LGGx42GNdweOOp~&g0F`k8p^umMTrFksYO!~kwX-uUmKASK<4xq&l7DuWr47(s3T zB_~vWAUhhKMKZKNdKr88l1qy~StuT!b$DPRkSx^0QJh**l9`uYJf%kvRCIvLlC+}y zypq(slqo%IVTn1Vsl|v?%jeg_nVy=LT9jClUo^$9hchLyB(=CCF}GlfUk^9Ln)sZ| zyzD7{JzP+3X;ID;zaHL_{N#90mIKKaPw8O=CC|z!Jwj>u`6YSzC8WVzF!Y7L>eK$ zQiqeo=fzVqQv4YSEM)Hjq=3OQ!Vj=a-hCn!*Y;WlE1Mnhcr|87)105JM3T zfN7OMl|a+kBLMP1aZX}!Mp0@(P9mtD;LS>h=Tl9GaAD}DX)@^WbA*2^zS*H1|;(=SLZ zDAu3SBMQ<1G7+RBz9cobASbaTbxIFML27}ns)0$$lpemKv}81EKq3fhWMI~mt&{vq=Bu;D9O#ypVGrwl9&`=T0#NjJ_K1O9lbKhX zS_JZWd}=I71AlTuUSi%TkVQj0TEQ%k0F_J}6u z0phiOv2c#HC1(ja{nRzLhMXAXp@g<2x>8T~4 z#z2o?acNRHMJh=8&aOdZ6T$RZGR zu~R@1mYbBH1CM>MQjy|H6hXLZP81V4VYY%b389!@T#{H+0xE|^(anO&F!XR`ro<=b zmx8kLlpgNn{G1#}+p>5{54$r|eDajqDXmk2ru6U?Bo-B?#^y%sd-akr(`hnuotH$mt^MW!PRH5X0T0!=HF`QD`!(Nh@4pKNJgD*oWgBxUjhIEgUenx(7 zs(w*vUS4XEetCXTwthinNk)Dij7rH**3T==EvVElN=-{GO3h17)kk<-uc)|WN`{O# zQ)v=7jPeUIlaay*7JU4W@XuiF5e!L8%1KqoPg8Kt&nrpID=CJAohUXLM97(BNM#t6 zCM9Ob)=tsLkdK{`p%^(jk1vt5!o0W%SwAi>t|z1j>cv#NIo$!0$nh%zndC&s zI*>{Fkh0J(L&mQ(31McBUw1P-&TxnxasWuaK0gP+FXt zqL5gukeH_cDjyO{@{1G{JWCXcGxAGwQWVlt^HPfvb8;#b^7C>k;TkgY6ms(O3ySr? zg|0@1Xb+R4!W2aA2JteaGTtHw2&iJr0o##-RL=GAp}HAtUMSQeIXk|vG`|G7B?7I^;01b5 zNJ4^5Qht7M39J%_RN$p)rFqGE83hG)2?+|Il$w~CSFBKyk*WZ0Stz8Wre)@3f?7bu z3TgR8XsHq$!x|aiVbw&B5@B1wdNM?NNBKZHX!^=YO2rD1-lV{yX70)CgKtWM}}0EFky4E1Q{6^U?mQu1oA6Q%HV=U zASBsnWWXC|8D-#REY^xYqbx%z%L`;6V+M1EG^DJ=?X3*Wj7m_wz?UJFcZkh3b zlQJ)~NQqAZC26FBCE_I`0|Tg?T3nEroT>m$#$4502oXs06h#P}yt%5mxFG2mQI;xL zDHN0@E(qU>OF^M5KQl!kFSVjXL(`f|0c2B-LSBAJd`f;^s)i;gNfnoX zB$6`{ixjjJ(o;*~QxZ!OH8S%`6!MVdL40sa0<0u21zB%EWqf8{NkK_bd@=fFzJ0=O=4NvT_!loi3qzyK?-dyXQq`Vh|g&^$j}e1nL1P}`+}Kw{2H zXJlZ=$^fa#&_+(bh8a>>u=oepkX&h*sW~Y)hb~yb(nu92tU71tf$9WRnMm?I>_Mp| zrA2x00T(zQ?t`p3padwDH4EfC{DUo7GayQ*f+$E1WI%RyQhrJ$vgN^!3eXM>xGMqb zu0SiRq@w)9l;p(XlFYnxh5WMAB8B|CR2_wq@_dE-B88HSqSRD{;?%-Y(8yCUsLNAa zT2PRanVP}{Nl1uhZxHqEfLI~gLkpu3!M*_$h*DYW2nTzH7o;KQZJHsKwTiI%tQ8QW zLD7U#Dq@ZtWlaVtg+wLD^a&s?V+J#UmUvblNF5^W!rX^q+ag36j9O~qEr)gSw^sK+ z%VDIU2zZcY?8%VIx&d+-v4!w{SRs5Bt_xfUTc8)hJjm@vSo%N}L^uOfBs?V$O*o4L zn+&Nem}^Rtvigy#0!U`hnt~yuku?)ZtcTq-EiE+}F~|z%!=0G*8{}W9te*s2S(>2@ z%k$qrIv@#!p)@ILC9;JQo_Wbdsi0AJNY4_M+c7e$I1Yud5XC8va5*m%sDG2i%|y7n z2+KBh8B$s7gw?~c4alb`2^oL30h#_86gb3Z8(928vyB~kY7WClDUvw}f>mdXkw97^y? z!X-m0%a^cvSZW7_Dha6_WV$8DQDmof7xdIFi?^>03s3^8;6VmX`-KGjk2CFi&?W7+ zg91=0tCfH&kNC%FzZ=R@7kPjLuE&>e`gGTmJbHIf$Xlxq9%`3@JfH$~6BgjQX ziIsX7g|iuX=D;F|T|PmCS(6E?hb4AUFp`kiL8jM(97T3w z_d-wXlAy62tOG}|aKxhm9#r5&zMX)-aVByQn#VRG+0DYW(Yhkv+jeuEtPeb za6rM6eL#j()=k3dVaXm8up}gVkm*N3jv_nR2cRc=HO!$-$lxku>LNY0s2H;raHEd7u$ZKlaqyVVQUwKyRF*Q~V1#FvunegzdBW;p*##8rBxDzm>D(Yk zk)2(_(6fswW_AHbHR?13ER2a%4G%(aW^pDE9yl{g6kRe)Bq%_ovcd_t5~=nG0qMYz zSzJj=)R}qU2~tqI30~3YabeUV&QvfJ7KcZBG==@A62TLdp;Oe+GfJ4u<+ z!xjeW%oZa?RQddRI3bHXO7e@Q`1Nq6B$lKWmn7yEO!4dChFBAylbM%2#jl48$}KI* znc~;OTaup~4_YS(k}aOn!JXNq5sG(-g2*C>uJ&n(G^2hYW(7K3brNFxMzic$;mi%Q~i zQp-|vrg$^;aAhRsz`3kFf~ggmCGo{2i6y1QFh#6AtSPBUrRh`rdicr{i}Et_(&LLu zic%AELB203N=!}#d1^{W4_{_pL1{^RYF=`FN@iaAlpfB~k~Ccl-QvvjDLpc%lJTiU zMfpYX8Hsr*IjKccde}ftO)i1BMr7?`W?<;ygP4nO15CFJ zssx(m9s!UaigOZ+Gm26RauPx7RC#j}^U_Nb(^KP<^HWl%^f0C7P3aLXN=?o$N{LTN zElABvNzF^n1cx+Ra(-S~CMb+JGgIOVKI2~ z!KoyNiogSX}lvL0pKq6=X3Mkb;mBpuJ=0KLZ z@)e{O#KRX|g51Ib5=lxdPK^hp?H+}Ul9GaAD}DX)@^U@MIsv`>qICU~)H3~o)PiFD zDLtYf9Uv1yI^s)Ga|?13OHx7eim3&Wsyrf1}2re~B)>0!yq2c>YH;@rfd63D`! z;wc?H!eBmloltRnPJVJCGz7sTCyB`=sYQ@%6`z?0Du3d06N|D-3#N2}7g2*3IzzL2 zXAf^mesX4BT0T_3o3Td-R3a3YCZVbmNX<=3O^Giqsmw_&&PYuynbO%Knw*oLm>r** zo0ypspO}(TlnP$I+|k3FnpXx|?A*fvDG5?RMVJ6+sIDkAxg@?Mu_!&Y1iXk@u(&j- zxFoZr6dX1wpry^VQ+k9@L_rf>prz6v)6(D^Hc;wM0gJPP1VO8)Yo};rO#xLs@foi& zo@M2N#%k-cE`g{;S-l{MqoqBZAk`(61(4;}VD)|(ul&HO{lJR-z-s+UGvq<5k>fMC zGoEGWXVgPhx-5cB;~j+z-D_n8W>jY6XUxf%l(9c!YiSQJa#8@hjyE~81f1wWi4GzH z%C0bVkYGR-fvAg}0!k3MN%=YO)CE>5Qe2552v^OCVj?HZR>*eLAq!v%<;Q$HbrskDQnLI_aaZ2qJjULXT#PZ_& z(xT+lDLo8RdN`6ZGILUjQuC(7PRU^CVJ}WiF3HT#gR9SA&0x!5kDa2C!O+86l39|I ziX_#;o|lqXRFqgb1*9Z{p@$_TwE|=pLZWpF*xC%%451#jg2W<_TQUSP7&DlA*r3kv z>tV^s%uAi(SDKXA!CAG(!((L1Iy2dQoCQ28J|9GdwgfWks>ZeTGy`6ZK(BG(M5jI`1uGW^Gr zoS#=*QdF8;l3#@EM^y0)sf5^YapO6u_0ILU~4Ja)tuPhQ!RgVg*p4Tnw_a zBqLR!I59U>p`@}PRUt7iMWHyeDpg0JJR`LzRlyHrB1lPIX>L+#5l92vXpmJYAo=2g z)a1;x%+wTx%sd5<;(t?~+Jq7;)P|cs1lT)b!Rtm28 z6cQ3rK-MQDD5T{VfyMKavQm>vieU~;O;N~AtW-$MDb80&N>zZ{s0XgzG%`ecm>d<5 z5+{h4A(bV-$iRRcJsI$_xQ7c7YG5-mu+=GuY9>P}OOla+0bhdXVF6eES&EDd3_WZ` zscEG}nNxafGfGMdtn~F$@{^18ijy-7D)sV<(m`B|N*^3i#d^@#)XONz&4FbPuupn8 zic*X7bIMXvrg$@!CS{2BOaul0po(y$I2eSE!!TV4 zfcXeJz`k%J!xx66XH`UFhYZbF{E8@SvDX)nrYaj!vB}WGR+3nho{HRB?eWsnQ;3IV zIx7XrvMacY0&7HrYC%IpEr=*g5@F5iEKNoRhAb^m@Mmae#e))xj5i0&!Ju-#hYQ{e zhUEIJ1mp;g2e};_rDV7qtgjec&M2oOmL%$e%3xh+$*T*Ng(Mrehgczk;Cc+yJ?Mc8 zKv0MQZjtWVsCFQB9c?!B0NmdLGn0!_6H8JRpvkRRA+0Ds7i#S-})`yQ7fV$XzrAZlFu!0=ATo=d*-U8sP#S5(-N*|B{h=3Irmx4lSUTLmE zQf5h7PGUNjfj)HT%v%g=6r+cV>Xt1q8g`tju8>)zrjzSo! zh+&OEg^>=}97i8dcRyDbTZ0M{9fj~9&k$EfCm)c>7CH(}t{#qI5V;zI3JZt^XUCu* z$H@2~e~?`@U~Lc~7$2-u0U{Rf>j`!fSPX2R8A< z4RCP`agBHM@qt37Bxa$bfTjp!FqeWttu-i2p(T()S!Qav2DtbIq(klXW85U%1r7v!V*3np1ySelwzh2mwHR8cC#`QUyT)Fw4Z3?Vra8YIQZ zi8+ZynaC!AQW4Cos??(VVht=N=_o+r2jWw3%ChD{)ddQOyc8V;Y+(m>AyzZshNR{e zlvI*zHAEMMR)f218qg4e`7l2zOB3NmTuQL}sU$VGAP3YsumL4yP%#P~#ZAo2OD(d4 z`xw+>fMf%3>eT`_Idss&SqC)!3)TsVQ)E6QHR_<{54aD?^HPg6t+~i@4a5+rn=m3@ z2jL&6tB?ht&Vp6}@FbZJbq{I)K!P1h=wk-04kVuAb2IaF6kzPc3LRL{W@QDfS`@&! z%odtHt*k&b3{qr*1DSj;Jpv0OwD5w53w44EVhhznhbUKa!4eZ9?(+*$ixNxn zi)u75Oi0Ay$Rte#cs9p0M2%QOthu;qp^f*^)>H+kRc4|CZ8<@kGA5u_3rq~!90I9> zHiw|iByeL4+7f~YjkczWAqDDaYYNhFfL17@ttn9B0vZ_578$HGRDiULNNvbLbivAV zG8=NZno39&FfJvSRlcS*7kTX$Xv<}^H3jMi<|k!g2JL8Tio|9iBwt{(J~3Julr=sf zwqR+fP-ZMqt{hygDflQMcxq!Sfx)*P&WhX|EARl;lpc&=9Y>!B`oK=^59hE&#hki&=_ z+nWP&1ZZsU3|tp@Y%i)bDQgSzRDvoruJMluK^v<*M5;zO95h>Yhd^Xx9R^K@9094y z&_)jbxD2T*nESzFl3Zz-sW~Y)7ap;KrICgzVFRcPJy4yX-ZheZ4|`B*Noi3Ye7O{y z5BEXV4^RL~WqkuVkHDDu7l_i2APSO#7?7Qvl%Gk8BowkWt}46N~Gj@9HawB@-%YHgQrMv zvjnubuPDD9vJfIUKc_Sow3INfB(*3xBQY;MH3cKZ8j@@TEKbPK36H9*dmvv)W!)hh z4)Anclp&RMgRpv7x(0Mlmafrf`CuW4TLC&;O3+NGr{I$7POJU3(|ojO&g;p$i$o+h0?st5?%0YV~PUO`qrXU z(7GPXM2(Rz2%7w5npu-yc>4l)lq9LNL;+fCfP07_Sw#AV^%uD?lCKLj zjD;s-j4~eN4E&BnN7#Fh-v9!~g36q3`C1mP|sE?GBZ zNM$W2!WqzH4N4*;Bx{iAh-8h|ML5QP>dwp{s7W}BLjyxLW4{pGY!1%8CKh5Bo-^==jBu? z-0vl8n@%^338?g-lS+1`pAKwWa2jWEQ1D_BLT;=U^IG0*h9fm<>-5 zS?ny}#x5%h!NxAUh1Z@TmBmO{J*M>|>|x=y|6S7Uy(d zHwcTw0dxU8s=;|*l|a1V%=_Jh@;{^6Pia}cpqP-#@+KU2@Is|8Ln_N1tRByX_a1Xl0Fn_G5Wm5vt+L`k z4g?;ETyzo>7u{gz)G;W4I5jQ z1?j-istI%ikEp?#x9};G^vtr0P{2RGD|WOb26(SliQ%S zu^yx~fs~2^sBHr{@n?wkP~Tv9KFTry1({Tq5#d0F*L71fq_Xq~tB3VzK#@X1LIRnN zNJ#jTD)v52AI?4vWHBrqm(apu5Z)|+Wz*>n4XNWD}a3-?t3(-MbI4{hQ%DPY3F-YNz z+uSUERtAPF0g!1K+VF-iC}%(lE8IFk)d;lV3#vv)Xs>{Z!URyJpkl+94bt#sBfjAa z(t)Guqp0fxKR%Yo>y9;K-|qs96cLs~vP^U}8~HW=Rp~I3wt3Ma8Lw zrKx$zprZgmI}*SZD`*%lH8D8@HbI9th)*FOey|^;p^4OKO`x@nu;fB}i{R-ds|pmv zQdt#*BL$wlSAklzgw?~ccQRNh{(Op*y+NiYfE)#`BycBYP%^=uy;q@U@5%VjfXK`P z9jOdoAqq-Kv_F^v7T1H)ZSdp)E>>oMBM^5?;4D_w5h_-w-4R{~N;gtjYX~?Plysma z%u0|B>?KTuIU@rD30+IXoE~T#EFl4UR4M2vQ-$=@ywsx1WbjF9AX(79F*N~N;)5l#f~ z5^ZCKRMsxAdVGC!BTyhDB!Gf}*w}^Sa>SI$MUdMFb}q= zs2TM(SR?L?3QG6T=|PAc8KOOE#3fUNO+@R+kjjGCg16|0$H8XMj!?oL0C#TAfYl*& z%4I-NgDVd~f(#J}e~==93!xFoi^!rGQd$4N)}clS8ziqn%ogooN-06;2bY>`?1Z}{ z(8z$85AHP***k~mATD6HWJqQG0{Z}O%D^75x}fkuni+@8x59FJB3kJK2@OO@tFtpO zfREERhgLag`5*?Yov1j1 z*pwmKV+0C!61|3qHF9)kNM%86CoUehWk_WO5cU}McyxfoBZajqQpd!eLIc4uh&PYc zgZ+w{1~?NEpk4s$&k*fl1@qD3zXPn5sQ8E20*il;r$Ch)aZL_{t&r41qV5c-EQsyI z#sBsUsjOp zi_CPoY-@S$S?llpv zh4!RgfOO!9%_LAaDj@-WmLupMh021|JkWg&u!WMK_0lC7i6x+`0Foiw<1;~b0F~q` zBq|h_q*z&%rGhSE0WD{P9Qg=4VG(o?6r{(2R3;|U+)8lj0hgK}tB}ec7BD|UD(f#e z^iWGpUX)+}n*rK}01q03IgnN)2hpuah;5)X5a2Z#R192%n|cDMZZa&~g!!DoMygAkz_f2(OE9?6BB~KKN7)D~`b9N|0VUJUI_`X7@?t~9I!J`YaDi{r4R!}dzkZ+vJfRYICGYOwI$-aZ3@

nG_IJXP6Yr7Q$)_B4!~b6Bo0`GNiIz5_UB9n3W+|AtQCJr12;Q2P&vr z#0gh~2-qGZ!3?P^2~JS&1~q;-;SB}quwA; zI48L697;G;V1qzGARXA-&OI*BRs^Wg3%R{2H3hoU0Cq1V0)jkou)Kg$>L{<3^8)(@}h1h_%NQ4LdMNpHQu;alEh23CvYM!400&PN7^4{Ew6 zSRTy=Ya%MePXa5=5ba@Bs6f8<9?T`z{&iqONwZ%Zysn@aBWjQW3a1jdJMpG{cw^vN zhE!G`5l)2W6;Qe(A+LZ;N8}Z}F2XT^c^7k2V~?1k7WHP9L(^XeJ4XI>o-_EEqho(Acqm^VTo{KHYADYVab5C5mj_TY@lTi z3t|J_A`Bk%_cEli1PD7G+{EDpt0T9EWs4O2$bBhzaf05%vIkp-QHQ3KBqYF!Jj})8 z?qE$sMFhlrQhHbr9mECf{S2urYr>Af5wHX^H`2H)wdNGEz^+9NZz9|3#bB*Og*wC* z;@avEwZw(@gAA#xG{Vk63UA!zVsER1vI?Y>!mSfjc|hAApvr@U_6Mj8d=9E_sMl6s z3CeL&S<4BB3aqWZ1f&B;g{Kq@I|dwe`9fkbYy%*q+CfU0iUhU5GBOb=;pIfuZjdXb zvUU>o7rdBzlp&S1m9To)Xg??%NQgU->4><)pE|IQ_TRy1J3^a&3WOHFLGJwn&98%& zdzUDH=GuwB+Zq=BX>_s<9*K~)BY_yf*>-$J_qHP>$-O1uU{LmlwH-k^uxF(RL3%80 z!@JA_)V~I$8KTDW@vattm;_oB0NQ#2TB-$0O6Yr>xU}GV#0T5jHAWsto0V|%!b_AF zpf)R5Jx$xJAcqlbv+|JFW(8{_s?rt#E2U|h6>J0Eq7xqUuRv{9uzI|Xhg9`obx3Vi zS}n1%MT#i`E2rRvU=IO>py5Zb`%xQZL@%*&2W!R~NU$MPd$3Yk3~)nCCN5@QgBs0X zm*90Yu9(HQ{E7H-3Q{K`rYJH{ViunrNP}L4msn+i{fRYZL8U3g6}XmI6@fM54J261 zLhPYM%tA~iE@t0=n&*TajXh=uWa?rn*tMwfLu7Yo9#|_;u>-M%xb6@{Epg%fHbW|F zB4KABg*R?}|LnGgvbRJVgN8Q-`=bOd%&TH?st?$_meng(+FazzPR4b;B#5tY;t}N@YDE z947GE_kD&`)&s)oVO=Ru7?RMH0+~)qyhFC%;n<7E%nNSTG4g`iNBFZNwAKC(6dpKY zTmiCCBri2J1$=r(QYvEQTt;e9Dn|ELo`42eED}_Qh%ZrykAw;P2p(S_Go-Tk39E<2 z7bpZsh%b=oi1@-^5@7H8zCiE##*#Q~0_g#hx~z@Hw!otd+|e~A5dJtjx?kzt(e;ER zFn0nD1{LhkEaL*wfg{U|E@H!aqlpzP=aYGuZZs&!rLrOkM-sdg_?{t^6$(~Q%kF9p z$YF%Kt9f8&pf;?Cm|`gdYr|iPLyv`l*g(tfD#Ql7#T`88e`ZK!Wf68fxG9znR)^GG zCFy*g=}5s()D+81uyv?WL2wb6C=L z1u`9xxA3|M$D+6I=)JcP5_@mZ#7Nu{H`*8uubaVrwN?V5jjONb%fv|U&f08HsU(#( zlYomsWiPa|HVvc$M>$qY^A&9bSG5e#lC`yDytzj(6U1Xu>o%h1P^;QP}uJw?0RsMW+zx3a*v8&Dnwer zLant`ufeWBjUpnOkYB)BiHatOEyOh;A!>;WaCT6DKPT)CqyWclFxEDtFE~yi`3bjH zP(cQ*=s*P-@f95;yG{mWChD~!wfMoUNDY3XTal_D9XLu~2WUkIT15f5Djsd8Ht4W6 z&<<^QlM!VZ7Uq@q@VyZEX$oW*2yQNBi1tuw47_s9vH|&CD$9y+c)@czCn({W5!L`3 zyaoj@38?~XJR()#Pk2~IuYFkK~PG7xwteb>op?-13ZAhAx4$6INL#C zB9+xjz?q1*0_nh!r}aQBD%i!;;H6QzB^ij`1}Lk8MN_~B%42l?bVLovcCe z0nMMVGy=(5zQP!(S{{^&p{W{jAT;)LO;8;?M@fTdr;3gH2tbsywJsjRz%Jq1s) zlAz$eNmv6c$$~ZTw+Gp{7I2-J>BQ~-r4Mxm=jSP#toDqy9L8fN0N05MpUr3!MYRF*Pf z&%slxJSg1d32T6*R#0e=kXpgUbAy}(POXHiP`t}6oInOiWjPSxTxbzv3(|oj@?t|W zGK&?8AV~%sR|>`X3Xr4n6><|xG8D@5i?WLq3X1XzQj2mb74q{GGE4MAi&Kjf$}@9v z6fzRaQb8vw7NvsYyr3wxBtAK@xCEpMBidtVX&WrT(AE+}E(!q!t5jAH;fR1IG(}KC z^CPSQme4>kM?yja8;?k6M76YG#SOG3m&Ys?A?s_vr6Q$fW{N^_YDqjek3h2oq$j7Q020%L4@wZF7B%nuBM=%m^Nukn zENP#2L^5sg_4ZSV$9s*Lrvph`G*KM!}Adlu13m1YM_vk%2FX5w(uNe3W{|F z!Wv*X2oxD4VG|;h|sp+XjSaOLL z@tR?IfD|q8c*)8E`9LZwi?E;J>DvYr8)<|!z|uD;kVr`1VB>>8<T~+hC+`4V>v4 zJW^GRk-~}B01r!WhoOr=xZq6Vj-XJbeHvc?3RtPEc?6t^l*VU+bl^ziy20S!BQud} zlb{=x%1P1#kD9DaAWukTZ6NGzcrteeMaUY$8eqvB6iy^0bFlFIi`w=2`@t ziIhgwK{{}xQ6BL4iUK(3Fh(i4ktAV>5Je0ga#?mDJEXE~2)hcN>Hv1k;*C{;7p`+oD0%{BONOzWtM;vu|iIMdS-HBPEMtQe~@l! z3TWy@BT=D7AxRS>c`Fgt1B)eMl){5Qs|DmxsjMc#UV~?ba8RJv5!L|944|+eAv1uD z&jLA%?932OdS+0gdS)QrM0jj~Gs7YRA&WCJM1$gm_L*S^C~Bm#wh?e9QfAl;(t#s0 zsA48;M?V)tZcqc|28`^0B@1Ebg5?LI)WV}6>lDbbQduVmdk>x=VnG3ags=u!h5&^J z2^j)x{05M-$j%V4sB5u~BGzJYB34e}TZjc-1BGuT)_v$oEH2lI#N2|MRE=Uy#3)h* z=*YiMP#4s%)kJ;m$bMbF*#MCK*3faDL=os#L5bC zp{q3)LNX6S*2*fcG`FDAnv1Kz$_hGcT2iWDt59HNm7AEI8edWh@{4++x{i91x{i9X zx~76PS6+dY6}0M9NQHP8qENwB0VD@$L2Hzhf)s;H&dDq;QOLoe6D*0MF$b&Z}pgi~~^ zf~`Wep^lM`v5rZtf;GssU_V3FwPA#W3CL*$R#s3oklrtPaKRKo0~9osfa*Yy&GD%f zP^W=5lRy@4fW&oDN_4=3ZaR<&ZJqq`Jdle^GxJI;;!6~AOLM@Aqhq5@z>bHzUZ>hr z$4tju$D&rJ+EB+>$5h9>w$_>pY#4?|jCG7aUV+$wA!`DWMUDbkKw^mlsMEmlfRZ?1 zZpG$Tn4C^ZiJ=Z!dNbBB(bPdrf+jkKU?E7DYG`U&bHPj?Y&tjyVBrZ*=^#U(h2&^1 z8qGz}GGH_pA<83I4uj-TJh=$od;quL{u5{l;B3LAf*KOA8V{v~@B&d|b3v;dPz{T> z$_CYyNXtp$;YNVglxAfyGB6|}FS}+&T6WEpmCMM$;LV6{!E_H>aeir0a_W=}9Z+S> z*u$4xT2z#pR}v2u_v_(-iR5JFrB3nd;V4cmDap)BFP_pPn3A7dT9TPltd~}lpI4Ha zmolY?Ei5soG_`ojJ+~o&XmNG)Z&uF+=3~7J=_p$;&U?d zvZwgmc*y#CFiGP=A}>R;Vdml z)3wko&P<=uBZDd#pITIuUlgB_n3s~1S~R7H4dm41k|{m>`K2YOrm%udnbISRCWB@~ zmaQ-YLk}OsT!b57x@Ax$&@}f5fc#LLlUSTllvw2I7$BrN;0N+ zbM(lT6lLbd!}Av0`SIXZ`IOEcF|cbg^NLf8Kt7L8%>#u|%9M^C?xMtUIM%7nbIiq!v%<=n)38HoLQV$2DBuE9N4}r|Ql+2>k@n5^$Ug7MCU!mt>ZJ*AT>~q^1>5sh!dz zgdz&=#(;!5ic-_y9Cm0wWJ>ImEJ;v_Ufjb5$`C1F6WBrOGQn((9=Ou1bVde-EM5@7 z2_nitLkX*ubu>#*n1LbVMQINw$S}~FIFQjAS#`n;3>{!o z{IWnMbYy{a`++t4f%W=mtgAZk(884z_8 zvIXZw7PvCh$_UJ;%*fA}lQAh{f5z5~M;SLtdw7vk8^}pLyvdm*;Cuy2*ANjY&dpk@64 literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/reference/unary_ufunc.doctree b/doc/develop/html/numpy/.doctrees/reference/unary_ufunc.doctree new file mode 100644 index 0000000000000000000000000000000000000000..81734d8ecd4f98d048b5e4fce1863f28c3fb3e5a GIT binary patch literal 15587 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 SK3plFA`x18fNJW}Bs~C3)LyRu literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/tutorial/dtype.doctree b/doc/develop/html/numpy/.doctrees/tutorial/dtype.doctree new file mode 100644 index 0000000000000000000000000000000000000000..992a347709f5fec22a29d629b76cdff86cd40ca6 GIT binary patch literal 9323 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 literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/tutorial/fromdata.doctree b/doc/develop/html/numpy/.doctrees/tutorial/fromdata.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ee881810fa351d31ab0d26b8d688db639ef15373 GIT binary patch literal 8007 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 literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/tutorial/ndarray.doctree b/doc/develop/html/numpy/.doctrees/tutorial/ndarray.doctree new file mode 100644 index 0000000000000000000000000000000000000000..40157e7e174a1189a4f6ce56100e94da697fb94a GIT binary patch literal 15759 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 literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/tutorial/simple.doctree b/doc/develop/html/numpy/.doctrees/tutorial/simple.doctree new file mode 100644 index 0000000000000000000000000000000000000000..2a197d9bfeb268f19363532fa79b986409d699ab GIT binary patch literal 6522 zcmZo*otiJn00upLDf!8zC7C(JdU^RNsl`)zI6wlqsd*(+CQs39oKibQqldF7vAj6H zv?w`sN)N-79**RU%$$^>)VwLNQ!*HO*o#w>OEUBG;OaA2GuSfNW2b0jF!ZpNWR~Ql zB1!c~J1P`s<`(3nDwLF#gW1g&U~qfctdqlTH3n1l#-{S2uLU5NMnGGsu3oFQ8~MI%E#c1ng~ z?34`U*eMyRu~RbCW2cm6Xl7_8+*3;wN-|Ov@=}vi zi;EMBDitzP6H`))iWSoGixj{ir;wbVTacfZnpaW`_G58si9%@sk`7R`6c;2WrxsgT z!MyBGWrL@{1E7cMMrTN6Sd$*0Y)Aph(8HUPS&~|mm=m9rlb@W8oQNuvGxL&jN>fr5 zY?AWxi%VcB6CAdB83hG)TnH7J`NbtgsfoFETwL%_RVYxfRRC+XvVtUTYb41$3|T8H zu+i4As2Dg0z~d|f6j(l`Nr^a)3UEXU z&i2g9EXhpF$t+F%`3^wP1OOXSa1Rd6#}6AS(=lor{I>DnNwPnssPHp zi8(nSoyDmNMXAN5IVHsknRyDusp+8dI1yCHDx?+_7eANP@Iui0I5V$5=#<))UT7U?N?q!y*>faM`tGm90BD~#a@9%KsGkj!GRqNLKy zoD$v4JcYEJ{KOIkkQAc0UN^Mdjg%{fn#(h!GAc>WSz<`34Uw}N3#_b4N2a9SL>nIp&T62LiQVJ-(6(FQ7IBS8~R#xe$CGp^-k(p-$P8oKf+y~N< zmjX?93J?udsYUt48ep4rASP+T>zF~{64bohK}uehKnh(%&7vQfUkc8yi8;kcjXZ_a z+=3El6Hg&0GaFRxWELwR@{$fI`jApGY5FpxGNzH9j%1L0ibzN5$kCkyjc%|vq0tRa zD~Q-8T0Lr3)Z|8P|Xc0K2sp2te!$hMk<7< zkf>0ek(r#KkO?Y1b25udK&-UPqT&*T#pEf0gbS>!U{MNgq$KC(6_+Sz*=ZD5 zSrwNQX(VcDf|P-cO3h2jvF74ZP|(*`2ucN)jNqykQf_AEmEJUuRScSCK0rgie&T?=hbjRp>uNUcR= z6L9C{5GiGs5+V(z!h1YD(uul|p$A>qP=s!No-R186i-Qn_1$}eAtEuCIT70>ES3&Eh)*&OD~?% zBM2Ix0*_dw73JrZq~@he>0t{4m5;@UzAm3%4`+I6UTRTdNq*53zaGw%#FEtFlEmDC zDSkcN5NqOdGV`*h`1No>xur!pQ~Y{(OY)QBLBl;D+2ScZtf_e=MU_)}gwpc!OY-td zQjsLR8GCp^qhEQYx$zZg`9--?ycv7=K!tZfd~$v+sMl6J#ji&iB9fYu3Koe64d2AW z2A%wRcp=gV0iL4Ng8ZVA_?*py!6t<^wjv|{FKxwJxr;2Q+kAp zQj_zGQsPrm3sUn^QuC5CQ$ex7mYkoLmI(?V&dikff}+&4%!(-)Y(0F5r6u|C2%#RP z%#VAs(h*;hnp=>QSdt1F14%8=RW&e4nbN~ol$MNU z4M+rGjSS41lKlLfV!h1Nk~FY286~+n`cry1OA?df%QI6-GNyQQ^vISJW#-1iGZx(W z@x`DayeXYMVqn)~<`t(Ffkr>#Q}aM!lrp8Ghr1}T9M1J->=7ug%qvN(h|kDO&&bJ4 z&nTJF!;+H^O5Qxhxrs$3@r9-Npn>0x9$_#a!i~?#Pfmn}pe(441vRINAbBc2GY?ew z#OEd!WtSFA=>!jzgNL)BdA+lTHzhwgGcPS4D&Wo7BLpfAic6DF)d{5LCZ(pt7nfA# zq!wqSrj|_U>=8}Q$xqCVPt8rt%!yA-NhwMNk3o0zFsJ5~fd;I5I3UG9DyaMt$jnR0 zEJ{r-i7!bkN>42T4Mg_{7MCU!mt>Zdg2N^SG(259rAG)w6g+e{rFII)v@|$}4V3y* zK*QiY>>xqVNOHMJh=8&aOdZ6T$RZGRu~R@1mYbBH1CM>MQjy|H6hXLZP81V4VYY%b389z|9w7&n z!=mVBL1h?vxH41Xlk-bKS$RqicXEDC4rB(ScuEhuGgN%?6i~GrG^K~HAhD=8H9i+K jB%Kb)YeMimk0Q(s7Y0WeR|=>Y0te0%KTy?JnxqE+G4Ecf literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/.doctrees/tutorial/ufunc.doctree b/doc/develop/html/numpy/.doctrees/tutorial/ufunc.doctree new file mode 100644 index 0000000000000000000000000000000000000000..6f68dea22e596da0ce0d1fd18e452e3be20bf4c6 GIT binary patch literal 14292 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 XE)0%7t`ty_1P+`jexRDNG)WHt0ll5~ literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/_sources/index.rst.txt b/doc/develop/html/numpy/_sources/index.rst.txt new file mode 100644 index 00000000..bb3b623e --- /dev/null +++ b/doc/develop/html/numpy/_sources/index.rst.txt @@ -0,0 +1,14 @@ +.. Boost.Python NumPy extension documentation master file, created by + sphinx-quickstart on Thu Oct 27 09:04:58 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to the documentation of the Boost.Python NumPy extension! +================================================================= + +.. toctree:: + :maxdepth: 2 + + Tutorial + Reference + diff --git a/doc/develop/html/numpy/_sources/reference/binary_ufunc.rst.txt b/doc/develop/html/numpy/_sources/reference/binary_ufunc.rst.txt new file mode 100644 index 00000000..0215e555 --- /dev/null +++ b/doc/develop/html/numpy/_sources/reference/binary_ufunc.rst.txt @@ -0,0 +1,110 @@ +binary_ufunc +============ + +.. contents :: Table of Contents + +A ``binary_ufunc`` is a struct used as an intermediate step to broadcast two arguments so that a C++ function can be converted to a ufunc like function + + ```` contains the ``binary_ufunc`` structure definitions + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + template + + struct binary_ufunc + { + + static object call(TBinaryFunctor & self, + object const & input1, + object const & input2, + object const & output); + + static object make(); + }; + + } + } + } + + +constructors +------------ + +:: + + struct example_binary_ufunc + { + typedef any_valid first_argument_type; + typedef any_valid second_argument_type; + typedef any_valid result_type; + }; + +:Requirements: The ``any_valid`` type must be defined using typedef as a valid C++ type in order to use the struct methods correctly + +:Note: The struct must be exposed as a Python class, and an instance of the class must be created to use the ``call`` method corresponding to the ``__call__`` attribute of the Python object + +accessors +--------- + +:: + + template + static object call(TBinaryFunctor & self, + object const & input, + object const & output); + +:Requires: Typenames ``TBinaryFunctor`` and optionally ``TArgument1`` and ``TArgument2`` for argument type and ``TResult`` for result type + +:Effects: Passes a Python object to the underlying C++ functor after broadcasting its arguments + +:: + + template + static object make(); + +:Requires: Typenames ``TBinaryFunctor`` and optionally ``TArgument1`` and ``TArgument2`` for argument type and ``TResult`` for result type + +:Returns: A Python function object to call the overloaded () operator in the struct (in typical usage) + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + struct BinarySquare + { + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a,double b) const { return (a*a + b*b) ; } + }; + + p::object ud = p::class_ >("BinarySquare").def("__call__", np::binary_ufunc::make()); + p::object inst = ud(); + result_array = inst.attr("__call__")(demo_array,demo_array) ; + std::cout << "Square of list with binary ufunc is " << p::extract (p::str(result_array)) << std::endl ; + diff --git a/doc/develop/html/numpy/_sources/reference/dtype.rst.txt b/doc/develop/html/numpy/_sources/reference/dtype.rst.txt new file mode 100644 index 00000000..03227116 --- /dev/null +++ b/doc/develop/html/numpy/_sources/reference/dtype.rst.txt @@ -0,0 +1,92 @@ +dtype +===== + +.. contents :: Table of Contents + +A `dtype`_ is an object describing the type of the elements of an ndarray + +.. _dtype: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html#data-type-objects-dtype + + ```` contains the method calls necessary to generate a python object equivalent to a numpy.dtype from builtin C++ objects, as well as to create custom dtypes from user defined types + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + class dtype : public object + { + static python::detail::new_reference convert(object::object_cref arg, bool align); + public: + + // Convert an arbitrary Python object to a data-type descriptor object. + template + explicit dtype(T arg, bool align=false); + + // Get the built-in numpy dtype associated with the given scalar template type. + template static dtype get_builtin(); + + // Return the size of the data type in bytes. + int get_itemsize() const; + }; + + } + } + } + +constructors +------------ + +:: + + template + explicit dtype(T arg, bool align=false) + +:Requirements: ``T`` must be either : + + * a built-in C++ typename convertible to object + * a valid python object or convertible to object + +:Effects: Constructs an object from the supplied python object / convertible + to object / builtin C++ data type + +:Throws: Nothing + +:: + + template static dtype get_builtin(); + +:Requirements: The typename supplied, ``T`` must be a builtin C++ type also supported by numpy + +:Returns: Numpy dtype corresponding to builtin C++ type + +accessors +--------- + +:: + + int get_itemsize() const; + +:Returns: the size of the data type in bytes. + + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + np::dtype dtype = np::dtype::get_builtin(); + p::tuple for_custom_dtype = p::make_tuple("ha",dtype); + np::dtype custom_dtype = np::dtype(list_for_dtype); + diff --git a/doc/develop/html/numpy/_sources/reference/index.rst.txt b/doc/develop/html/numpy/_sources/reference/index.rst.txt new file mode 100644 index 00000000..5c0d852d --- /dev/null +++ b/doc/develop/html/numpy/_sources/reference/index.rst.txt @@ -0,0 +1,12 @@ +Boost.Python NumPy extension Reference +====================================== + +.. toctree:: + :maxdepth: 2 + + dtype + ndarray + unary_ufunc + binary_ufunc + multi_iter + diff --git a/doc/develop/html/numpy/_sources/reference/multi_iter.rst.txt b/doc/develop/html/numpy/_sources/reference/multi_iter.rst.txt new file mode 100644 index 00000000..c1d812ef --- /dev/null +++ b/doc/develop/html/numpy/_sources/reference/multi_iter.rst.txt @@ -0,0 +1,94 @@ +multi_iter +========== + +.. contents :: Table of Contents + +A ``multi_iter`` is a Python object, intended to be used as an iterator It should generally only be used in loops. + + ```` contains the class definitions for ``multi_iter`` + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + class multi_iter : public object + { + public: + void next(); + bool not_done() const; + char * get_data(int n) const; + int const get_nd() const; + Py_intptr_t const * get_shape() const; + Py_intptr_t const shape(int n) const; + }; + + + multi_iter make_multi_iter(object const & a1); + multi_iter make_multi_iter(object const & a1, object const & a2); + multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3); + + } + } + } + + +constructors +------------ + +:: + + multi_iter make_multi_iter(object const & a1); + multi_iter make_multi_iter(object const & a1, object const & a2); + multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3); + +:Returns: A Python iterator object broadcasting over one, two or three sequences as supplied + +accessors +--------- + +:: + + void next(); + +:Effects: Increments the iterator + +:: + + bool not_done() const; + +:Returns: boolean value indicating whether the iterator is at its end + +:: + + char * get_data(int n) const; + +:Returns: a pointer to the element of the nth broadcasted array. + +:: + + int const get_nd() const; + +:Returns: the number of dimensions of the broadcasted array expression + +:: + + Py_intptr_t const * get_shape() const; + +:Returns: the shape of the broadcasted array expression as an array of integers. + +:: + + Py_intptr_t const shape(int n) const; + +:Returns: the shape of the broadcasted array expression in the nth dimension. + + diff --git a/doc/develop/html/numpy/_sources/reference/ndarray.rst.txt b/doc/develop/html/numpy/_sources/reference/ndarray.rst.txt new file mode 100644 index 00000000..1486c73a --- /dev/null +++ b/doc/develop/html/numpy/_sources/reference/ndarray.rst.txt @@ -0,0 +1,382 @@ +ndarray +======= + +.. contents :: Table of Contents + +A `ndarray`_ is an N-dimensional array which contains items of the same type and size, where N is the number of dimensions and is specified in the form of a ``shape`` tuple. Optionally, the numpy ``dtype`` for the objects contained may also be specified. + +.. _ndarray: http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html +.. _dtype: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html#data-type-objects-dtype + + ```` contains the structures and methods necessary to move raw data between C++ and Python and create ndarrays from the data + + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + class ndarray : public object + { + + public: + + enum bitflag + { + NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2, + ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8, + CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8, + FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8, + UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8 + }; + + ndarray view(dtype const & dt) const; + ndarray astype(dtype const & dt) const; + ndarray copy() const; + int const shape(int n) const; + int const strides(int n) const; + char * get_data() const; + dtype get_dtype() const; + python::object get_base() const; + void set_base(object const & base); + Py_intptr_t const * get_shape() const; + Py_intptr_t const * get_strides() const; + int const get_nd() const; + + bitflag const get_flags() const; + + ndarray transpose() const; + ndarray squeeze() const; + ndarray reshape(tuple const & shape) const; + object scalarize() const; + }; + + ndarray zeros(tuple const & shape, dtype const & dt); + ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); + + ndarray empty(tuple const & shape, dtype const & dt); + ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); + + ndarray array(object const & obj); + ndarray array(object const & obj, dtype const & dt); + + template + ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner); + template + ndarray from_data(void const * data, dtype const & dt, Container shape, Container strides, object const & owner); + + ndarray from_object(object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, dtype const & dt,int nd, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, int nd_min, int nd_max,ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE); + ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE) + + ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) ; + ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b); + + } + + +constructors +------------ + +:: + + ndarray view(dtype const & dt) const; + +:Returns: new ndarray with old ndarray data cast as supplied dtype + +:: + + ndarray astype(dtype const & dt) const; + +:Returns: new ndarray with old ndarray data converted to supplied dtype + +:: + + ndarray copy() const; + +:Returns: Copy of calling ndarray object + +:: + + ndarray transpose() const; + +:Returns: An ndarray with the rows and columns interchanged + +:: + + ndarray squeeze() const; + +:Returns: An ndarray with all unit-shaped dimensions removed + +:: + + ndarray reshape(tuple const & shape) const; + +:Requirements: The new ``shape`` of the ndarray must be supplied as a tuple + +:Returns: An ndarray with the same data but reshaped to the ``shape`` supplied + + +:: + + object scalarize() const; + +:Returns: A scalar if the ndarray has only one element, otherwise it returns the entire array + +:: + + ndarray zeros(tuple const & shape, dtype const & dt); + ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt); + +:Requirements: The following parameters must be supplied as required : + + * the ``shape`` or the size of all dimensions, as a tuple + * the ``dtype`` of the data + * the ``nd`` size for a square shaped ndarray + * the ``shape`` Py_intptr_t + +:Returns: A new ndarray with the given shape and data type, with data initialized to zero. + +:: + + ndarray empty(tuple const & shape, dtype const & dt); + ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt); + + +:Requirements: The following parameters must be supplied : + + * the ``shape`` or the size of all dimensions, as a tuple + * the ``dtype`` of the data + * the ``shape`` Py_intptr_t + +:Returns: A new ndarray with the given shape and data type, with data left uninitialized. + +:: + + ndarray array(object const & obj); + ndarray array(object const & obj, dtype const & dt); + +:Returns: A new ndarray from an arbitrary Python sequence, with dtype of each element specified optionally + +:: + + template + inline ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner) + +:Requirements: The following parameters must be supplied : + + * the ``data`` which is a generic C++ data container + * the dtype ``dt`` of the data + * the ``shape`` of the ndarray as Python object + * the ``strides`` of each dimension of the array as a Python object + * the ``owner`` of the data, in case it is not the ndarray itself + +:Returns: ndarray with attributes and data supplied + +:Note: The ``Container`` typename must be one that is convertible to a std::vector or python object type + +:: + + ndarray from_object(object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * minimum number of dimensions ``nd_min`` of the ndarray as Python object + * maximum number of dimensions ``nd_max`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray constructed with dimensions and data supplied as parameters + +:: + + inline ndarray from_object(object const & obj, dtype const & dt, int nd, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * number of dimensions ``nd`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray with dimensions ``nd`` x ``nd`` and suplied parameters + +:: + + inline ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE) + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * optional ``flags`` bitflags + +:Returns: Supplied Python object as ndarray + +:: + + ndarray from_object(object const & obj, int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * minimum number of dimensions ``nd_min`` of the ndarray as Python object + * maximum number of dimensions ``nd_max`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray with supplied dimension limits and parameters + +:Note: dtype need not be supplied here + +:: + + inline ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE); + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * the dtype ``dt`` of the data + * number of dimensions ``nd`` of the ndarray as Python object + * optional ``flags`` bitflags + +:Returns: ndarray of ``nd`` x ``nd`` dimensions constructed from the supplied object + +:: + + inline ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE) + +:Requirements: The following parameters must be supplied : + + * the ``obj`` Python object to convert to ndarray + * optional ``flags`` bitflags + +:Returns: ndarray of same dimensions and dtype as supplied Python object + + +accessors +--------- + +:: + + int const shape(int n) const; + +:Returns: The size of the n-th dimension of the ndarray + +:: + + int const strides(int n) const; + +:Returns: The stride of the nth dimension. + +:: + + char * get_data() const; + +:Returns: Array's raw data pointer as a char + +:Note: This returns char so stride math works properly on it.User will have to reinterpret_cast it. + +:: + + dtype get_dtype() const; + +:Returns: Array's data-type descriptor object (dtype) + + +:: + + object get_base() const; + +:Returns: Object that owns the array's data, or None if the array owns its own data. + + +:: + + void set_base(object const & base); + +:Returns: Set the object that owns the array's data. Exercise caution while using this + + +:: + + Py_intptr_t const * get_shape() const; + +:Returns: Shape of the array as an array of integers + + +:: + + Py_intptr_t const * get_strides() const; + +:Returns: Stride of the array as an array of integers + + +:: + + int const get_nd() const; + +:Returns: Number of array dimensions + + +:: + + bitflag const get_flags() const; + +:Returns: Array flags + +:: + + inline ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) + +:Returns: bitflag logically OR-ed as (a | b) + +:: + + inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b) + +:Returns: bitflag logically AND-ed as (a & b) + + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + p::object tu = p::make_tuple('a','b','c') ; + np::ndarray example_tuple = np::array (tu) ; + + p::list l ; + np::ndarray example_list = np::array (l) ; + + np::dtype dt = np::dtype::get_builtin(); + np::ndarray example_list1 = np::array (l,dt); + + int data[] = {1,2,3,4} ; + p::tuple shape = p::make_tuple(4) ; + p::tuple stride = p::make_tuple(4) ; + p::object own ; + np::ndarray data_ex = np::from_data(data,dt,shape,stride,own); + + uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; + shape = p::make_tuple(3,2) ; + stride = p::make_tuple(4,2) ; + np::dtype dt1 = np::dtype::get_builtin(); + + np::ndarray mul_data_ex = np::from_data(mul_data,dt1, p::make_tuple(3,4),p::make_tuple(4,1),p::object()); + mul_data_ex = np::from_data(mul_data,dt1, shape,stride,p::object()); + diff --git a/doc/develop/html/numpy/_sources/reference/unary_ufunc.rst.txt b/doc/develop/html/numpy/_sources/reference/unary_ufunc.rst.txt new file mode 100644 index 00000000..eaec034c --- /dev/null +++ b/doc/develop/html/numpy/_sources/reference/unary_ufunc.rst.txt @@ -0,0 +1,103 @@ +unary_ufunc +=========== + +.. contents :: Table of Contents + +A ``unary_ufunc`` is a struct used as an intermediate step to broadcast a single argument so that a C++ function can be converted to a ufunc like function + + ```` contains the ``unary_ufunc`` structure definitions + + +synopsis +-------- + +:: + + namespace boost + { + namespace python + { + namespace numpy + { + + template + struct unary_ufunc + { + + static object call(TUnaryFunctor & self, + object const & input, + object const & output) ; + + static object make(); + + }; + } + } + } + + +constructors +------------ + +:: + + struct example_unary_ufunc + { + typedef any_valid_type argument_type; + typedef any_valid_type result_type; + }; + +:Requirements: The ``any_valid`` type must be defined using typedef as a valid C++ type in order to use the struct methods correctly + +:Note: The struct must be exposed as a Python class, and an instance of the class must be created to use the ``call`` method corresponding to the ``__call__`` attribute of the Python object + +accessors +--------- + +:: + + template + static object call(TUnaryFunctor & self, + object const & input, + object const & output); + +:Requires: Typenames ``TUnaryFunctor`` and optionally ``TArgument`` for argument type and ``TResult`` for result type + +:Effects: Passes a Python object to the underlying C++ functor after broadcasting its arguments + +:: + + template + static object make(); + +:Requires: Typenames ``TUnaryFunctor`` and optionally ``TArgument`` for argument type and ``TResult`` for result type + +:Returns: A Python function object to call the overloaded () operator in the struct (in typical usage) + + + +Example(s) +---------- + +:: + + namespace p = boost::python; + namespace np = boost::python::numpy; + + struct UnarySquare + { + typedef double argument_type; + typedef double result_type; + double operator()(double r) const { return r * r;} + }; + + p::object ud = p::class_ >("UnarySquare").def("__call__", np::unary_ufunc::make()); + p::object inst = ud(); + std::cout << "Square of unary scalar 1.0 is " << p::extract (p::str(inst.attr("__call__")(1.0))) << std::endl ; + diff --git a/doc/develop/html/numpy/_sources/tutorial/dtype.rst.txt b/doc/develop/html/numpy/_sources/tutorial/dtype.rst.txt new file mode 100644 index 00000000..557e72ba --- /dev/null +++ b/doc/develop/html/numpy/_sources/tutorial/dtype.rst.txt @@ -0,0 +1,54 @@ +How to use dtypes +================= + +Here is a brief tutorial to show how to create ndarrays with built-in python data types, and extract the types and values of member variables + +Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Next, we create the shape and dtype. We use the get_builtin method to get the numpy dtype corresponding to the builtin C++ dtype +Here, we will create a 3x3 array passing a tuple with (3,3) for the size, and double as the data type :: + + p::tuple shape = p::make_tuple(3, 3); + np::dtype dtype = np::dtype::get_builtin(); + np::ndarray a = np::zeros(shape, dtype); + +Finally, we can print the array using the extract method in the python namespace. +Here, we first convert the variable into a string, and then extract it as a C++ character array from the python string using the template :: + + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + +We can also print the dtypes of the data members of the ndarray by using the get_dtype method for the ndarray :: + + std::cout << "Datatype is:\n" << p::extract(p::str(a.get_dtype())) << std::endl ; + +We can also create custom dtypes and build ndarrays with the custom dtypes + +We use the dtype constructor to create a custom dtype. This constructor takes a list as an argument. + +The list should contain one or more tuples of the format (variable name, variable type) + +So first create a tuple with a variable name and its dtype, double, to create a custom dtype :: + + p::tuple for_custom_dtype = p::make_tuple("ha",dtype) ; + +Next, create a list, and add this tuple to the list. Then use the list to create the custom dtype :: + + p::list list_for_dtype ; + list_for_dtype.append(for_custom_dtype) ; + np::dtype custom_dtype = np::dtype(list_for_dtype) ; + +We are now ready to create an ndarray with dimensions specified by \*shape\* and of custom dtpye :: + + np::ndarray new_array = np::zeros(shape,custom_dtype); + } diff --git a/doc/develop/html/numpy/_sources/tutorial/fromdata.rst.txt b/doc/develop/html/numpy/_sources/tutorial/fromdata.rst.txt new file mode 100644 index 00000000..33bcee45 --- /dev/null +++ b/doc/develop/html/numpy/_sources/tutorial/fromdata.rst.txt @@ -0,0 +1,56 @@ +How to access data using raw pointers +===================================== + +One of the advantages of the ndarray wrapper is that the same data can be used in both Python and C++ and changes can be made to reflect at both ends. +The from_data method makes this possible. + +Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Create an array in C++ , and pass the pointer to it to the from_data method to create an ndarray:: + + int arr[] = {1,2,3,4,5}; + np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin(), + p::make_tuple(5), + p::make_tuple(sizeof(int)), + p::object()); + +Print the source C++ array, as well as the ndarray, to check if they are the same:: + + std::cout << "C++ array :" << std::endl; + for (int j=0;j<4;j++) + { + std::cout << arr[j] << ' '; + } + std::cout << std::endl + << "Python ndarray :" << p::extract(p::str(py_array)) << std::endl; + +Now, change an element in the Python ndarray, and check if the value changed correspondingly in the source C++ array:: + + py_array[1] = 5 ; + std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl; + for (int j = 0; j < 5; j++) + { + std::cout << arr[j] << ' '; + } + +Next, change an element of the source C++ array and see if it is reflected in the Python ndarray:: + + arr[2] = 8; + std::cout << std::endl + << "Is the change reflected in the Python ndarray ?" << std::endl + << p::extract(p::str(py_array)) << std::endl; + } + +As we can see, the changes are reflected across the ends. This happens because the from_data method passes the C++ array by reference to create the ndarray, and thus uses the same locations for storing data. + diff --git a/doc/develop/html/numpy/_sources/tutorial/index.rst.txt b/doc/develop/html/numpy/_sources/tutorial/index.rst.txt new file mode 100644 index 00000000..3de2ef53 --- /dev/null +++ b/doc/develop/html/numpy/_sources/tutorial/index.rst.txt @@ -0,0 +1,12 @@ +Boost.Python NumPy extension Tutorial +===================================== + +.. toctree:: + :maxdepth: 2 + + simple + dtype + ndarray + ufunc + fromdata + diff --git a/doc/develop/html/numpy/_sources/tutorial/ndarray.rst.txt b/doc/develop/html/numpy/_sources/tutorial/ndarray.rst.txt new file mode 100644 index 00000000..b270da70 --- /dev/null +++ b/doc/develop/html/numpy/_sources/tutorial/ndarray.rst.txt @@ -0,0 +1,99 @@ +Creating ndarrays +================= + +The Boost.Numpy library exposes quite a few methods to create ndarrays. ndarrays can be created in a variety of ways, include empty arrays and zero filled arrays. +ndarrays can also be created from arbitrary python sequences as well as from data and dtypes. + +This tutorial will introduce you to some of the ways in which you can create ndarrays. The methods covered here include creating ndarrays from arbitrary Python sequences, as well as from C++ containers, using both unit and non-unit strides + +First, as before, initialise the necessary namepaces and runtimes :: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Let's now create an ndarray from a simple tuple. We first create a tuple object, and then pass it to the array method, to generate the necessary tuple :: + + p::object tu = p::make_tuple('a','b','c'); + np::ndarray example_tuple = np::array(tu); + +Let's now try the same with a list. We create an empty list, add an element using the append method, and as before, call the array method :: + + p::list l; + l.append('a'); + np::ndarray example_list = np::array (l); + +Optionally, we can also specify a dtype for the array :: + + np::dtype dt = np::dtype::get_builtin(); + np::ndarray example_list1 = np::array (l,dt); + +We can also create an array by supplying data arrays and a few other parameters. + +First,create an integer array :: + + int data[] = {1,2,3,4,5}; + +Create a shape, and strides, needed by the function :: + + p::tuple shape = p::make_tuple(5); + p::tuple stride = p::make_tuple(sizeof(int)); + +Here, shape is (4,) , and the stride is `sizeof(int)``. +A stride is the number of bytes that must be traveled to get to the next desired element while constructing the ndarray. + +The function also needs an owner, to keep track of the data array passed. Passing none is dangerous :: + + p::object own; + +The from_data function takes the data array, datatype,shape,stride and owner as arguments and returns an ndarray :: + + np::ndarray data_ex1 = np::from_data(data,dt, shape,stride,own); + +Now let's print the ndarray we created :: + + std::cout << "Single dimensional array ::" << std::endl + << p::extract(p::str(data_ex)) << std::endl; + +Let's make it a little more interesting. Lets make an 3x2 ndarray from a multi-dimensional array using non-unit strides + +First lets create a 3x4 array of 8-bit integers :: + + uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}}; + +Now let's create an array of 3x2 elements, picking the first and third elements from each row . For that, the shape will be 3x2. +The strides will be 4x2 i.e. 4 bytes to go to the next desired row, and 2 bytes to go to the next desired column :: + + shape = p::make_tuple(3,2); + stride = p::make_tuple(sizeof(uint8_t)*2,sizeof(uint8_t)); + +Get the numpy dtype for the built-in 8-bit integer data type :: + + np::dtype dt1 = np::dtype::get_builtin(); + +Now lets first create and print out the ndarray as is. +Notice how we can pass the shape and strides in the function directly, as well as the owner. The last part can be done because we don't have any use to +manipulate the "owner" object :: + + np::ndarray mul_data_ex = np::from_data(mul_data, dt1, + p::make_tuple(3,4), + p::make_tuple(4,1), + p::object()); + std::cout << "Original multi dimensional array :: " << std::endl + << p::extract(p::str(mul_data_ex)) << std::endl; + +Now create the new ndarray using the shape and strides and print out the array we created using non-unit strides :: + + mul_data_ex = np::from_data(mul_data, dt1, shape, stride, p::object()); + std::cout << "Selective multidimensional array :: "<(p::str(mul_data_ex)) << std::endl ; + } + +.. note:: The from_data method will throw ``error_already_set`` if the number of elements dictated by the shape and the corresponding strides don't match. diff --git a/doc/develop/html/numpy/_sources/tutorial/simple.rst.txt b/doc/develop/html/numpy/_sources/tutorial/simple.rst.txt new file mode 100644 index 00000000..889eea11 --- /dev/null +++ b/doc/develop/html/numpy/_sources/tutorial/simple.rst.txt @@ -0,0 +1,41 @@ +A simple tutorial on Arrays +=========================== + +Let's start with a simple tutorial to create and modify arrays. + +Get the necessary headers for numpy components and set up necessary namespaces:: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + +Initialise the Python runtime, and the numpy module. Failure to call these results in segmentation errors:: + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + + +Zero filled n-dimensional arrays can be created using the shape and data-type of the array as a parameter. Here, the shape is 3x3 and the datatype is the built-in float type:: + + p::tuple shape = p::make_tuple(3, 3); + np::dtype dtype = np::dtype::get_builtin(); + np::ndarray a = np::zeros(shape, dtype); + +You can also create an empty array like this :: + + np::ndarray b = np::empty(shape,dtype); + +Print the original and reshaped array. The array a which is a list is first converted to a string, and each value in the list is extracted using extract< >:: + + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + + // Reshape the array into a 1D array + a = a.reshape(p::make_tuple(9)); + // Print it again. + std::cout << "Reshaped array:\n" << p::extract(p::str(a)) << std::endl; + } + diff --git a/doc/develop/html/numpy/_sources/tutorial/ufunc.rst.txt b/doc/develop/html/numpy/_sources/tutorial/ufunc.rst.txt new file mode 100644 index 00000000..a3571dbc --- /dev/null +++ b/doc/develop/html/numpy/_sources/tutorial/ufunc.rst.txt @@ -0,0 +1,120 @@ +Ufuncs +====== + +Ufuncs or universal functions operate on ndarrays element by element, and support array broadcasting, type casting, and other features. + +Lets try and see how we can use the binary and unary ufunc methods + +After the neccessary includes :: + + #include + #include + + namespace p = boost::python; + namespace np = boost::python::numpy; + +Now we create the structs necessary to implement the ufuncs. The typedefs *must* be made as the ufunc generators take these typedefs as inputs and return an error otherwise :: + + struct UnarySquare + { + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * r;} + }; + + struct BinarySquare + { + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a,double b) const { return (a*a + b*b) ; } + }; + +Initialise the Python runtime and the numpy module :: + + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); + +Now expose the struct UnarySquare to Python as a class, and let ud be the class object. :: + + p::object ud = p::class_ >("UnarySquare"); + ud.def("__call__", np::unary_ufunc::make()); + +Let inst be an instance of the class ud :: + + p::object inst = ud(); + +Use the "__call__" method to call the overloaded () operator and print the value :: + + std::cout << "Square of unary scalar 1.0 is " << p::extract(p::str(inst.attr("__call__")(1.0))) << std::endl; + +Create an array in C++ :: + + int arr[] = {1,2,3,4} ; + + +..and use it to create the ndarray in Python :: + + np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin(), + p::make_tuple(4), + p::make_tuple(4), + p::object()); + +Print out the demo array :: + + std::cout << "Demo array is " << p::extract(p::str(demo_array)) << std::endl; + +Call the "__call__" method to perform the operation and assign the value to result_array :: + + p::object result_array = inst.attr("__call__")(demo_array); + +Print the resultant array :: + + std::cout << "Square of demo array is " << p::extract(p::str(result_array)) << std::endl; + +Lets try the same with a list :: + + p::list li; + li.append(3); + li.append(7); + +Print out the demo list :: + + std::cout << "Demo list is " << p::extract(p::str(li)) << std::endl; + +Call the ufunc for the list :: + + result_array = inst.attr("__call__")(li); + +And print the list out :: + + std::cout << "Square of demo list is " << p::extract(p::str(result_array)) << std::endl; + +Now lets try Binary ufuncs. Again, expose the struct BinarySquare to Python as a class, and let ud be the class object :: + + ud = p::class_ >("BinarySquare"); + ud.def("__call__", np::binary_ufunc::make()); + +And initialise ud :: + + inst = ud(); + +Print the two input lists :: + + std::cout << "The two input list for binary ufunc are " << std::endl + << p::extract(p::str(demo_array)) << std::endl + << p::extract(p::str(demo_array)) << std::endl; + +Call the binary ufunc taking demo_array as both inputs :: + + result_array = inst.attr("__call__")(demo_array,demo_array); + +And print the output :: + + std::cout << "Square of list with binary ufunc is " << p::extract(p::str(result_array)) << std::endl; + } + diff --git a/doc/develop/html/numpy/_static/basic.css b/doc/develop/html/numpy/_static/basic.css new file mode 100644 index 00000000..0807176e --- /dev/null +++ b/doc/develop/html/numpy/_static/basic.css @@ -0,0 +1,676 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist td { + vertical-align: top; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/doc/develop/html/numpy/_static/boost.css b/doc/develop/html/numpy/_static/boost.css new file mode 100644 index 00000000..28f89359 --- /dev/null +++ b/doc/develop/html/numpy/_static/boost.css @@ -0,0 +1,716 @@ + +/*============================================================================= +Copyright (c) 2004 Joel de Guzman +http://spirit.sourceforge.net/ + +Copyright 2013 Niall Douglas additions for colors and alignment. +Copyright 2013 Paul A. Bristow additions for more colors and alignments. + +Distributed under the Boost Software License, Version 1.0. (See accompany- +ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= +Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= +Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= +Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 9pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= +Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font-size: 140%; } + h2 { font-weight: bold; font-size: 140%; } + h3 { font-weight: bold; font-size: 130%; } + h4 { font-weight: bold; font-size: 120%; } + h5 { font-weight: normal; font-style: italic; font-size: 110%; } + h6 { font-weight: normal; font-style: italic; font-size: 100%; } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= +Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= +Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= +Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= +Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= +Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= +Table of contents +=============================================================================*/ + + div.toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + + /* No margin on nested menus */ + + .toc dl dl { margin: 0; } + +/*============================================================================= +Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= +Suppress margins in tables +=============================================================================*/ + + table th > *:first-child, + table td > *:first-child + { + margin-top: 0; + } + + table th > *:last-child, + table td > *:last-child + { + margin-bottom: 0; + } + +/*============================================================================= +Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= +Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= +Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= +Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Links */ + a, a .keyword, a .identifier, a .special, a .preprocessor + a .char, a .comment, a .string, a .number + { + color: #005a9c; + } + + a:visited, a:visited .keyword, a:visited .identifier, + a:visited .special, a:visited .preprocessor a:visited .char, + a:visited .comment, a:visited .string, a:visited .number + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + div.toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= +Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== +Super and Subscript: style so that line spacing isn't effected, see +http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { +height: 0; +line-height: 1; +vertical-align: baseline; +position: relative; + +} + +/* For internet explorer: */ + +* html sup, +* html sub { +vertical-align: bottom; +} + +sup { +bottom: 1ex; +} + +sub { +top: .5ex; +} + +/*============================================================================== +Indexes: pretty much the same as the TOC. +==============================================================================*/ + + .index + { + font-size: 80%; + padding-top: 0px; + padding-bottom: 0px; + margin-top: 0px; + margin-bottom: 0px; + margin-left: 0px; + } + + .index ul + { + padding-left: 3em; + } + + .index p + { + padding: 2px; + margin: 2px; + } + + .index-entry-level-0 + { + font-weight: bold; + } + + .index em + { + font-weight: bold; + } + + +/*============================================================================== +Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. +Added from Niall Douglas for role color and alignment. +http://article.gmane.org/gmane.comp.lib.boost.devel/243318 +*/ + +/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ +span.aligncenter +{ + display: inline-block; width: 100%; text-align: center; +} +span.alignright +{ + display: inline-block; width: 100%; text-align: right; +} +/* alignleft is the default. */ +span.alignleft +{ + display: inline-block; width: 100%; text-align: left; +} + +/* alignjustify stretches the word spacing so that each line has equal width +within a chosen fraction of page width (here arbitrarily 20%). +*Not* useful inside table items as the column width remains the total string width. +Nor very useful, except to temporarily restrict the width. +*/ +span.alignjustify +{ + display: inline-block; width: 20%; text-align: justify; +} + +/* Text colors. +Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. +Quickbook Usage: [role red Some red text] + +*/ +span.red { inline-block; color: red; } +span.green { color: green; } +span.lime { color: #00FF00; } +span.blue { color: blue; } +span.navy { color: navy; } +span.yellow { color: yellow; } +span.magenta { color: magenta; } +span.indigo { color: #4B0082; } +span.cyan { color: cyan; } +span.purple { color: purple; } +span.gold { color: gold; } +span.silver { color: silver; } /* lighter gray */ +span.gray { color: #808080; } /* light gray */ diff --git a/doc/develop/html/numpy/_static/boost.png b/doc/develop/html/numpy/_static/boost.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d51fcd5c9149fd77f5ca6ed2b6b1b70e8fe24f GIT binary patch literal 6308 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 literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/_static/bpl.png b/doc/develop/html/numpy/_static/bpl.png new file mode 100644 index 0000000000000000000000000000000000000000..c2d8c69e00ca3aada62024809e20d138a8906875 GIT binary patch literal 21289 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 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('

') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/doc/develop/html/numpy/_static/documentation_options.js b/doc/develop/html/numpy/_static/documentation_options.js new file mode 100644 index 00000000..1925df3b --- /dev/null +++ b/doc/develop/html/numpy/_static/documentation_options.js @@ -0,0 +1,10 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '1.0', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, +}; \ No newline at end of file diff --git a/doc/develop/html/numpy/_static/file.png b/doc/develop/html/numpy/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7o_e}ChEy=Fo!lJ6#wgPI zU9-A1=eok}ZEQDX(r(*2tb58m$7=u1ea82H)jeO=^6%fjou57xMW{G_5a*B3{pP}1 zS6~0}?_b_epFayX9PiZV3J_7<*U-z(&Te62!(wS=#r62dj~f93Q(yV3O;UNueM4ey zPF+*P_cxDwe?L<@A-VUOYxn_?IFqgAjDfX>&K+iC+ZOj{hWM55XBY3QXXIt>UXl5V zY32J_2KpZQFCE-8U%FHkYESx{HDO9L>%8Dl(|ry6XI@BV%vz@ZVSj$)G){LlpS0qd r#>Mpuckiw~`|AFW`^Ks}LhH4IH@r-6bi2gBz`)??>gTe~DWM4fp;vuF literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/_static/home.png b/doc/develop/html/numpy/_static/home.png new file mode 100644 index 0000000000000000000000000000000000000000..5584aacb097a80e66a5320312b6e4eb017af1a06 GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0y~yU=Rjj7G?$phK4%r{|pQa%*9TgAsieWw;%dHU|?WS z3GfMV6&Dfg?(A@OuseF>a6(*+nzF*onKLh6zO-%YmOy{sw6wJU|Nk%gvq74Hfq|za z$S?Rm0x$^OKX;CSfq}EYBeIx*fm;ZK886+f`@_J%pjzS@Q4*Y=R#Ki=l*-_nm|T>f zo0^iDsNj}alvU8YOY t9}F9JU6`43jMG5vNQA& elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + + + + var preservedScriptAttributes = { + type: true, + src: true, + noModule: true + }; + + function DOMEval( code, doc, node ) { + doc = doc || document; + + var i, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + if ( node[ i ] ) { + script[ i ] = node[ i ]; + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.3.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + div.style.position = "absolute"; + scrollboxSizeVal = div.offsetWidth === 36 || "absolute"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + ) ); + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + val = curCSS( elem, dimension, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox; + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = valueIsBorderBox && + ( support.boxSizingReliable() || val === elem.style[ dimension ] ); + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + if ( val === "auto" || + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { + + val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; + + // offsetWidth/offsetHeight provide border-box values + valueIsBorderBox = true; + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra && boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ); + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && support.scrollboxSize() === styles.position ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = Date.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + + +

Index

+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/index.html b/doc/develop/html/numpy/index.html new file mode 100644 index 00000000..ae76c96b --- /dev/null +++ b/doc/develop/html/numpy/index.html @@ -0,0 +1,99 @@ + + + + + + + + Welcome to the documentation of the Boost.Python NumPy extension! - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + + + + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/objects.inv b/doc/develop/html/numpy/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..1906accfe8317a1b8416f6c3f9836b81c5d4fdb2 GIT binary patch literal 483 zcmY#Z2rkIT%&Sny%qvUHE6FdaR47X=D$dN$Q!wIERtPA{&q_@$u~Kl#&o3^~3#cr~ z$j?*oE6ok4R7kBTNzDVPNY2kKC`v6ZPEAoLEzZnKSE$O#Ow!}3xYaxPwBHc}9@p=Gxjr)*cj)eJ zb>1L#eJ&9te5vMUt2qCo8SiTn)kLF-)wVRz2=BE%cSp7HH+Ks%3et> ztyf$8aHqZ4X5U?#%vJmJuPim@c+zl=W3Hmq78MUm?sZaK{O4G2$wyn2Z@r$;r~6>) zg|>6W!4m4mwI*-#gnld(S6_T=qjJA!)fUxzb=ulB)m@=mQg0>QJGf%Yqy;Kld7nu( zA9?t2#uBr`k)CsY<+6M*Qx#g%IqQn2;4ho%Yd;%*&U08Ja literal 0 HcmV?d00001 diff --git a/doc/develop/html/numpy/reference/binary_ufunc.html b/doc/develop/html/numpy/reference/binary_ufunc.html new file mode 100644 index 00000000..371e0cf5 --- /dev/null +++ b/doc/develop/html/numpy/reference/binary_ufunc.html @@ -0,0 +1,212 @@ + + + + + + + + binary_ufunc - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

binary_ufunc

+
+

Table of Contents

+ +
+

A binary_ufunc is a struct used as an intermediate step to broadcast two arguments so that a C++ function can be converted to a ufunc like function

+
+
<boost/python/numpy/ufunc.hpp> contains the binary_ufunc structure definitions
+
+

synopsis

+
namespace boost
+{
+namespace python
+{
+namespace numpy
+{
+
+template <typename TBinaryFunctor,
+          typename TArgument1=typename TBinaryFunctor::first_argument_type,
+          typename TArgument2=typename TBinaryFunctor::second_argument_type,
+          typename TResult=typename TBinaryFunctor::result_type>
+
+struct binary_ufunc
+{
+
+  static object call(TBinaryFunctor & self,
+                     object const & input1,
+                     object const & input2,
+                     object const & output);
+
+  static object make();
+};
+
+}
+}
+}
+
+
+
+
+

constructors

+
struct example_binary_ufunc
+{
+  typedef any_valid first_argument_type;
+  typedef any_valid second_argument_type;
+  typedef any_valid result_type;
+};
+
+
+ +++ + + + + + +
Requirements:The any_valid type must be defined using typedef as a valid C++ type in order to use the struct methods correctly
Note:The struct must be exposed as a Python class, and an instance of the class must be created to use the call method corresponding to the __call__ attribute of the Python object
+
+
+

accessors

+
template <typename TBinaryFunctor,
+          typename TArgument1=typename TBinaryFunctor::first_argument_type,
+          typename TArgument2=typename TBinaryFunctor::second_argument_type,
+          typename TResult=typename TBinaryFunctor::result_type>
+static object call(TBinaryFunctor & self,
+                   object const & input,
+                   object const & output);
+
+
+ +++ + + + + + +
Requires:Typenames TBinaryFunctor and optionally TArgument1 and TArgument2 for argument type and TResult for result type
Effects:Passes a Python object to the underlying C++ functor after broadcasting its arguments
+
template <typename TBinaryFunctor,
+          typename TArgument1=typename TBinaryFunctor::first_argument_type,
+          typename TArgument2=typename TBinaryFunctor::second_argument_type,
+          typename TResult=typename TBinaryFunctor::result_type>
+static object make();
+
+
+ +++ + + + + + +
Requires:Typenames TBinaryFunctor and optionally TArgument1 and TArgument2 for argument type and TResult for result type
Returns:A Python function object to call the overloaded () operator in the struct (in typical usage)
+
+
+

Example(s)

+
namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+struct BinarySquare
+{
+  typedef double first_argument_type;
+  typedef double second_argument_type;
+  typedef double result_type;
+
+  double operator()(double a,double b) const { return (a*a + b*b) ; }
+};
+
+p::object ud = p::class_<BinarySquare, boost::shared_ptr<BinarySquare> >("BinarySquare").def("__call__", np::binary_ufunc<BinarySquare>::make());
+p::object inst = ud();
+result_array = inst.attr("__call__")(demo_array,demo_array) ;
+std::cout << "Square of list with binary ufunc is " << p::extract <char const * > (p::str(result_array)) << std::endl ;
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/reference/dtype.html b/doc/develop/html/numpy/reference/dtype.html new file mode 100644 index 00000000..f15cc374 --- /dev/null +++ b/doc/develop/html/numpy/reference/dtype.html @@ -0,0 +1,196 @@ + + + + + + + + dtype - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

dtype

+
+

Table of Contents

+ +
+

A dtype is an object describing the type of the elements of an ndarray

+
+
<boost/python/numpy/dtype.hpp> contains the method calls necessary to generate a python object equivalent to a numpy.dtype from builtin C++ objects, as well as to create custom dtypes from user defined types
+
+

synopsis

+
namespace boost
+{
+namespace python
+{
+namespace numpy
+{
+
+class dtype : public object
+{
+  static python::detail::new_reference convert(object::object_cref arg, bool align);
+public:
+
+  // Convert an arbitrary Python object to a data-type descriptor object.
+  template <typename T>
+  explicit dtype(T arg, bool align=false);
+
+  // Get the built-in numpy dtype associated with the given scalar template type.
+  template <typename T> static dtype get_builtin();
+
+  // Return the size of the data type in bytes.
+  int get_itemsize() const;
+};
+
+}
+}
+}
+
+
+
+
+

constructors

+
template <typename T>
+explicit dtype(T arg, bool align=false)
+
+
+ +++ + + + + + + + +
Requirements:

T must be either :

+
    +
  • a built-in C++ typename convertible to object
  • +
  • a valid python object or convertible to object
  • +
+
Effects:

Constructs an object from the supplied python object / convertible +to object / builtin C++ data type

+
Throws:

Nothing

+
+
template <typename T> static dtype get_builtin();
+
+
+ +++ + + + + + +
Requirements:The typename supplied, T must be a builtin C++ type also supported by numpy
Returns:Numpy dtype corresponding to builtin C++ type
+
+
+

accessors

+
int get_itemsize() const;
+
+
+ +++ + + + +
Returns:the size of the data type in bytes.
+
+
+

Example(s)

+
namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+np::dtype dtype = np::dtype::get_builtin<double>();
+p::tuple for_custom_dtype = p::make_tuple("ha",dtype);
+np::dtype custom_dtype = np::dtype(list_for_dtype);
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/reference/index.html b/doc/develop/html/numpy/reference/index.html new file mode 100644 index 00000000..6acde14c --- /dev/null +++ b/doc/develop/html/numpy/reference/index.html @@ -0,0 +1,120 @@ + + + + + + + + Boost.Python NumPy extension Reference - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + + + + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/reference/multi_iter.html b/doc/develop/html/numpy/reference/multi_iter.html new file mode 100644 index 00000000..b784fa2d --- /dev/null +++ b/doc/develop/html/numpy/reference/multi_iter.html @@ -0,0 +1,212 @@ + + + + + + + + multi_iter - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

multi_iter

+
+

Table of Contents

+ +
+

A multi_iter is a Python object, intended to be used as an iterator It should generally only be used in loops.

+
+
<boost/python/numpy/ufunc.hpp> contains the class definitions for multi_iter
+
+

synopsis

+
namespace boost
+{
+namespace python
+{
+namespace numpy
+{
+
+class multi_iter : public object
+{
+public:
+  void next();
+  bool not_done() const;
+  char * get_data(int n) const;
+  int const get_nd() const;
+  Py_intptr_t const * get_shape() const;
+  Py_intptr_t const shape(int n) const;
+};
+
+
+multi_iter make_multi_iter(object const & a1);
+multi_iter make_multi_iter(object const & a1, object const & a2);
+multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3);
+
+}
+}
+}
+
+
+
+
+

constructors

+
multi_iter make_multi_iter(object const & a1);
+multi_iter make_multi_iter(object const & a1, object const & a2);
+multi_iter make_multi_iter(object const & a1, object const & a2, object const & a3);
+
+
+ +++ + + + +
Returns:A Python iterator object broadcasting over one, two or three sequences as supplied
+
+
+

accessors

+
void next();
+
+
+ +++ + + + +
Effects:Increments the iterator
+
bool not_done() const;
+
+
+ +++ + + + +
Returns:boolean value indicating whether the iterator is at its end
+
char * get_data(int n) const;
+
+
+ +++ + + + +
Returns:a pointer to the element of the nth broadcasted array.
+
int const get_nd() const;
+
+
+ +++ + + + +
Returns:the number of dimensions of the broadcasted array expression
+
Py_intptr_t const * get_shape() const;
+
+
+ +++ + + + +
Returns:the shape of the broadcasted array expression as an array of integers.
+
Py_intptr_t const shape(int n) const;
+
+
+ +++ + + + +
Returns:the shape of the broadcasted array expression in the nth dimension.
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/reference/ndarray.html b/doc/develop/html/numpy/reference/ndarray.html new file mode 100644 index 00000000..ed47cc6c --- /dev/null +++ b/doc/develop/html/numpy/reference/ndarray.html @@ -0,0 +1,629 @@ + + + + + + + + ndarray - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

ndarray

+
+

Table of Contents

+ +
+

A ndarray is an N-dimensional array which contains items of the same type and size, where N is the number of dimensions and is specified in the form of a shape tuple. Optionally, the numpy dtype for the objects contained may also be specified.

+
+
<boost/python/numpy/ndarray.hpp> contains the structures and methods necessary to move raw data between C++ and Python and create ndarrays from the data
+
+

synopsis

+
namespace boost
+{
+namespace python
+{
+namespace numpy
+{
+
+class ndarray : public object
+{
+
+public:
+
+  enum bitflag
+  {
+    NONE=0x0, C_CONTIGUOUS=0x1, F_CONTIGUOUS=0x2, V_CONTIGUOUS=0x1|0x2,
+    ALIGNED=0x4, WRITEABLE=0x8, BEHAVED=0x4|0x8,
+    CARRAY_RO=0x1|0x4, CARRAY=0x1|0x4|0x8, CARRAY_MIS=0x1|0x8,
+    FARRAY_RO=0x2|0x4, FARRAY=0x2|0x4|0x8, FARRAY_MIS=0x2|0x8,
+    UPDATE_ALL=0x1|0x2|0x4, VARRAY=0x1|0x2|0x8, ALL=0x1|0x2|0x4|0x8
+  };
+
+  ndarray view(dtype const & dt) const;
+  ndarray astype(dtype const & dt) const;
+  ndarray copy() const;
+  int const shape(int n) const;
+  int const strides(int n) const;
+  char * get_data() const;
+  dtype get_dtype() const;
+  python::object get_base() const;
+  void set_base(object const & base);
+  Py_intptr_t const * get_shape() const;
+  Py_intptr_t const * get_strides() const;
+  int const get_nd() const;
+
+  bitflag const get_flags() const;
+
+  ndarray transpose() const;
+  ndarray squeeze() const;
+  ndarray reshape(tuple const & shape) const;
+  object scalarize() const;
+};
+
+ndarray zeros(tuple const & shape, dtype const & dt);
+ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt);
+
+ndarray empty(tuple const & shape, dtype const & dt);
+ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt);
+
+ndarray array(object const & obj);
+ndarray array(object const & obj, dtype const & dt);
+
+template <typename Container>
+ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner);
+template <typename Container>
+ndarray from_data(void const * data, dtype const & dt, Container shape, Container strides, object const & owner);
+
+ndarray from_object(object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE);
+ndarray from_object(object const & obj, dtype const & dt,int nd, ndarray::bitflag flags=ndarray::NONE);
+ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE);
+ndarray from_object(object const & obj, int nd_min, int nd_max,ndarray::bitflag flags=ndarray::NONE);
+ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE);
+ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE)
+
+ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b) ;
+ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b);
+
+}
+
+
+
+
+

constructors

+
ndarray view(dtype const & dt) const;
+
+
+ +++ + + + +
Returns:new ndarray with old ndarray data cast as supplied dtype
+
ndarray astype(dtype const & dt) const;
+
+
+ +++ + + + +
Returns:new ndarray with old ndarray data converted to supplied dtype
+
ndarray copy() const;
+
+
+ +++ + + + +
Returns:Copy of calling ndarray object
+
ndarray transpose() const;
+
+
+ +++ + + + +
Returns:An ndarray with the rows and columns interchanged
+
ndarray squeeze() const;
+
+
+ +++ + + + +
Returns:An ndarray with all unit-shaped dimensions removed
+
ndarray reshape(tuple const & shape) const;
+
+
+ +++ + + + + + +
Requirements:The new shape of the ndarray must be supplied as a tuple
Returns:An ndarray with the same data but reshaped to the shape supplied
+
object scalarize() const;
+
+
+ +++ + + + +
Returns:A scalar if the ndarray has only one element, otherwise it returns the entire array
+
ndarray zeros(tuple const & shape, dtype const & dt);
+ndarray zeros(int nd, Py_intptr_t const * shape, dtype const & dt);
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied as required :

+
    +
  • the shape or the size of all dimensions, as a tuple
  • +
  • the dtype of the data
  • +
  • the nd size for a square shaped ndarray
  • +
  • the shape Py_intptr_t
  • +
+
Returns:

A new ndarray with the given shape and data type, with data initialized to zero.

+
+
ndarray empty(tuple const & shape, dtype const & dt);
+ndarray empty(int nd, Py_intptr_t const * shape, dtype const & dt);
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the shape or the size of all dimensions, as a tuple
  • +
  • the dtype of the data
  • +
  • the shape Py_intptr_t
  • +
+
Returns:

A new ndarray with the given shape and data type, with data left uninitialized.

+
+
ndarray array(object const & obj);
+ndarray array(object const & obj, dtype const & dt);
+
+
+ +++ + + + +
Returns:A new ndarray from an arbitrary Python sequence, with dtype of each element specified optionally
+
template <typename Container>
+inline ndarray from_data(void * data,dtype const & dt,Container shape,Container strides,python::object const & owner)
+
+
+ +++ + + + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the data which is a generic C++ data container
  • +
  • the dtype dt of the data
  • +
  • the shape of the ndarray as Python object
  • +
  • the strides of each dimension of the array as a Python object
  • +
  • the owner of the data, in case it is not the ndarray itself
  • +
+
Returns:

ndarray with attributes and data supplied

+
Note:

The Container typename must be one that is convertible to a std::vector or python object type

+
+
ndarray from_object(object const & obj, dtype const & dt,int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE);
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the obj Python object to convert to ndarray
  • +
  • the dtype dt of the data
  • +
  • minimum number of dimensions nd_min of the ndarray as Python object
  • +
  • maximum number of dimensions nd_max of the ndarray as Python object
  • +
  • optional flags bitflags
  • +
+
Returns:

ndarray constructed with dimensions and data supplied as parameters

+
+
inline ndarray from_object(object const & obj, dtype const & dt, int nd, ndarray::bitflag flags=ndarray::NONE);
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the obj Python object to convert to ndarray
  • +
  • the dtype dt of the data
  • +
  • number of dimensions nd of the ndarray as Python object
  • +
  • optional flags bitflags
  • +
+
Returns:

ndarray with dimensions nd x nd and suplied parameters

+
+
inline ndarray from_object(object const & obj, dtype const & dt, ndarray::bitflag flags=ndarray::NONE)
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the obj Python object to convert to ndarray
  • +
  • the dtype dt of the data
  • +
  • optional flags bitflags
  • +
+
Returns:

Supplied Python object as ndarray

+
+
ndarray from_object(object const & obj, int nd_min, int nd_max, ndarray::bitflag flags=ndarray::NONE);
+
+
+ +++ + + + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the obj Python object to convert to ndarray
  • +
  • minimum number of dimensions nd_min of the ndarray as Python object
  • +
  • maximum number of dimensions nd_max of the ndarray as Python object
  • +
  • optional flags bitflags
  • +
+
Returns:

ndarray with supplied dimension limits and parameters

+
Note:

dtype need not be supplied here

+
+
inline ndarray from_object(object const & obj, int nd, ndarray::bitflag flags=ndarray::NONE);
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the obj Python object to convert to ndarray
  • +
  • the dtype dt of the data
  • +
  • number of dimensions nd of the ndarray as Python object
  • +
  • optional flags bitflags
  • +
+
Returns:

ndarray of nd x nd dimensions constructed from the supplied object

+
+
inline ndarray from_object(object const & obj, ndarray::bitflag flags=ndarray::NONE)
+
+
+ +++ + + + + + +
Requirements:

The following parameters must be supplied :

+
    +
  • the obj Python object to convert to ndarray
  • +
  • optional flags bitflags
  • +
+
Returns:

ndarray of same dimensions and dtype as supplied Python object

+
+
+
+

accessors

+
int const shape(int n) const;
+
+
+ +++ + + + +
Returns:The size of the n-th dimension of the ndarray
+
int const strides(int n) const;
+
+
+ +++ + + + +
Returns:The stride of the nth dimension.
+
char * get_data() const;
+
+
+ +++ + + + + + +
Returns:Array’s raw data pointer as a char
Note:This returns char so stride math works properly on it.User will have to reinterpret_cast it.
+
dtype get_dtype() const;
+
+
+ +++ + + + +
Returns:Array’s data-type descriptor object (dtype)
+
object get_base() const;
+
+
+ +++ + + + +
Returns:Object that owns the array’s data, or None if the array owns its own data.
+
void set_base(object const & base);
+
+
+ +++ + + + +
Returns:Set the object that owns the array’s data. Exercise caution while using this
+
Py_intptr_t const * get_shape() const;
+
+
+ +++ + + + +
Returns:Shape of the array as an array of integers
+
Py_intptr_t const * get_strides() const;
+
+
+ +++ + + + +
Returns:Stride of the array as an array of integers
+
int const get_nd() const;
+
+
+ +++ + + + +
Returns:Number of array dimensions
+
bitflag const get_flags() const;
+
+
+ +++ + + + +
Returns:Array flags
+
inline ndarray::bitflag operator|(ndarray::bitflag a, ndarray::bitflag b)
+
+
+ +++ + + + +
Returns:bitflag logically OR-ed as (a | b)
+
inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b)
+
+
+ +++ + + + +
Returns:bitflag logically AND-ed as (a & b)
+
+
+

Example(s)

+
namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+p::object tu = p::make_tuple('a','b','c') ;
+np::ndarray example_tuple = np::array (tu) ;
+
+p::list l ;
+np::ndarray example_list = np::array (l) ;
+
+np::dtype dt = np::dtype::get_builtin<int>();
+np::ndarray example_list1 = np::array (l,dt);
+
+int data[] = {1,2,3,4} ;
+p::tuple shape = p::make_tuple(4) ;
+p::tuple stride = p::make_tuple(4) ;
+p::object own ;
+np::ndarray data_ex = np::from_data(data,dt,shape,stride,own);
+
+uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}};
+shape = p::make_tuple(3,2) ;
+stride = p::make_tuple(4,2) ;
+np::dtype dt1 = np::dtype::get_builtin<uint8_t>();
+
+np::ndarray mul_data_ex = np::from_data(mul_data,dt1, p::make_tuple(3,4),p::make_tuple(4,1),p::object());
+mul_data_ex = np::from_data(mul_data,dt1, shape,stride,p::object());
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/reference/unary_ufunc.html b/doc/develop/html/numpy/reference/unary_ufunc.html new file mode 100644 index 00000000..4f6c6012 --- /dev/null +++ b/doc/develop/html/numpy/reference/unary_ufunc.html @@ -0,0 +1,203 @@ + + + + + + + + unary_ufunc - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

unary_ufunc

+
+

Table of Contents

+ +
+

A unary_ufunc is a struct used as an intermediate step to broadcast a single argument so that a C++ function can be converted to a ufunc like function

+
+
<boost/python/numpy/ufunc.hpp> contains the unary_ufunc structure definitions
+
+

synopsis

+
namespace boost
+{
+namespace python
+{
+namespace numpy
+{
+
+template <typename TUnaryFunctor,
+          typename TArgument=typename TUnaryFunctor::argument_type,
+          typename TResult=typename TUnaryFunctor::result_type>
+struct unary_ufunc
+{
+
+  static object call(TUnaryFunctor & self,
+                     object const & input,
+                     object const & output) ;
+
+  static object make();
+
+};
+}
+}
+}
+
+
+
+
+

constructors

+
struct example_unary_ufunc
+{
+  typedef any_valid_type argument_type;
+  typedef any_valid_type result_type;
+};
+
+
+ +++ + + + + + +
Requirements:The any_valid type must be defined using typedef as a valid C++ type in order to use the struct methods correctly
Note:The struct must be exposed as a Python class, and an instance of the class must be created to use the call method corresponding to the __call__ attribute of the Python object
+
+
+

accessors

+
template <typename TUnaryFunctor,
+          typename TArgument=typename TUnaryFunctor::argument_type,
+          typename TResult=typename TUnaryFunctor::result_type>
+static object call(TUnaryFunctor & self,
+                   object const & input,
+                   object const & output);
+
+
+ +++ + + + + + +
Requires:Typenames TUnaryFunctor and optionally TArgument for argument type and TResult for result type
Effects:Passes a Python object to the underlying C++ functor after broadcasting its arguments
+
template <typename TUnaryFunctor,
+          typename TArgument=typename TUnaryFunctor::argument_type,
+          typename TResult=typename TUnaryFunctor::result_type>
+static object make();
+
+
+ +++ + + + + + +
Requires:Typenames TUnaryFunctor and optionally TArgument for argument type and TResult for result type
Returns:A Python function object to call the overloaded () operator in the struct (in typical usage)
+
+
+

Example(s)

+
namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+struct UnarySquare
+{
+  typedef double argument_type;
+  typedef double result_type;
+  double operator()(double r) const { return r * r;}
+};
+
+p::object ud = p::class_<UnarySquare, boost::shared_ptr<UnarySquare> >("UnarySquare").def("__call__", np::unary_ufunc<UnarySquare>::make());
+p::object inst = ud();
+std::cout << "Square of unary scalar 1.0 is " << p::extract <char const * > (p::str(inst.attr("__call__")(1.0))) << std::endl ;
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/search.html b/doc/develop/html/numpy/search.html new file mode 100644 index 00000000..eb0b1f45 --- /dev/null +++ b/doc/develop/html/numpy/search.html @@ -0,0 +1,93 @@ + + + + + + + + Search - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+
+
+
+
+ + +

Search

+
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+

+ From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

+
+ + + +
+ +
+ +
+ + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/searchindex.js b/doc/develop/html/numpy/searchindex.js new file mode 100644 index 00000000..0e4f075a --- /dev/null +++ b/doc/develop/html/numpy/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["index","reference/binary_ufunc","reference/dtype","reference/index","reference/multi_iter","reference/ndarray","reference/unary_ufunc","tutorial/dtype","tutorial/fromdata","tutorial/index","tutorial/ndarray","tutorial/simple","tutorial/ufunc"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:55},filenames:["index.rst","reference/binary_ufunc.rst","reference/dtype.rst","reference/index.rst","reference/multi_iter.rst","reference/ndarray.rst","reference/unary_ufunc.rst","tutorial/dtype.rst","tutorial/fromdata.rst","tutorial/index.rst","tutorial/ndarray.rst","tutorial/simple.rst","tutorial/ufunc.rst"],objects:{},objnames:{},objtypes:{},terms:{"0x0":5,"0x1":5,"0x2":5,"0x4":5,"0x8":5,"3x2":10,"3x3":[7,11],"3x4":10,"4x2":10,"boolean":4,"byte":[2,10],"case":5,"char":[1,4,5,6,7,8,10,11,12],"class":[1,2,4,5,6,12],"const":[1,2,4,5,6,7,8,10,11,12],"enum":5,"final":7,"float":11,"function":[1,6,10,12],"int":[2,4,5,7,8,10,11,12],"new":[5,10],"public":[2,4,5],"return":[1,2,4,5,6,10,12],"static":[1,2,6],"throw":[2,10],"try":[10,12],"void":[4,5],"while":[5,10],AND:5,And:12,For:10,One:8,The:[1,2,5,6,7,8,10,11,12],Then:7,Use:12,__call__:[1,6,12],access:[0,9],accessor:3,across:8,add:[7,10],advantag:8,after:[1,6,12],again:[11,12],align:[2,5],all:5,also:[2,5,7,10,11],ani:10,any_valid:[1,6],any_valid_typ:6,append:[7,10,12],arbitrari:[2,5,10],arg:2,argc:[7,8,10,11,12],argument:[1,6,7,10],argument_typ:[6,12],argv:[7,8,10,11,12],arr:[8,12],arrai:[0,4,5,7,8,9,10,12],assign:12,associ:2,astyp:5,attr:[1,6,12],attribut:[1,5,6],base:5,becaus:[8,10],befor:[7,8,10],behav:5,between:5,binari:[1,12],binary_ufunc:[0,3,12],binarysquar:[1,12],bit:10,bitflag:5,bool:[2,4],boost:[1,2,4,5,6,7,8,10,11,12],both:[8,10,12],brief:7,broadcast:[1,4,6,12],build:7,built:[2,7,10,11],builtin:[2,7],c_contigu:5,call:[1,2,5,6,10,11,12],can:[1,6,7,8,10,11,12],carrai:5,carray_mi:5,carray_ro:5,cast:[5,12],caution:5,chang:8,charact:7,check:8,class_:[1,6,12],column:[5,10],compon:11,construct:[2,5,10],constructor:[3,7],contain:[1,2,4,5,6,7,10],convert:[1,2,5,6,7,11],copi:5,correctli:[1,6],correspond:[1,2,6,7,10],correspondingli:8,cout:[1,6,7,8,10,11,12],cover:10,creat:[0,1,2,5,6,7,8,9,11,12],custom:[2,7],custom_dtyp:[2,7],danger:10,data:[0,2,5,7,9,10,11],data_ex1:10,data_ex:[5,10],datatyp:[7,10,11],def:[1,6,12],defin:[1,2,6],definit:[1,4,6],demo:12,demo_arrai:[1,12],describ:2,descriptor:[2,5],desir:10,detail:2,dictat:10,dimens:[4,5,7],dimension:[5,10,11],directli:10,don:10,done:10,doubl:[1,2,6,7,12],dt1:[5,10],dtpye:7,dtype:[0,3,5,8,9,10,11,12],each:[5,10,11],effect:[1,2,4,6],either:2,element:[2,4,5,8,10,12],empti:[5,10,11],end:[4,8],endl:[1,6,7,8,10,11,12],entir:5,equival:2,error:[11,12],error_already_set:10,exampl:3,example_binary_ufunc:1,example_list1:[5,10],example_list:[5,10],example_tupl:[5,10],example_unary_ufunc:6,exercis:5,explicit:2,expos:[1,6,10,12],express:4,extract:[1,6,7,8,10,11,12],f_contigu:5,failur:11,fals:2,farrai:5,farray_mi:5,farray_ro:5,featur:12,few:10,fill:[10,11],first:[7,8,10,11],first_argument_typ:[1,12],flag:5,follow:5,for_custom_dtyp:[2,7],form:5,format:7,from:[2,5,7,10],from_data:[5,8,10,12],from_object:5,functor:[1,6],gener:[2,4,5,10,12],get:[2,7,8,10,11],get_bas:5,get_builtin:[2,5,7,8,10,11,12],get_data:[4,5],get_dtyp:[5,7],get_flag:5,get_items:2,get_nd:[4,5],get_shap:[4,5],get_strid:5,given:[2,5],happen:8,has:5,have:[5,10],header:[7,8,11],here:[5,7,10,11],how:[0,9,10,12],hpp:[1,2,4,5,6,7,8,10,11,12],implement:12,includ:[7,8,10,11,12],increment:4,indic:4,initi:[5,7,8,10,11,12],initialis:[10,11,12],inlin:5,input1:1,input2:1,input:[1,6,12],inst:[1,6,12],instanc:[1,6,12],integ:[4,5,10],intend:4,interchang:5,interest:10,intermedi:[1,6],introduc:10,iostream:[7,8,10,11,12],item:5,iter:4,its:[1,4,5,6,7],itself:5,keep:10,last:10,left:5,let:[10,11,12],librari:10,like:[1,6,7,8,11],limit:5,list:[1,5,7,10,11,12],list_for_dtyp:[2,7],littl:10,locat:8,logic:5,loop:4,made:[8,12],mai:5,main:[7,8,10,11,12],make:[1,6,8,10,12],make_multi_it:4,make_tupl:[2,5,7,8,10,11,12],manipul:10,match:10,math:5,maximum:5,member:7,method:[1,2,5,6,7,8,10,12],minimum:5,modifi:11,modul:[7,8,11,12],more:[7,10],move:5,mul_data:[5,10],mul_data_ex:[5,10],multi:10,multi_it:[0,3],multidimension:10,must:[1,2,5,6,10,12],name:7,namepac:10,namespac:[1,2,4,5,6,7,8,10,11,12],nd_max:5,nd_min:5,ndarrai:[0,2,3,7,8,9,11,12],neccessari:12,necessari:[2,5,7,8,10,11,12],need:[5,10],new_arrai:7,new_refer:2,next:[4,7,8,10],non:10,none:[5,10],not_don:4,note:[1,5,6],noth:2,notic:10,now:[7,8,10,12],nth:[4,5],number:[4,5,10],numpi:[1,2,4,5,6,7,8,10,11,12],obj:5,object:[1,2,4,5,6,8,10,12],object_cref:2,old:5,one:[4,5,7],onli:[4,5],oper:[1,5,6,12],option:[1,5,6,10],order:[1,6],origin:[7,10,11],other:[10,12],otherwis:[5,12],out:[10,12],output:[1,6,12],over:4,overload:[1,6,12],own:[5,10],owner:[5,10],paramet:[5,10,11],part:10,pass:[1,6,7,8,10],perform:12,pick:10,pointer:[0,4,5,9],possibl:8,print:[7,8,10,11,12],properli:5,py_arrai:8,py_initi:[7,8,10,11,12],py_intptr_t:[4,5],python:[1,2,4,5,6,7,8,10,11,12],quit:10,raw:[0,5,9],readi:7,refer:[0,8],reflect:8,reinterpret_cast:5,remov:5,requir:[1,2,5,6],reshap:[5,11],result:[1,6,11,12],result_arrai:[1,12],result_typ:[1,6,12],row:[5,10],runtim:[7,8,10,11,12],same:[5,8,10,12],scalar:[2,5,6,12],second_argument_typ:[1,12],see:[8,12],segment:11,select:10,self:[1,6],sequenc:[4,5,10],set:[5,11],set_bas:5,setup:[7,8],shape:[4,5,7,10,11],shared_ptr:[1,6,12],should:[4,7],show:7,simpl:[0,9,10],singl:[6,10],size:[2,5,7],sizeof:[8,10],some:10,sourc:8,specifi:[5,7,10],squar:[1,5,6,12],squeez:5,start:11,std:[1,5,6,7,8,10,11,12],step:[1,6],store:8,str:[1,6,7,8,10,11,12],stride:[5,10],string:[7,11],struct:[1,6,12],structur:[1,5,6],supli:5,suppli:[2,4,5,10],support:[2,12],synopsi:3,take:[7,10,12],targument1:1,targument2:1,targument:6,tbinaryfunctor:1,templat:[1,2,5,6,7],thei:8,thi:[5,7,8,10,11],third:10,three:4,thu:8,track:10,transpos:5,travel:10,tresult:[1,6],tunaryfunctor:6,tupl:[2,5,7,10,11],tutori:[0,7,10],two:[1,4,12],type:[1,2,5,6,7,10,11,12],typedef:[1,6,12],typenam:[1,2,5,6],typic:[1,6],ufunc:[0,1,4,6,9],uint8_t:[5,10],unari:[6,12],unary_ufunc:[0,3,12],unarysquar:[6,12],underli:[1,6],uniniti:5,unit:[5,10],univers:12,update_al:5,usag:[1,6],use:[0,1,6,9,10,12],used:[1,4,6,8],user:[2,5],uses:8,using:[0,1,5,6,7,9,10,11],v_contigu:5,valid:[1,2,6],valu:[4,7,8,11,12],variabl:7,varieti:10,varrai:5,vector:5,view:5,wai:10,well:[2,8,10],where:5,whether:4,which:[5,10,11],work:5,wrapper:8,writeabl:5,you:[10,11],zero:[5,7,10,11]},titles:["Welcome to the documentation of the Boost.Python NumPy extension!","binary_ufunc","dtype","Boost.Python NumPy extension Reference","multi_iter","ndarray","unary_ufunc","How to use dtypes","How to access data using raw pointers","Boost.Python NumPy extension Tutorial","Creating ndarrays","A simple tutorial on Arrays","Ufuncs"],titleterms:{access:8,accessor:[1,2,4,5,6],arrai:11,binary_ufunc:1,boost:[0,3,9],constructor:[1,2,4,5,6],content:[1,2,4,5,6],creat:10,data:8,document:0,dtype:[2,7],exampl:[1,2,5,6],extens:[0,3,9],how:[7,8],multi_it:4,ndarrai:[5,10],numpi:[0,3,9],pointer:8,python:[0,3,9],raw:8,refer:3,simpl:11,synopsi:[1,2,4,5,6],tabl:[1,2,4,5,6],tutori:[9,11],ufunc:12,unary_ufunc:6,use:7,using:8,welcom:0}}) \ No newline at end of file diff --git a/doc/develop/html/numpy/tutorial/dtype.html b/doc/develop/html/numpy/tutorial/dtype.html new file mode 100644 index 00000000..bdf2c7be --- /dev/null +++ b/doc/develop/html/numpy/tutorial/dtype.html @@ -0,0 +1,133 @@ + + + + + + + + How to use dtypes - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

How to use dtypes

+

Here is a brief tutorial to show how to create ndarrays with built-in python data types, and extract the types and values of member variables

+

Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:

+
#include <boost/python/numpy.hpp>
+#include <iostream>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+int main(int argc, char **argv)
+{
+  Py_Initialize();
+  np::initialize();
+
+
+

Next, we create the shape and dtype. We use the get_builtin method to get the numpy dtype corresponding to the builtin C++ dtype +Here, we will create a 3x3 array passing a tuple with (3,3) for the size, and double as the data type

+
p::tuple shape = p::make_tuple(3, 3);
+np::dtype dtype = np::dtype::get_builtin<double>();
+np::ndarray a = np::zeros(shape, dtype);
+
+
+

Finally, we can print the array using the extract method in the python namespace. +Here, we first convert the variable into a string, and then extract it as a C++ character array from the python string using the <char const * > template

+
std::cout << "Original array:\n" << p::extract<char const *>(p::str(a)) << std::endl;
+
+
+

We can also print the dtypes of the data members of the ndarray by using the get_dtype method for the ndarray

+
std::cout << "Datatype is:\n" << p::extract<char const *>(p::str(a.get_dtype())) << std::endl ;
+
+
+

We can also create custom dtypes and build ndarrays with the custom dtypes

+

We use the dtype constructor to create a custom dtype. This constructor takes a list as an argument.

+

The list should contain one or more tuples of the format (variable name, variable type)

+

So first create a tuple with a variable name and its dtype, double, to create a custom dtype

+
p::tuple for_custom_dtype = p::make_tuple("ha",dtype) ;
+
+
+

Next, create a list, and add this tuple to the list. Then use the list to create the custom dtype

+
p::list list_for_dtype ;
+list_for_dtype.append(for_custom_dtype) ;
+np::dtype custom_dtype = np::dtype(list_for_dtype) ;
+
+
+

We are now ready to create an ndarray with dimensions specified by *shape* and of custom dtpye

+
  np::ndarray new_array = np::zeros(shape,custom_dtype);
+}
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/tutorial/fromdata.html b/doc/develop/html/numpy/tutorial/fromdata.html new file mode 100644 index 00000000..fc436b10 --- /dev/null +++ b/doc/develop/html/numpy/tutorial/fromdata.html @@ -0,0 +1,136 @@ + + + + + + + + How to access data using raw pointers - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

How to access data using raw pointers

+

One of the advantages of the ndarray wrapper is that the same data can be used in both Python and C++ and changes can be made to reflect at both ends. +The from_data method makes this possible.

+

Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:

+
#include <boost/python/numpy.hpp>
+#include <iostream>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+int main(int argc, char **argv)
+{
+  Py_Initialize();
+  np::initialize();
+
+
+

Create an array in C++ , and pass the pointer to it to the from_data method to create an ndarray:

+
int arr[] = {1,2,3,4,5};
+np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin<int>(),
+                                     p::make_tuple(5),
+                                     p::make_tuple(sizeof(int)),
+                                     p::object());
+
+
+

Print the source C++ array, as well as the ndarray, to check if they are the same:

+
std::cout << "C++ array :" << std::endl;
+for (int j=0;j<4;j++)
+{
+  std::cout << arr[j] << ' ';
+}
+std::cout << std::endl
+          << "Python ndarray :" << p::extract<char const *>(p::str(py_array)) << std::endl;
+
+
+

Now, change an element in the Python ndarray, and check if the value changed correspondingly in the source C++ array:

+
py_array[1] = 5 ;
+std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl;
+for (int j = 0; j < 5; j++)
+{
+  std::cout << arr[j] << ' ';
+}
+
+
+

Next, change an element of the source C++ array and see if it is reflected in the Python ndarray:

+
  arr[2] = 8;
+  std::cout << std::endl
+            << "Is the change reflected in the Python ndarray ?" << std::endl
+            << p::extract<char const *>(p::str(py_array)) << std::endl;
+}
+
+
+

As we can see, the changes are reflected across the ends. This happens because the from_data method passes the C++ array by reference to create the ndarray, and thus uses the same locations for storing data.

+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/tutorial/index.html b/doc/develop/html/numpy/tutorial/index.html new file mode 100644 index 00000000..dd321e28 --- /dev/null +++ b/doc/develop/html/numpy/tutorial/index.html @@ -0,0 +1,91 @@ + + + + + + + + Boost.Python NumPy extension Tutorial - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + + + + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/tutorial/ndarray.html b/doc/develop/html/numpy/tutorial/ndarray.html new file mode 100644 index 00000000..b8d9c8eb --- /dev/null +++ b/doc/develop/html/numpy/tutorial/ndarray.html @@ -0,0 +1,179 @@ + + + + + + + + Creating ndarrays - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

Creating ndarrays

+

The Boost.Numpy library exposes quite a few methods to create ndarrays. ndarrays can be created in a variety of ways, include empty arrays and zero filled arrays. +ndarrays can also be created from arbitrary python sequences as well as from data and dtypes.

+

This tutorial will introduce you to some of the ways in which you can create ndarrays. The methods covered here include creating ndarrays from arbitrary Python sequences, as well as from C++ containers, using both unit and non-unit strides

+

First, as before, initialise the necessary namepaces and runtimes

+
#include <boost/python/numpy.hpp>
+#include <iostream>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+int main(int argc, char **argv)
+{
+  Py_Initialize();
+  np::initialize();
+
+
+

Let’s now create an ndarray from a simple tuple. We first create a tuple object, and then pass it to the array method, to generate the necessary tuple

+
p::object tu = p::make_tuple('a','b','c');
+np::ndarray example_tuple = np::array(tu);
+
+
+

Let’s now try the same with a list. We create an empty list, add an element using the append method, and as before, call the array method

+
p::list l;
+l.append('a');
+np::ndarray example_list = np::array (l);
+
+
+

Optionally, we can also specify a dtype for the array

+
np::dtype dt = np::dtype::get_builtin<int>();
+np::ndarray example_list1 = np::array (l,dt);
+
+
+

We can also create an array by supplying data arrays and a few other parameters.

+

First,create an integer array

+
int data[] = {1,2,3,4,5};
+
+
+

Create a shape, and strides, needed by the function

+
p::tuple shape = p::make_tuple(5);
+p::tuple stride = p::make_tuple(sizeof(int));
+
+
+

Here, shape is (4,) , and the stride is sizeof(int)`. +A stride is the number of bytes that must be traveled to get to the next desired element while constructing the ndarray.

+

The function also needs an owner, to keep track of the data array passed. Passing none is dangerous

+
p::object own;
+
+
+

The from_data function takes the data array, datatype,shape,stride and owner as arguments and returns an ndarray

+
np::ndarray data_ex1 = np::from_data(data,dt, shape,stride,own);
+
+
+

Now let’s print the ndarray we created

+
std::cout << "Single dimensional array ::" << std::endl
+          << p::extract<char const *>(p::str(data_ex)) << std::endl;
+
+
+

Let’s make it a little more interesting. Lets make an 3x2 ndarray from a multi-dimensional array using non-unit strides

+

First lets create a 3x4 array of 8-bit integers

+
uint8_t mul_data[][4] = {{1,2,3,4},{5,6,7,8},{1,3,5,7}};
+
+
+

Now let’s create an array of 3x2 elements, picking the first and third elements from each row . For that, the shape will be 3x2. +The strides will be 4x2 i.e. 4 bytes to go to the next desired row, and 2 bytes to go to the next desired column

+
shape = p::make_tuple(3,2);
+stride = p::make_tuple(sizeof(uint8_t)*2,sizeof(uint8_t));
+
+
+

Get the numpy dtype for the built-in 8-bit integer data type

+
np::dtype dt1 = np::dtype::get_builtin<uint8_t>();
+
+
+

Now lets first create and print out the ndarray as is. +Notice how we can pass the shape and strides in the function directly, as well as the owner. The last part can be done because we don’t have any use to +manipulate the “owner” object

+
np::ndarray mul_data_ex = np::from_data(mul_data, dt1,
+                                        p::make_tuple(3,4),
+                                        p::make_tuple(4,1),
+                                        p::object());
+std::cout << "Original multi dimensional array :: " << std::endl
+          << p::extract<char const *>(p::str(mul_data_ex)) << std::endl;
+
+
+

Now create the new ndarray using the shape and strides and print out the array we created using non-unit strides

+
  mul_data_ex = np::from_data(mul_data, dt1, shape, stride, p::object());
+  std::cout << "Selective multidimensional array :: "<<std::endl
+            << p::extract<char const *>(p::str(mul_data_ex)) << std::endl ;
+}
+
+
+
+

Note

+

The from_data method will throw error_already_set if the number of elements dictated by the shape and the corresponding strides don’t match.

+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/tutorial/simple.html b/doc/develop/html/numpy/tutorial/simple.html new file mode 100644 index 00000000..57437aaa --- /dev/null +++ b/doc/develop/html/numpy/tutorial/simple.html @@ -0,0 +1,121 @@ + + + + + + + + A simple tutorial on Arrays - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

A simple tutorial on Arrays

+

Let’s start with a simple tutorial to create and modify arrays.

+

Get the necessary headers for numpy components and set up necessary namespaces:

+
#include <boost/python/numpy.hpp>
+#include <iostream>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+
+

Initialise the Python runtime, and the numpy module. Failure to call these results in segmentation errors:

+
int main(int argc, char **argv)
+{
+  Py_Initialize();
+  np::initialize();
+
+
+

Zero filled n-dimensional arrays can be created using the shape and data-type of the array as a parameter. Here, the shape is 3x3 and the datatype is the built-in float type:

+
p::tuple shape = p::make_tuple(3, 3);
+np::dtype dtype = np::dtype::get_builtin<float>();
+np::ndarray a = np::zeros(shape, dtype);
+
+
+

You can also create an empty array like this

+
np::ndarray b = np::empty(shape,dtype);
+
+
+

Print the original and reshaped array. The array a which is a list is first converted to a string, and each value in the list is extracted using extract< >:

+
  std::cout << "Original array:\n" << p::extract<char const *>(p::str(a)) << std::endl;
+
+  // Reshape the array into a 1D array
+  a = a.reshape(p::make_tuple(9));
+  // Print it again.
+  std::cout << "Reshaped array:\n" << p::extract<char const *>(p::str(a)) << std::endl;
+}
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/numpy/tutorial/ufunc.html b/doc/develop/html/numpy/tutorial/ufunc.html new file mode 100644 index 00000000..1b7f50ff --- /dev/null +++ b/doc/develop/html/numpy/tutorial/ufunc.html @@ -0,0 +1,199 @@ + + + + + + + + Ufuncs - Boost.Python NumPy extension 1.0 documentation + + + + + + + + + + + + + + + +
+ + + + + + + +
+

C++ Boost

+
+

(NumPy)

+ +
+ + +
+
+
+
+ + +
+

Ufuncs

+

Ufuncs or universal functions operate on ndarrays element by element, and support array broadcasting, type casting, and other features.

+

Lets try and see how we can use the binary and unary ufunc methods

+

After the neccessary includes

+
#include <boost/python/numpy.hpp>
+#include <iostream>
+
+namespace p = boost::python;
+namespace np = boost::python::numpy;
+
+
+

Now we create the structs necessary to implement the ufuncs. The typedefs must be made as the ufunc generators take these typedefs as inputs and return an error otherwise

+
struct UnarySquare
+{
+  typedef double argument_type;
+  typedef double result_type;
+
+  double operator()(double r) const { return r * r;}
+};
+
+struct BinarySquare
+{
+  typedef double first_argument_type;
+  typedef double second_argument_type;
+  typedef double result_type;
+
+  double operator()(double a,double b) const { return (a*a + b*b) ; }
+};
+
+
+

Initialise the Python runtime and the numpy module

+
int main(int argc, char **argv)
+{
+  Py_Initialize();
+  np::initialize();
+
+
+

Now expose the struct UnarySquare to Python as a class, and let ud be the class object.

+
p::object ud = p::class_<UnarySquare, boost::shared_ptr<UnarySquare> >("UnarySquare");
+ud.def("__call__", np::unary_ufunc<UnarySquare>::make());
+
+
+

Let inst be an instance of the class ud

+
p::object inst = ud();
+
+
+

Use the “__call__” method to call the overloaded () operator and print the value

+
std::cout << "Square of unary scalar 1.0 is " << p::extract<char const *>(p::str(inst.attr("__call__")(1.0))) << std::endl;
+
+
+

Create an array in C++

+
int arr[] = {1,2,3,4} ;
+
+
+

..and use it to create the ndarray in Python

+
np::ndarray demo_array = np::from_data(arr, np::dtype::get_builtin<int>(),
+                                       p::make_tuple(4),
+                                       p::make_tuple(4),
+                                       p::object());
+
+
+

Print out the demo array

+
std::cout << "Demo array is " << p::extract<char const *>(p::str(demo_array)) << std::endl;
+
+
+

Call the “__call__” method to perform the operation and assign the value to result_array

+
p::object result_array = inst.attr("__call__")(demo_array);
+
+
+

Print the resultant array

+
std::cout << "Square of demo array is " << p::extract<char const *>(p::str(result_array)) << std::endl;
+
+
+

Lets try the same with a list

+
p::list li;
+li.append(3);
+li.append(7);
+
+
+

Print out the demo list

+
std::cout << "Demo list is " << p::extract<char const *>(p::str(li)) << std::endl;
+
+
+

Call the ufunc for the list

+
result_array = inst.attr("__call__")(li);
+
+
+

And print the list out

+
std::cout << "Square of demo list is " << p::extract<char const *>(p::str(result_array)) << std::endl;
+
+
+

Now lets try Binary ufuncs. Again, expose the struct BinarySquare to Python as a class, and let ud be the class object

+
ud = p::class_<BinarySquare, boost::shared_ptr<BinarySquare> >("BinarySquare");
+ud.def("__call__", np::binary_ufunc<BinarySquare>::make());
+
+
+

And initialise ud

+
inst = ud();
+
+
+

Print the two input lists

+
std::cout << "The two input list for binary ufunc are " << std::endl
+          << p::extract<char const *>(p::str(demo_array)) << std::endl
+          << p::extract<char const *>(p::str(demo_array)) << std::endl;
+
+
+

Call the binary ufunc taking demo_array as both inputs

+
result_array = inst.attr("__call__")(demo_array,demo_array);
+
+
+

And print the output

+
  std::cout << "Square of list with binary ufunc is " << p::extract<char const *>(p::str(result_array)) << std::endl;
+}
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/doc/develop/html/reference/HTML.manifest b/doc/develop/html/reference/HTML.manifest new file mode 100644 index 00000000..4a0a14f7 --- /dev/null +++ b/doc/develop/html/reference/HTML.manifest @@ -0,0 +1,58 @@ +index.html +concepts.html +concepts/dereferenceable.html +concepts/extractor.html +concepts/holdergenerator.html +concepts/resultconverter.html +concepts/objectwrapper.html +high_level_components.html +high_level_components/boost_python_def_hpp.html +high_level_components/boost_python_def_visitor_hpp.html +high_level_components/boost_python_docstring_options_h.html +high_level_components/boost_python_enum_hpp.html +high_level_components/boost_python_errors_hpp.html +high_level_components/boost_python_exception_translato.html +high_level_components/boost_python_init_hpp.html +high_level_components/boost_python_iterator_hpp.html +high_level_components/boost_python_module_hpp.html +high_level_components/boost_python_operators_hpp.html +high_level_components/boost_python_scope_hpp.html +high_level_components/boost_python_stl_iterator_hpp.html +high_level_components/boost_python_wrapper_hpp.html +object_wrappers.html +object_wrappers/boost_python_list_hpp.html +object_wrappers/boost_python_long_hpp.html +object_wrappers/boost_python_object_hpp.html +object_wrappers/boost_python_str_hpp.html +object_wrappers/boost_python_slice_hpp.html +object_wrappers/boost_python_tuple_hpp.html +function_invocation_and_creation.html +function_invocation_and_creation/boost_python_call_hpp.html +function_invocation_and_creation/boost_python_call_method_hpp.html +function_invocation_and_creation/boost_python_data_members_hpp.html +function_invocation_and_creation/boost_python_make_function_hpp.html +function_invocation_and_creation/boost_python_overloads_hpp.html +function_invocation_and_creation/boost_python_ptr_hpp.html +function_invocation_and_creation/boost_python_raw_function_hpp.html +function_invocation_and_creation/function_documentation.html +function_invocation_and_creation/models_of_callpolicies.html +function_invocation_and_creation/models_of_resultconverter.html +function_invocation_and_creation/models_of_resultconvertergenerat.html +to_from_python_type_conversion.html +to_from_python_type_conversion/boost_python_implicit_hpp.html +to_from_python_type_conversion/boost_python_lvalue_from_pytype_.html +to_from_python_type_conversion/boost_python_opaque_pointer_conv.html +to_from_python_type_conversion/boost_python_to_python_converter.html +to_from_python_type_conversion/boost_python_register_ptr_to_pyt.html +embedding.html +embedding/boost_python_import_hpp.html +utility_and_infrastructure.html +utility_and_infrastructure/boost_python_instance_holder_hpp.html +utility_and_infrastructure/boost_python_pointee_hpp.html +utility_and_infrastructure/boost_python_handle_hpp.html +utility_and_infrastructure/boost_python_type_id_hpp.html +utility_and_infrastructure/boost_python_ssize_t_hpp.html +topics.html +topics/pickle_support.html +topics/indexing_support.html +glossary.html diff --git a/doc/develop/html/reference/concepts.html b/doc/develop/html/reference/concepts.html new file mode 100644 index 00000000..7a040431 --- /dev/null +++ b/doc/develop/html/reference/concepts.html @@ -0,0 +1,261 @@ + + + +Chapter 1. Concepts + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 1. Concepts

+ +
+ + +
+ +

+ Models of the CallPolicies concept are used to specialize the behavior + of Python callable objects generated by Boost.Python to wrapped C++ objects + like function and member function pointers, providing three behaviors: +

+
    +
  1. + precall - Python argument + tuple management before the wrapped object is invoked +
  2. +
  3. + result_converter - + C++ return value handling +
  4. +
  5. + postcall - Python argument + tuple and result management after the wrapped object is invoked +
  6. +
  7. + extract_return_type + - metafunction for extracting the return type from a given signature + type sequence +
  8. +
+
+
+ +

+ In order to allow the use of multiple models of CallPolicies in the same + callable object, Boost.Python's CallPolicies class templates provide a + chaining interface which allows them to be recursively composed. This interface + takes the form of an optional template parameter, Base, + which defaults to default_call_policies. + By convention, the precall + function of the Base is + invoked after the precall + function supplied by the outer + template, and the postcall + function of the Base is + invoked before the postcall + function of the outer template. + If a result_converter is + supplied by the outer template, + it replaces any result_converter + supplied by the Base. For + an example, see return_internal_reference. +

+
+
+ +
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Expression +

+
+

+ Type +

+
+

+ Result/Semantics +

+
+

+ x.precall(a) +

+
+

+ convertible to bool +

+
+

+ returns false and + PyErr_Occurred() != + 0 upon failure, true otherwise. +

+
+

+ P::result_converter +

+
+

+ A model of ResultConverterGenerator. +

+
+

+ An MPL unary Metafunction Class used produce the "preliminary" + result object. +

+
+

+ x.postcall(a, + r) +

+
+

+ convertible to PyObject* +

+
+

+ 0 and PyErr_Occurred() + != 0 + upon failure. Must "conserve references" even in the + event of an exception. In other words, if r + is not returned, its reference count must be decremented; if + another existing object is returned, its reference count must + be incremented. +

+
+

+ P::extract_return_type +

+
+

+ A model of Metafunction. +

+
+

+ An MPL unary Metafunction used extract the return type from a + given signature. By default it is derived from mpl::front. +

+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/concepts/dereferenceable.html b/doc/develop/html/reference/concepts/dereferenceable.html new file mode 100644 index 00000000..13ebaea6 --- /dev/null +++ b/doc/develop/html/reference/concepts/dereferenceable.html @@ -0,0 +1,104 @@ + + + +Dereferenceable + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Instances of a Dereferenceable + type can be used like a pointer to access an lvalue. +

+
+
+ +

+ In the table below, T is + a model of Dereferenceable, and x + denotes an object of type T. + In addition, all pointers are Dereferenceable. +

+
+++++ + + + + + + + + + + +
+

+ Expression +

+
+

+ Result +

+
+

+ Operational Semantics +

+
+

+ get_pointer(x) +

+
+

+ convertible to pointee<T>::type* +

+
+

+ &*x, + or a null pointer +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/concepts/extractor.html b/doc/develop/html/reference/concepts/extractor.html new file mode 100644 index 00000000..a8de1b6a --- /dev/null +++ b/doc/develop/html/reference/concepts/extractor.html @@ -0,0 +1,135 @@ + + + +Extractor + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ An Extractor is a class which Boost.Python can use to extract C++ objects + from Python objects, and is typically used by facilities that define from_python conversions for "traditional" + Python extension types. +

+
+
+ +

+ In the table below, X denotes + a model of Extractor and + a denotes an instance of + a Python object type. +

+
+++++ + + + + + + + + + + + + + + + + + +
+

+ Expression +

+
+

+ Type +

+
+

+ Semantics +

+
+

+ X::execute(a) +

+
+

+ non-void +

+
+

+ Returns the C++ object being extracted. The execute function + must not be overloaded. +

+
+

+ &a.ob_type +

+
+

+ PyTypeObject** +

+
+

+ Points to the ob_type + field of an object which is layout-compatible with PyObject +

+
+
+
+

+Notes +

+

+ Informally, an Extractor's execute member must be a non-overloaded static + function whose single argument is a Python object type. Acceptable Python + object types include those publicly (and unambiguously) derived from PyObject, + and POD types which are layout-compatible with PyObject. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/concepts/holdergenerator.html b/doc/develop/html/reference/concepts/holdergenerator.html new file mode 100644 index 00000000..97ae0544 --- /dev/null +++ b/doc/develop/html/reference/concepts/holdergenerator.html @@ -0,0 +1,92 @@ + + + +HolderGenerator + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ A HolderGenerator is a unary metafunction class which returns types suitable + for holding instances of its argument in a wrapped C++ class instance. +

+
+
+ +

+ In the table below, G denotes + an type which models HolderGenerator, + and X denotes a class type. +

+
++++ + + + + + + + + +
+

+ Expression +

+
+

+ Requirements +

+
+

+ G::apply<X>::type +

+
+

+ A concrete subclass of instance_holder + which can hold objects of type X. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/concepts/objectwrapper.html b/doc/develop/html/reference/concepts/objectwrapper.html new file mode 100644 index 00000000..c606dd68 --- /dev/null +++ b/doc/develop/html/reference/concepts/objectwrapper.html @@ -0,0 +1,132 @@ + + + +ObjectWrapper + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ This page defines two concepts used to describe classes which manage a + Python objects, and which are intended to support usage with a Python-like + syntax. +

+
+
+ +

+ Models of the ObjectWrapper concept have object + as a publicly-accessible base class, and are used to supply special construction + behavior and/or additional convenient functionality through (often templated) + member functions. Except when the return type R is itself an TypeWrapper, + a member function invocation of the form +

+
x.some_function(a1, a2,...an)
+

+ always has semantics equivalent to: +

+
extract<R>(x.attr("some_function")(object(a1), object(a2),...object(an)))()
+

+ (see caveat below). +

+
+
+ +

+ TypeWrapper is a refinement of ObjectWrapper + which is associated with a particular Python type X. + For a given TypeWrapper T, + a valid constructor expression +

+
T(a1, a2,...an)
+

+ builds a new T object managing the result of invoking X with arguments + corresponding to +

+
object(a1), object(a2),...object(an)
+

+ . When used as arguments to wrapped C++ functions, or as the template parameter + to extract<>, + only instances of the associated Python type will be considered a match. +

+
+
+

+Caveat +

+

+ The upshot of the special member function invocation rules when the return + type is a TypeWrapper is that it is possible for the returned object to + manage a Python object of an inappropriate type. This is not usually a + serious problem; the worst-case result is that errors will be detected + at runtime a little later than they might otherwise be. For an example + of how this can occur, note that the dict + member function items returns + an object of type list. + Now suppose the user defines this dict + subclass in Python: +

+
>>> class mydict(dict):
+...     def items(self):
+...         return tuple(dict.items(self)) # return a tuple
+
+

+ Since an instance of mydict + is also an instance of dict, + when used as an argument to a wrapped C++ function, boost::python::dict + can accept objects of Python type mydict. + Invoking items() + on this object can result in an instance of boost::python::list + which actually holds a Python tuple. + Subsequent attempts to use list + methods (e.g. append, or + any other mutating operation) on this object will raise the same exception + that would occur if you tried to do it from Python. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/concepts/resultconverter.html b/doc/develop/html/reference/concepts/resultconverter.html new file mode 100644 index 00000000..049e49b8 --- /dev/null +++ b/doc/develop/html/reference/concepts/resultconverter.html @@ -0,0 +1,210 @@ + + + +ResultConverter + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ A ResultConverter for a type T + is a type whose instances can be used to convert C++ return values of type + T to_python. + A ResultConverterGenerator is an MPL unary metafunction class which, given + the return type of a C++ function, returns a ResultConverter for that type. + ResultConverters in Boost.Python generally inspect library's registry of + converters to find a suitable converter, but converters which don't use + the registry are also possible. +

+
+
+ +

+ In the table below, C denotes + a ResultConverter type for a type R, + c denotes an object of + type C, and r denotes an object of type R. +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Expression +

+
+

+ Type +

+
+

+ Semantics +

+
+

+ C c +

+
+ +

+ Constructs a c + object. +

+
+

+ c.convertible() +

+
+

+ convertible to bool +

+
+

+ false iff no conversion + from any R value + to a Python object is possible. +

+
+

+ c(r) +

+
+

+ convertible to PyObject* +

+
+

+ A pointer to a Python object corresponding to r, + or 0 iff r could not be converted to_python, in which case PyErr_Occurred should return + non-zero. +

+
+

+ c.get_pytype() +

+
+

+ PyTypeObject const * +

+
+

+ A pointer to a Python Type object corresponding to result of + the conversion, or 0. + Used for documentation generation. If 0 + is returned the generated type in the documentation will be object. +

+
+
+
+ +

+ In the table below, G denotes + a ResultConverterGenerator type and R + denotes a possible C++ function return type. +

+
++++ + + + + + + + + +
+

+ Expression +

+
+

+ Requirements +

+
+

+ G::apply<R>::type +

+
+

+ A ResultConverter type for R. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/embedding.html b/doc/develop/html/reference/embedding.html new file mode 100644 index 00000000..e4088c7d --- /dev/null +++ b/doc/develop/html/reference/embedding.html @@ -0,0 +1,205 @@ + + + +Chapter 6. Embedding + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 6. Embedding

+ +
+ + +
+ +

+ Exposes a mechanism for embedding the python interpreter into C++ code. +

+
+
+ +
object eval(str expression,
+            object globals = object(),
+            object locals = object());
+
+
+

+
+
Effects
+

+ Evaluate Python expression from expression in the context specified + by the dictionaries globals and locals. +

+
Returns
+

+ An instance of object which holds the value of the expression. +

+
+
+
+
+ +
object exec(str code,
+            object globals = object(),
+            object locals = object());
+
+
+

+
+
Effects
+

+ Execute Python source code from code in the context specified by + the dictionaries globals and locals. +

+
Returns
+

+ An instance of object which holds the result of executing the code. +

+
+
+
+
+ +
object exec_file(str filename,
+                 object globals = object(),
+                 object locals = object());
+
+
+

+
+
Effects
+

+ Execute Python source code from the file named by filename in the + context specified by the dictionaries globals and locals. +

+
Returns
+

+ An instance of object which holds the result of executing the code. +

+
+
+
+
+ +

+ The following example demonstrates the use of import and exec to define + a function in python, and later call it from within C++. +

+
#include <iostream>
+#include <string>
+
+using namespace boost::python;
+
+void greet()
+{
+  // Retrieve the main module.
+  object main = import("__main__");
+
+  // Retrieve the main module's namespace
+  object global(main.attr("__dict__"));
+
+  // Define greet function in Python.
+  object result = exec(
+    "def greet():                   \n"
+    "   return 'Hello from Python!' \n",
+    global, global);
+
+  // Create a reference to it.
+  object greet = global["greet"];
+
+  // Call it.
+  std::string message = extract<std::string>(greet());
+  std::cout << message << std::endl;
+}
+
+

+ Instead of embedding the python script into a string, we could also store + it in an a file... +

+
def greet():
+   return 'Hello from Python!'
+
+

+ ... and execute that instead. +

+
  // ...
+  // Load the greet function from a file.
+  object result = exec_file(script, global, global);
+  // ...
+}
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/embedding/boost_python_import_hpp.html b/doc/develop/html/reference/embedding/boost_python_import_hpp.html new file mode 100644 index 00000000..a0933199 --- /dev/null +++ b/doc/develop/html/reference/embedding/boost_python_import_hpp.html @@ -0,0 +1,94 @@ + + + +boost/python/import.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Exposes a mechanism for importing python modules. +

+
+
+ +
object import(str name);
+
+

+
+
Effects
+

+ Imports the module named by name. +

+
Returns
+

+ An instance of object which holds a reference to the imported module. +

+
+
+
+
+ +

+ The following example demonstrates the use of import to access a function + in python, and later call it from within C++. +

+
#include <iostream>
+#include <string>
+
+using namespace boost::python;
+
+void print_python_version()
+{
+  // Load the sys module.
+  object sys = import("sys");
+
+  // Extract the python version.
+  std::string version = extract<std::string>(sys.attr("version"));
+  std::cout << version << std::endl;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation.html b/doc/develop/html/reference/function_invocation_and_creation.html new file mode 100644 index 00000000..3d2e6f28 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation.html @@ -0,0 +1,287 @@ + + + +Chapter 4. Function Invocation and Creation + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 4. Function Invocation and Creation

+
+

Table of Contents

+
+
boost/python/args.hpp
+
+
Introduction
+
Class + arg
+
Class + arg constructor
+
Class + arg operator=
+
Keyword-expression + operator,
+
Example
+
+
boost/python/call.hpp
+
+
Introduction
+
Function + call
+
Example
+
+
boost/python/call_method.hpp
+
+
Introduction
+
Function + call_method
+
Example
+
+
boost/python/data_members.hpp
+
+
Introduction
+
Functions
+
Example
+
+
boost/python/make_function.hpp
+
+
Introduction
+
Functions
+
Example
+
+
boost/python/overloads.hpp
+
+
Introduction
+
OverloadDispatcher + Concept
+
Macros
+
Example
+
+
boost/python/ptr.hpp
+
+
Introduction
+
Functions
+
Class + template pointer_wrapper
+
Class + template pointer_wrapper + types
+
Class + template pointer_wrapper + constructors and destructor
+
Class + template pointer_wrapper + observer functions
+
Metafunctions
+
Example
+
+
boost/python/raw_function.hpp
+
+
Introduction
+
Function + raw_function
+
Example
+
+
Function + documentation
+
+
boost/python/function_doc_signature.hpp
+
boost/python/pytype_function.hpp
+
+
Models + of CallPolicies
+
+
boost/python/default_call_policies.hpp
+
boost/python/return_arg.hpp
+
boost/python/return_internal_reference.hpp
+
boost/python/return_value_policy.hpp
+
boost/python/with_custodian_and_ward.hpp
+
+
Models + of ResultConverter
+
+
boost/python/to_python_indirect.hpp
+
boost/python/to_python_value.hpp
+
+
Models + of ResultConverterGenerator
+
+
boost/python/copy_const_reference.hpp
+
boost/python/copy_non_const_reference.hpp
+
boost/python/manage_new_object.hpp
+
boost/python/reference_existing_object.hpp
+
boost/python/return_by_value.hpp
+
boost/python/return_opaque_pointer.hpp
+
+
+
+
+ + +
+ + +

+ Supplies a family of overloaded functions for specifying argument keywords + for wrapped C++ functions. +

+
+ +

+ A keyword-expression results in an object which holds a sequence of + ntbses, and whose type encodes the number + of keywords specified. The keyword-expression may contain default values + for some or all of the keywords it holds +

+
+
+
+ +

+ The objects of class arg are keyword-expressions holding one keyword ( + size one ) +

+
namespace boost { namespace python
+{
+        struct arg
+        {
+          template <class T>
+                  arg &operator = (T const &value);
+          explicit arg (char const *name){elements[0].name = name;}
+        };
+
+}}
+
+
+
+ +
arg(char const* name);
+
+

+
+
Requires
+

+ The argument must be a ntbs. +

+
Effects
+

+ Constructs an arg object holding a keyword with name name. +

+
+
+
+
+ +
template <class T> arg &operator = (T const &value);
+
+

+
+
Requires
+

+ The argument must convertible to python. +

+
Effects
+

+ Assigns default value for the keyword. +

+
Returns
+

+ Reference to this. +

+
+
+
+
+ +
keyword-expression operator , (keyword-expression, const arg &kw) const
+keyword-expression operator , (keyword-expression, const char *name) const;
+
+
+

+
+
Requires
+

+ The argument name must be a ntbs. +

+
Effects
+

+ Extends the keyword-expression argument with one more keyword. +

+
Returns
+

+ The extended keyword-expression. +

+
+
+
+
+ +
#include <boost/python/def.hpp>
+using namespace boost::python;
+
+int f(double x, double y, double z=0.0, double w=1.0);
+
+BOOST_PYTHON_MODULE(xxx)
+{
+  def("f", f, (arg("x"), "y", arg("z")=0.0, arg("w")=1.0));
+}
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_call_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_call_hpp.html new file mode 100644 index 00000000..c5c198e0 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_call_hpp.html @@ -0,0 +1,96 @@ + + + +boost/python/call.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +
<boost/python/call.hpp> defines the call family of overloaded function templates, used to invoke Python callable objects from C++.
+
+
+
+ +
template <class R, class A1, class A2, ... class An>
+R call(PyObject* callable, A1 const&, A2 const&, ... An const&)
+
+
+

+
+
Requires
+

+ R is a pointer type, reference type, or a complete type with an accessible + copy constructor +

+
Effects
+

+ Invokes callable(a1, a2, ...an) in Python, where a1...an are the + arguments to call(), converted to Python objects. +

+
Returns
+

+ The result of the Python call, converted to the C++ type R. +

+
Rationale
+

+ For a complete semantic description and rationale, see this page. +

+
+
+
+
+ +

+ The following C++ function applies a Python callable object to its two + arguments and returns the result. If a Python exception is raised or the + result can't be converted to a double, an exception is thrown. +

+
double apply2(PyObject* func, double x, double y)
+{
+   return boost::python::call<double>(func, x, y);
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_call_method_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_call_method_hpp.html new file mode 100644 index 00000000..aab64dbd --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_call_method_hpp.html @@ -0,0 +1,156 @@ + + + +boost/python/call_method.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/call_method.hpp> defines the call_method family of + overloaded function templates, used to invoke callable attributes of Python + objects from C++. +

+
+
+ +
template <class R, class A1, class A2, ... class An>
+R call_method(PyObject* self, char const* method, A1 const&, A2 const&, ... An const&)
+
+
+

+
+
Requires
+

+ R is a pointer type, + reference type, or a complete type with an accessible copy constructor +

+
Effects
+

+ Invokes self.method(a1, a2, ...an) in Python, where a1...an + are the arguments to call_method(), converted to Python objects. For + a complete semantic description, see this page. +

+
Returns
+

+ The result of the Python call, converted to the C++ type R. +

+
Rationale
+

+ call_method is critical + to implementing C++ virtual functions which are overridable in Python, + as shown by the example below. +

+
+
+
+
+ +

+ The following C++ illustrates the use of call_method + in wrapping a class with a virtual function that can be overridden in Python: + C++ Module Definition +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/utility.hpp>
+#include <cstring>
+
+// class to be wrapped
+class Base
+{
+ public:
+   virtual char const* class_name() const { return "Base"; }
+   virtual ~Base();
+};
+
+bool is_base(Base* b)
+{
+   return !std::strcmp(b->class_name(), "Base");
+}
+
+// Wrapper code begins here
+using namespace boost::python;
+
+// Callback class
+class Base_callback : public Base
+{
+ public:
+   Base_callback(PyObject* self) : m_self(self) {}
+
+   char const* class_name() const { return call_method<char const*>(m_self, "class_name"); }
+   char const* Base_name() const { return Base::class_name(); }
+ private:
+   PyObject* const m_self;
+};
+
+using namespace boost::python;
+BOOST_PYTHON_MODULE(my_module)
+{
+    def("is_base", is_base);
+
+    class_<Base,Base_callback, noncopyable>("Base")
+        .def("class_name", &Base_callback::Base_name)
+        ;
+
+}
+
+

+ Python code: +

+
>>> from my_module import *
+>>> class Derived(Base):
+...    def __init__(self):
+...       Base.__init__(self)
+...    def class_name(self):
+...       return self.__class__.__name__
+...
+>>> is_base(Base()) # calls the class_name() method from C++
+1
+>>> is_base(Derived())
+0
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_data_members_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_data_members_hpp.html new file mode 100644 index 00000000..ec5d5077 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_data_members_hpp.html @@ -0,0 +1,215 @@ + + + +boost/python/data_members.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ make_getter() + and make_setter() + are the functions used internally by class_<>::def_readonly and class_<>::def_readwrite to produce Python + callable objects which wrap C++ data members. +

+
+
+ +
template <class C, class D>
+object make_getter(D C::*pm);
+
+template <class C, class D, class Policies>
+object make_getter(D C::*pm, Policies const& policies);
+
+
+

+
+
Requires
+

+ Policies is a model of CallPolicies. +

+
Effects
+

+ Creates a Python callable object which accepts a single argument + that can be converted from_python to C*, and returns the corresponding + member D member of the C object, converted to_python. If policies + is supplied, it will be applied to the function as described here. + Otherwise, the library attempts to determine whether D is a user-defined + class type, and if so uses return_internal_reference<> for + Policies. Note that this test may inappropriately choose return_internal_reference<> + in some cases when D is a smart pointer type. This is a known defect. +

+
Returns
+

+ An instance of object which holds the new Python callable object. +

+
+
+
template <class D>
+object make_getter(D const& d);
+template <class D, class Policies>
+object make_getter(D const& d, Policies const& policies);
+
+template <class D>
+object make_getter(D const* p);
+template <class D, class Policies>
+object make_getter(D const* p, Policies const& policies);
+
+
+

+
+
Requires
+

+ Policies is a model of CallPolicies. +

+
Effects
+

+ Creates a Python callable object which accepts no arguments and returns + d or *p, converted to_python on demand. If policies is supplied, + it will be applied to the function as described here. Otherwise, + the library attempts to determine whether D is a user-defined class + type, and if so uses reference_existing_object for Policies. +

+
Returns
+

+ An instance of object which holds the new Python callable object. +

+
+
+
template <class C, class D>
+object make_setter(D C::*pm);
+
+template <class C, class D, class Policies>
+object make_setter(D C::*pm, Policies const& policies);
+
+
+

+
+
Requires
+

+ Policies is a model of CallPolicies. +

+
Effects
+

+ Creates a Python callable object which, when called from Python, + expects two arguments which can be converted from_python to C* and + D const&, respectively, and sets the corresponding D member of + the C object. If policies is supplied, it will be applied to the + function as described here. +

+
Returns
+

+ An instance of object which holds the new Python callable object. +

+
+
+
template <class D>
+object make_setter(D& d);
+template <class D, class Policies>
+object make_setter(D& d, Policies const& policies);
+
+template <class D>
+object make_setter(D* p);
+template <class D, class Policies>
+object make_setter(D* p, Policies const& policies);
+
+
+

+
+
Requires
+

+ Policies is a model of CallPolicies. +

+
Effects
+

+ Creates a Python callable object which accepts one argument, which + is converted from Python to D const& and written into d or *p, + respectively. If policies is supplied, it will be applied to the + function as described here. +

+
Returns
+

+ An instance of object which holds the new Python callable object. +

+
+
+
+
+ +

+ The code below uses make_getter and make_setter to expose a data member + as functions: +

+
#include <boost/python/data_members.hpp>
+#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+
+struct X
+{
+    X(int x) : y(x) {}
+    int y;
+};
+
+using namespace boost::python;
+
+BOOST_PYTHON_MODULE_INIT(data_members_example)
+{
+    class_<X>("X", init<int>())
+       .def("get", make_getter(&X::y))
+       .def("set", make_setter(&X::y))
+       ;
+}
+
+

+ It can be used this way in Python: +

+
>>> from data_members_example import *
+>>> x = X(1)
+>>> x.get()
+1
+>>> x.set(2)
+>>> x.get()
+2
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_make_function_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_make_function_hpp.html new file mode 100644 index 00000000..91fc7ec1 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_make_function_hpp.html @@ -0,0 +1,194 @@ + + + +boost/python/make_function.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ make_function() and make_constructor() are the functions used internally + by def() and class_<>::def() to produce Python callable objects which + wrap C++ functions and member functions. +

+
+
+ +
template <class F>
+object make_function(F f)
+
+template <class F, class Policies>
+object make_function(F f, Policies const& policies)
+
+template <class F, class Policies, class KeywordsOrSignature>
+object make_function(F f, Policies const& policies, KeywordsOrSignature const& ks)
+
+template <class F, class Policies, class Keywords, class Signature>
+object make_function(F f, Policies const& policies, Keywords const& kw, Signature const& sig)
+
+
+

+
+
Requires
+

+ F is a function pointer or member function pointer type. If policies + are supplied, it must be a model of CallPolicies. If kewords are + supplied, it must be the result of a keyword-expression specifying + no more arguments than the arity of f. +

+
Effects
+
+

+ Creates a Python callable object which, when called from Python, + converts its arguments to C++ and calls f. If F is a pointer-to-member-function + type, the target object of the function call (*this) will be taken + from the first Python argument, and subsequent Python arguments will + be used as the arguments to f. +

+
    +
  • + If policies are supplied, it will be applied to the function + as described here. +
  • +
  • + If keywords are supplied, the keywords will be applied in order + to the final arguments of the resulting function. +
  • +
  • + If Signature is supplied, it should be an instance of an MPL + front-extensible sequence representing the function's return + type followed by its argument types. Pass a Signature when wrapping + function object types whose signatures can't be deduced, or when + you wish to override the types which will be passed to the wrapped + function. +
  • +
+
+
Returns
+

+ An instance of object which holds the new Python callable object. +

+
Caveats
+

+ An argument of pointer type may be 0 if None is passed from Python. + An argument type which is a constant reference may refer to a temporary + which was created from the Python object for just the duration of + the call to the wrapped function, for example a std::vector conjured + up by the conversion process from a Python list. Use a non-const + reference argument when a persistent lvalue is required. +

+
+
+
template <class F>
+object make_constructor(F f)
+
+template <class F, class Policies>
+object make_constructor(F f, Policies const& policies)
+
+template <class F, class Policies, class KeywordsOrSignature>
+object make_constructor(F f, Policies const& policies, KeywordsOrSignature const& ks)
+
+template <class F, class Policies, class Keywords, class Signature>
+object make_constructor(F f, Policies const& policies, Keywords const& kw, Signature const& sig)
+
+
+

+
+
Requires
+

+ F is a function pointer type. If policies are supplied, it must be + a model of CallPolicies. If kewords are supplied, it must be the + result of a keyword-expression specifying no more arguments than + the arity of f. +

+
Effects
+

+ Creates a Python callable object which, when called from Python, + converts its arguments to C++ and calls f. +

+
Returns
+

+ An instance of object which holds the new Python callable object. +

+
+
+
+
+ +

+ C++ function exposed below returns a callable object wrapping one of two + functions. +

+
#include <boost/python/make_function.hpp>
+#include <boost/python/module.hpp>
+
+char const* foo() { return "foo"; }
+char const* bar() { return "bar"; }
+
+using namespace boost::python;
+object choose_function(bool selector)
+{
+    if (selector)
+        return boost::python::make_function(foo);
+    else
+        return boost::python::make_function(bar);
+}
+
+BOOST_PYTHON_MODULE(make_function_test)
+{
+    def("choose_function", choose_function);
+}
+
+

+ It can be used this way in Python: +

+
>>> from make_function_test import *
+>>> f = choose_function(1)
+>>> g = choose_function(0)
+>>> f()
+'foo'
+>>> g()
+'bar'
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_overloads_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_overloads_hpp.html new file mode 100644 index 00000000..5c426b16 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_overloads_hpp.html @@ -0,0 +1,208 @@ + + + +boost/python/overloads.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ + +

+ Defines facilities for generating families of overloaded Python functions + and extension class methods from C++ functions and member functions with + default arguments, or from similar families of C++ overloads +

+
+ +

+ An overload-dispatch-expression is used to describe a family of overloaded + methods to be generated for an extension class. It has the following + properties: +

+
+

+
+
docstring
+

+ An ntbs whose value will bound to the + methods' __doc__ + attribute +

+
keywords
+

+ A keyword-expression + which will be used to name (a trailing subsequence of) the arguments + to the generated methods. +

+
call policies
+

+ An instance of some type which models CallPolicies. +

+
minimum arity
+

+ The minimum number of arguments to be accepted by a generated method + overload. +

+
maximum arity
+

+ The maximum number of arguments to be accepted by a generated method + overload. +

+
+
+
+
+
+ +

+ An OverloadDispatcher X is a class which has a minimum arity and a maximum + arity, and for which the following following are valid overload-dispatch-expressions, + with the same minimum and maximum arity as the OverloadDispatcher. +

+
X()
+X(docstring)
+X(docstring, keywords)
+X(keywords, docstring)
+X()[policies]
+X(docstring)[policies]
+X(docstring, keywords)[policies]
+X(keywords, docstring)[policies]
+
+

+ * If policies are supplied, it must be an instance of a type which models + CallPolicies, and will be + used as the result's call policies. Otherwise the result's call policies + will be an instance of default_call_policies. * If docstring + is supplied it must be an ntbs, and will be + used as the result's docstring. Otherwise the result has an empty docstring. + * If keywords is supplied it must be the result of a keyword-expression + whose length is no greater than X's maximum arity, and will be used as + the result's keywords. Otherwise the result's keywords will be empty. +

+
+
+

+Macros +

+
BOOST_PYTHON_FUNCTION_OVERLOADS(name, func_id, min_args, max_args)
+
+

+ Expands to the definition of an OverloadDispatcher called name in the current + scope which can be used to generate the following function invocation: +

+
func_id(a1, a2,...ai);
+

+ for all min_args <= + i <= + max_args. +

+
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(name, member_name, min_args, max_args)
+
+

+ Expands to the definition of an OverloadDispatcher called name in the current + scope which can be used to generate the following function invocation: +

+
x.member_name(a1, a2,...ai);
+

+ for all min_args <= i <= max_args, where x is a reference to an object + of class type. +

+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/overloads.hpp>
+#include <boost/python/return_internal_reference.hpp>
+
+using namespace boost::python;
+
+tuple f(int x = 1, double y = 4.25, char const* z = "wow")
+{
+    return make_tuple(x, y, z);
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3)
+
+struct Y {};
+struct X
+{
+    Y& f(int x, double y = 4.25, char const* z = "wow")
+    {
+        return inner;
+    }
+    Y inner;
+};
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(f_member_overloads, f, 1, 3)
+
+BOOST_PYTHON_MODULE(args_ext)
+{
+    def("f", f,
+        f_overloads(
+            args("x", "y", "z"), "This is f's docstring"
+        ));
+
+
+    class_<Y>("Y")
+        ;
+
+    class_<X>("X", "This is X's docstring")
+        .def("f1", &X::f,
+                f_member_overloads(
+                    args("x", "y", "z"), "f's docstring"
+                )[return_internal_reference<>()]
+        )
+        ;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_ptr_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_ptr_hpp.html new file mode 100644 index 00000000..4a4a606e --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_ptr_hpp.html @@ -0,0 +1,287 @@ + + + +boost/python/ptr.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/ptr.hpp> defines the ptr() function template, which + allows users to specify how to convert C++ pointer values to python in + the context of implementing overridable virtual functions, invoking Python + callable objects, or explicitly converting C++ objects to Python. Normally, + when passing pointers to Python callbacks, the pointee is copied to ensure + that the Python object never holds a dangling reference. To specify that + the new Python object should merely contain a copy of a pointer p, the + user can pass ptr(p) instead of passing p directly. This interface is meant + to mirror the use of boost::ref(), which can be similarly used to prevent + copying of referents. +

+

+ ptr(p) returns an instance of pointer_wrapper<>, + which can be detected using the is_pointer_wrapper<> + metafunction; unwrap_pointer<> + is a metafunction which extracts the original pointer type from a pointer_wrapper<>. + These classes can be thought of as implementation details. +

+
+
+ +
template <class T>
+pointer_wrapper<T> ptr(T x);
+
+
+

+
+
Requires
+

+ T is a pointer type. +

+
Returns
+

+ pointer_wrapper<T>(x) +

+
Throws
+

+ nothing. +

+
+
+
+
+ +

+ A "type envelope" which is returned by ptr(), used to indicate reference semantics + for pointers passed to Python callbacks. +

+
namespace boost { namespace python
+{
+    template<class Ptr> class pointer_wrapper
+    {
+     public:
+        typedef Ptr type;
+
+        explicit pointer_wrapper(Ptr x);
+        operator Ptr() const;
+        Ptr get() const;
+    };
+}}
+
+
+
+ +
typedef Ptr type;
+
+

+ The type of the pointer being wrapped. +

+
+
+ +
explicit pointer_wrapper(Ptr x);
+
+
+

+
+
Requires
+

+ Ptr is a pointer + type +

+
Effects
+

+ Stores x in a the + pointer_wrapper<>. +

+
Throws
+

+ nothing. +

+
+
+
+
+ +
operator Ptr() const;
+Ptr get() const;
+
+
+

+
+
Returns
+

+ a copy of the stored pointer. +

+
Rationale
+

+ pointer_wrapper is intended to be a stand-in for the actual pointer + type, but sometimes it's better to have an explicit way to retrieve + the pointer. +

+
+
+
+
+ + +
+ +

+ A unary metafunction whose value is true iff its argument is a pointer_wrapper<>. +

+
namespace boost { namespace python
+{
+    template<class T> class is_pointer_wrapper
+    {
+        static unspecified value = ...;
+    };
+}}
+
+
+

+
+
Returns
+

+ true iff T is a specialization of pointer_wrapper<>. + value is an integral constant convertible to bool of unspecified + type +

+
+
+
+
+ +

+ A unary metafunction which extracts the wrapped pointer type from a specialization + of pointer_wrapper<>. +

+
namespace boost { namespace python
+{
+    template<class T> class unwrap_pointer
+    {
+        typedef unspecified type;
+    };
+}}
+
+
+

+
+
Returns
+

+ T::type if T + is a specialization of pointer_wrapper<>, T + otherwise +

+
+
+
+
+
+ +

+ This example illustrates the use of ptr() to prevent an object from being + copied: +

+
#include <boost/python/call.hpp>
+#include <boost/python/ptr.hpp>
+
+class expensive_to_copy
+{
+   ...
+};
+
+void pass_as_arg(expensive_to_copy* x, PyObject* f)
+{
+   // call the Python function f, passing a Python object built around
+   // which refers to *x by-pointer.
+   //
+   // *** Note: ensuring that *x outlives the argument to f() is    ***
+   // *** up to the user! Failure to do so could result in a crash! ***
+
+   boost::python::call<void>(f, ptr(x));
+}
+...
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/boost_python_raw_function_hpp.html b/doc/develop/html/reference/function_invocation_and_creation/boost_python_raw_function_hpp.html new file mode 100644 index 00000000..96ade980 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/boost_python_raw_function_hpp.html @@ -0,0 +1,111 @@ + + + +boost/python/raw_function.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ raw_function(...) + is used to convert a function taking a tuple and a dict into a Python callable object + which accepts a variable number of arguments and arbitrary keyword arguments. +

+
+
+ +
template <class F>
+object raw_function(F f, std::size_t min_args = 0);
+
+
+

+
+
Requires
+

+ f(tuple(), dict()) is well-formed. +

+
Returns
+

+ a callable object which requires at least min_args arguments. When + called, the actual non-keyword arguments will be passed in a tuple + as the first argument to f, and the keyword arguments will be passed + in a dict as the second argument to f. +

+
+
+
+
+ +

+ C++: +

+
#include <boost/python/def.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/dict.hpp>
+#include <boost/python/module.hpp>
+#include <boost/python/raw_function.hpp>
+
+using namespace boost::python;
+
+tuple raw(tuple args, dict kw)
+{
+    return make_tuple(args, kw);
+}
+
+BOOST_PYTHON_MODULE(raw_test)
+{
+    def("raw", raw_function(raw));
+}
+
+

+ Python: +

+
>>> from raw_test import *
+
+>>> raw(3, 4, foo = 'bar', baz = 42)
+((3, 4), {'foo': 'bar', 'baz': 42})
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/function_documentation.html b/doc/develop/html/reference/function_invocation_and_creation/function_documentation.html new file mode 100644 index 00000000..6ec03322 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/function_documentation.html @@ -0,0 +1,458 @@ + + + +Function documentation + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ + +
+ +

+ Boost.Python supports docstrings with automatic appending of Pythonic + and C++ signatures. This feature is implemented by class function_doc_signature_generator. The + class uses all of the overloads, supplied arg names and default values, + as well as the user-defined docstrings, to generate documentation for + a given function. +

+
+
+ +

+ The class has only one public function which returns a list of strings + documenting the overloads of a function. +

+
namespace boost { namespace python { namespace objects {
+
+    class function_doc_signature_generator
+    {
+      public:
+          static list function_doc_signatures(function const *f);
+    };
+
+}}}
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/overloads.hpp>
+#include <boost/python/raw_function.hpp>
+
+using namespace boost::python;
+
+tuple f(int x = 1, double y = 4.25, char const* z = "wow")
+{
+    return make_tuple(x, y, z);
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3)
+
+
+struct X
+{
+    tuple f(int x = 1, double y = 4.25, char const* z = "wow")
+    {
+        return make_tuple(x, y, z);
+    }
+};
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3)
+
+tuple raw_func(tuple args, dict kw)
+{
+    return make_tuple(args, kw);
+}
+
+BOOST_PYTHON_MODULE(args_ext)
+{
+    def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow")
+        , "This is f's docstring"
+        );
+
+    def("raw", raw_function(raw_func));
+
+    def("f1", f, f_overloads("f1's docstring", args("x", "y", "z")));
+
+
+    class_<X>("X", "This is X's docstring", init<>(args("self")))
+        .def("f", &X::f
+             , "This is X.f's docstring"
+             , args("self","x", "y", "z"))
+
+        ;
+
+}
+
+

+ Python code: +

+
>>> import args_ext
+>>> help(args_ext)
+Help on module args_ext:
+
+NAME
+    args_ext
+
+FILE
+    args_ext.pyd
+
+CLASSES
+    Boost.Python.instance(__builtin__.object)
+        X
+
+    class X(Boost.Python.instance)
+     |  This is X's docstring
+     |
+     |  Method resolution order:
+     |      X
+     |      Boost.Python.instance
+     |      __builtin__.object
+     |
+     |  Methods defined here:
+     |
+     |  __init__(...)
+     |      __init__( (object)self) -> None :
+     |       C++ signature:
+     |           void __init__(struct _object *)
+     |
+     |  f(...)
+     |      f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring
+     |      C++ signature:
+     |          class boost::python::tuple f(struct X {lvalue},int,double,char const *)
+     |
+     |    .................
+     |
+FUNCTIONS
+    f(...)
+        f([ (int)x=1 [, (float)y=4.25 [, (str)z='wow']]]) -> tuple : This is f's docstring
+        C++ signature:
+            class boost::python::tuple f([ int=1 [,double=4.25 [,char const *='wow']]])
+
+    f1(...)
+        f1([ (int)x [, (float)y [, (str)z]]]) -> tuple : f1's docstring
+        C++ signature:
+            class boost::python::tuple f1([ int [,double [,char const *]]])
+
+    raw(...)
+        object raw(tuple args, dict kwds) :
+        C++ signature:
+            object raw(tuple args, dict kwds)
+
+
+
+
+ + +
+ +

+ To support Pythonic signatures the converters should supply a get_pytype function returning a pointer + to the associated PyTypeObject. + See for example ResultConverter or to_python_converter. The classes + in this header file are meant to be used when implmenting get_pytype. There are also _direct versions of the templates of + class T + which should be used with undecorated type parameter, expected to be + in the conversion registry when the module loads. +

+
+
+ +

+ This template generates a static get_pytype + member returning the template parameter. +

+
namespace boost { namespace python { namespace converter{
+
+    template < PyTypeObject const *pytype >
+    class wrap_pytype
+    {
+      public:
+          static PyTypeObject const *get_pytype(){return pytype; }
+    };
+
+}}}
+
+
+
+ +

+ This template should be used with template parameters which are (possibly + decorated) types exported to python using class_. The generated a static + get_pytype member returns + the corresponding python type. +

+
namespace boost { namespace python { namespace converter{
+
+    template < class T >
+    class registered_pytype
+    {
+      public:
+          static PyTypeObject const *get_pytype();
+    };
+
+}}}
+
+
+
+ +

+ This template generates a static get_pytype + member which inspects the registered from_python + converters for the type T + and returns a matching python type. +

+
namespace boost { namespace python { namespace converter{
+
+    template < class T >
+    class expected_from_python_type
+    {
+      public:
+          static PyTypeObject const *get_pytype();
+    };
+
+}}}
+
+
+
+ +

+ This template generates a static get_pytype + member returning the python type to which T + can be converted. +

+
namespace boost { namespace python { namespace converter{
+
+    template < class T >
+    class to_python_target_type
+    {
+      public:
+          static PyTypeObject const *get_pytype();
+    };
+
+}}}
+
+
+
+ +

+ This example presumes that someone has implemented the standard noddy + example module from the Python documentation, and placed the corresponding + declarations in "noddy.h". Because noddy_NoddyObject + is the ultimate trivial extension type, the example is a bit contrived: + it wraps a function for which all information is contained in the type + of its return value. +

+

+ C++ module definition: +

+
#include <boost/python/reference.hpp>
+#include <boost/python/module.hpp>
+#include "noddy.h"
+
+struct tag {};
+tag make_tag() { return tag(); }
+
+using namespace boost::python;
+
+struct tag_to_noddy
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported
+: wrap_pytype<&noddy_NoddyType> //inherits get_pytype from wrap_pytype
+#endif
+{
+    static PyObject* convert(tag const& x)
+    {
+        return PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
+    }
+};
+
+BOOST_PYTHON_MODULE(to_python_converter)
+{
+    def("make_tag", make_tag);
+    to_python_converter<tag, tag_to_noddy
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
+          , true
+#endif
+          >(); //"true" because tag_to_noddy has member get_pytype
+}
+
+

+ The following example registers to and from python converters using the + templates expected_from_python_type and to_pyhton_target_type. +

+
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/extract.hpp>
+#include <boost/python/to_python_converter.hpp>
+#include <boost/python/class.hpp>
+
+using namespace boost::python;
+
+struct A
+{
+};
+
+struct B
+{
+  A a;
+  B(const A& a_):a(a_){}
+};
+
+// Converter from A to python int
+struct BToPython
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported
+   : converter::to_python_target_type<A>  //inherits get_pytype
+#endif
+{
+  static PyObject* convert(const B& b)
+  {
+    return incref(object(b.a).ptr());
+  }
+};
+
+// Conversion from python int to A
+struct BFromPython
+{
+  BFromPython()
+  {
+    boost::python::converter::registry::push_back
+        ( &convertible
+        , &construct
+        , type_id< B >()
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
+        , &converter::expected_from_python_type<A>::get_pytype//convertible to A can be converted to B
+#endif
+        );
+  }
+
+  static void* convertible(PyObject* obj_ptr)
+  {
+      extract<const A&> ex(obj_ptr);
+      if (!ex.check()) return 0;
+      return obj_ptr;
+  }
+
+  static void construct(
+      PyObject* obj_ptr,
+      converter::rvalue_from_python_stage1_data* data)
+  {
+    void* storage = (
+        (converter::rvalue_from_python_storage< B >*)data)-> storage.bytes;
+
+    extract<const A&> ex(obj_ptr);
+    new (storage) B(ex());
+    data->convertible = storage;
+  }
+};
+
+
+B func(const B& b) { return b ; }
+
+BOOST_PYTHON_MODULE(pytype_function_ext)
+{
+  to_python_converter< B , BToPython
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
+             ,true
+#endif
+             >(); //has get_pytype
+  BFromPython();
+
+  class_<A>("A") ;
+
+  def("func", &func);
+
+}
+
+
+
+>>> from pytype_function_ext import *
+>>> print func.__doc__
+func( (A)arg1) -> A :
+    C++ signature:
+         struct B func(struct B)
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/models_of_callpolicies.html b/doc/develop/html/reference/function_invocation_and_creation/models_of_callpolicies.html new file mode 100644 index 00000000..696dd2c4 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/models_of_callpolicies.html @@ -0,0 +1,1098 @@ + + + +Models of CallPolicies + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ + +
+ +

+ default_call_policies + is a model of CallPolicies + with no precall or postcall behavior and a result_converter which handles by-value + returns. Wrapped C++ functions and member functions use + default_call_policies unless + otherwise specified. You may find it convenient to derive new models + of CallPolicies + from default_call_policies. +

+
namespace boost { namespace python
+{
+    struct default_call_policies
+    {
+        static bool precall(PyObject*);
+        static PyObject* postcall(PyObject*, PyObject* result);
+        typedef default_result_converter result_converter;
+        template <class Sig> struct extract_return_type : mpl::front<Sig>{};
+    };
+}}
+
+
+
+ +
bool precall(PyObject*);
+
+

+
+
Returns
+

+ true +

+
Throws
+

+ nothing +

+
+
+
PyObject* postcall(PyObject*, PyObject* result);
+
+

+
+
Returns
+

+ result +

+
Throws
+

+ nothing +

+
+
+
+
+ +

+ default_result_converter is a model of ResultConverterGenerator which + can be used to wrap C++ functions returning non-pointer types, char const*, and PyObject*, by-value. +

+
namespace boost { namespace python
+{
+    struct default_result_converter
+    {
+        template <class T> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Requires
+

+ T is not a reference type. If T is a pointer type, T is const char* + or PyObject*. +

+
Returns
+

+ typedef to_python_value<T const&> type; +

+
+
+
+
+ +

+ This example comes from the Boost.Python implementation itself. Because + the return_value_policy class template does not implement precall or + postcall behavior, its default base class is default_call_policies: +

+
template <class Handler, class Base = default_call_policies>
+struct return_value_policy : Base
+{
+   typedef Handler result_converter;
+};
+
+
+
+
+ + +
+ +

+ return_arg and return_self instantiations are models + of CallPolicies + which return the specified argument parameter (usually *this) + of a wrapped (member) function. +

+
+
+ +
++++++ + + + + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Description +

+
+

+ Default +

+
+

+ arg_pos +

+
+

+ A positive compile-time constant of type std::size_t. +

+
+

+ the position of the argument to be returned. +

+
+

+ 1 +

+
+

+ Base +

+
+

+ A model of CallPolicies +

+
+

+ Used for policy composition. Any result_converter + it supplies will be overridden by return_arg, + but its precall + and postcall + policies are composed as described here CallPolicies. +

+
+

+ default_call_policies +

+
+
namespace boost { namespace python
+{
+   template <size_t arg_pos=1, class Base = default_call_policies>
+   struct return_arg : Base
+   {
+      static PyObject* postcall(PyObject*, PyObject* result);
+      struct result_converter{ template <class T> struct apply; };
+      template <class Sig> struct extract_return_type : mpl::at_c<Sig, arg_pos>{};
+
+   };
+}}
+
+
+
+ +
PyObject* postcall(PyObject* args, PyObject* result);
+
+

+
+
Requires
+

+ PyTuple_Check(args) + != 0 + and PyTuple_Size(args) != 0 +

+
Returns
+

+ PyTuple_GetItem(args,arg_pos-1) +

+
+
+
+
+ +
namespace boost { namespace python
+{
+   template <class Base = default_call_policies>
+   struct return_self
+     : return_arg<1,Base>
+   {};
+}}
+
+
+
+ +

+ C++ module definition: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/return_arg.hpp>
+
+struct Widget
+{
+   Widget() :sensitive_(true){}
+   bool get_sensitive() const { return sensitive_; }
+   void set_sensitive(bool s) { this->sensitive_ = s; }
+ private:
+   bool sensitive_;
+};
+
+struct Label : Widget
+{
+   Label() {}
+
+   std::string  get_label() const { return label_; }
+   void set_label(const std::string &l){ label_ = l; }
+
+ private:
+   std::string label_;
+};
+
+using namespace boost::python;
+BOOST_PYTHON_MODULE(return_self_ext)
+{
+   class_<widget>("Widget")
+      .def("sensitive", &Widget::get_sensitive)
+      .def("sensitive", &Widget::set_sensitive, return_self<>())
+      ;
+
+   class_<Label, bases<Widget> >("Label")
+      .def("label", &Label::get_label)
+      .def("label", &Label::set_label, return_self<>())
+      ;
+}
+
+

+ Python code: +

+
>>> from return_self_ext import *
+>>> l1 = Label().label("foo").sensitive(false)
+>>> l2 = Label().sensitive(false).label("foo")
+
+
+
+
+ + +
+ +

+ return_internal_reference + instantiations are models of CallPolicies which allow pointers + and references to objects held internally by a free or member function + argument or from the target of a member function to be returned safely + without making a copy of the referent. The default for its first template + argument handles the common case where the containing object is the target + (*this) + of a wrapped member function. +

+
+
+ +
++++++ + + + + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Description +

+
+

+ Default +

+
+

+ owner_arg +

+
+

+ A positive compile-time constant of type std::size_t. +

+
+

+ The index of the parameter which contains the object to which + the reference or pointer is being returned. If used to wrap + a member function, parameter 1 is the target object (*this). + Note that if the target Python object type doesn't support + weak references, a Python TypeError exception will be raised + when the function being wrapped is called. +

+
+
+

+ Base +

+
+

+ A model of CallPolicies +

+
+

+ Used for policy composition. Any result_converter + it supplies will be overridden by return_internal_reference, + but its precall + and postcall + policies are composed as described here CallPolicies. +

+
+

+ default_call_policies +

+
+
namespace boost { namespace python
+{
+   template <std::size_t owner_arg = 1, class Base = default_call_policies>
+   struct return_internal_reference : Base
+   {
+      static PyObject* postcall(PyObject*, PyObject* result);
+      typedef reference_existing_object result_converter;
+   };
+}}
+
+
+
+ +
PyObject* postcall(PyObject* args, PyObject* result);
+
+

+
+
Requires
+

+ PyTuple_Check(args) + != 0 +

+
Returns
+

+ with_custodian_and_ward_postcall::postcall(args, result) +

+
+
+
+
+ +

+ C++ module definition: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/return_internal_reference.hpp>
+
+class Bar
+{
+ public:
+   Bar(int x) : x(x) {}
+   int get_x() const { return x; }
+   void set_x(int x) { this->x = x; }
+ private:
+   int x;
+};
+
+class Foo
+{
+ public:
+   Foo(int x) : b(x) {}
+
+   // Returns an internal reference
+   Bar const& get_bar() const { return b; }
+
+ private:
+   Bar b;
+};
+
+using namespace boost::python;
+BOOST_PYTHON_MODULE(internal_refs)
+{
+   class_<Bar>("Bar", init<int>())
+      .def("get_x", &Bar::get_x)
+      .def("set_x", &Bar::set_x)
+      ;
+
+   class_<Foo>("Foo", init<int>())
+      .def("get_bar", &Foo::get_bar
+          , return_internal_reference<>())
+      ;
+}
+
+

+ Python code: +

+
>>> from internal_refs import *
+>>> f = Foo(3)
+>>> b1 = f.get_bar()
+>>> b2 = f.get_bar()
+>>> b1.get_x()
+3
+>>> b2.get_x()
+3
+>>> b1.set_x(42)
+>>> b2.get_x()
+42
+
+
+
+
+ + +
+ +

+ return_value_policy instantiations are simply models of CallPolicies which are composed + of a ResultConverterGenerator and + optional Base CallPolicies. +

+
+
+ +
+++++ + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Default +

+
+

+ ResultConverterGenerator +

+
+

+ A model of ResultConverterGenerator +

+
+
+

+ Base +

+
+

+ A model of CallPolicies +

+
+

+ default_call_policies +

+
+
namespace boost { namespace python
+{
+  template <class ResultConverterGenerator, class Base = default_call_policies>
+  struct return_value_policy : Base
+  {
+      typedef ResultConverterGenerator result_converter;
+  };
+}}
+
+
+
+ +

+ C++ module definition: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/return_value_policy.hpp>
+
+// classes to wrap
+struct Bar { int x; }
+
+struct Foo {
+   Foo(int x) : { b.x = x; }
+   Bar const& get_bar() const { return b; }
+ private:
+   Bar b;
+};
+
+// Wrapper code
+using namespace boost::python;
+BOOST_PYTHON_MODULE(my_module)
+{
+   class_<Bar>("Bar");
+
+   class_<Foo>("Foo", init<int>())
+      .def("get_bar", &Foo::get_bar
+          , return_value_policy<copy_const_reference>())
+      ;
+}
+
+

+ Python code: +

+
>>> from my_module import *
+>>> f = Foo(3)         # create a Foo object
+>>> b = f.get_bar()    # make a copy of the internal Bar object
+
+
+
+
+ + +
+ +

+ This header provides facilities for establishing a lifetime dependency + between two of a function's Python argument or result objects. The ward + object will not be destroyed until after the custodian as long as the + custodian object supports weak + references (Boost.Python extension classes all support weak references). + If the custodian object does not support weak references and is not + None, an appropriate + exception will be thrown. The two class templates with_custodian_and_ward + and with_custodian_and_ward_postcall + differ in the point at which they take effect. +

+

+ In order to reduce the chance of inadvertently creating dangling pointers, + the default is to do lifetime binding before the underlying C++ object + is invoked. However, before invocation the result object is not available, + so with_custodian_and_ward_postcall + is provided to bind lifetimes after invocation. Also, if a C++ exception + is thrown after with_custodian_and_ward<>::precall + but before the underlying C++ object actually stores a pointer, the lifetime + of the custodian and ward objects will be artificially bound together, + so one might choose with_custodian_and_ward_postcall + instead, depending on the semantics of the function being wrapped. +

+

+ Please note that this is not the appropriate tool to use when wrapping + functions which transfer ownership of a raw pointer across the function-call + boundary. Please see the FAQ if you want to do that. +

+
+
+ +
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Description +

+
+

+ Default +

+
+

+ custodian +

+
+

+ A positive compile-time constant of type + std::size_t. +

+
+

+ The 1-based index of the parameter which is the dependency + in the lifetime relationship to be established. If used to + wrap a member function, parameter 1 is the target object (*this). + Note that if the target Python object type doesn't support + weak references, a Python TypeError exception will be raised + when the C++ object being wrapped is called. +

+
+
+

+ ward +

+
+

+ A positive compile-time constant of type std::size_t. +

+
+

+ The 1-based index of the parameter which is the dependent in + the lifetime relationship to be established. If used to wrap + a member function, parameter 1 is the target object (*this). +

+
+
+

+ Base +

+
+

+ A model of CallPolicies +

+
+

+ Used for policy composition. +

+
+

+ default_call_policies +

+
+
namespace boost { namespace python
+{
+   template <std::size_t custodian, std::size_t ward, class Base = default_call_policies>
+   struct with_custodian_and_ward : Base
+   {
+      static bool precall(PyObject* args);
+   };
+}}
+
+
+ +
bool precall(PyObject* args);
+
+

+
+
Requires
+

+ PyTuple_Check(args) + != 0 +

+
Effects
+

+ Makes the lifetime of the argument indicated by ward dependent + on the lifetime of the argument indicated by custodian. +

+
Returns
+

+ false and PyErr_Occurred() != 0 upon failure, true otherwise. +

+
+
+
+
+ +
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Description +

+
+

+ Default +

+
+

+ custodian +

+
+

+ A positive compile-time constant of type std::size_t. +

+
+

+ The index of the parameter which is the dependency in the lifetime + relationship to be established. Zero indicates the result object; + 1 indicates the first argument. If used to wrap a member function, + parameter 1 is the target object (*this). Note that if the target + Python object type doesn't support weak references, a Python + TypeError exception will be raised when the C++ object being + wrapped is called. +

+
+
+

+ ward +

+
+

+ A positive compile-time constant of type std::size_t. +

+
+

+ The index of the parameter which is the dependent in the lifetime + relationship to be established. Zero indicates the result object; + 1 indicates the first argument. If used to wrap a member function, + parameter 1 is the target object (*this). +

+
+
+

+ Base +

+
+

+ A model of CallPolicies +

+
+

+ Used for policy composition. +

+
+

+ default_call_policies +

+
+
namespace boost { namespace python
+{
+   template <std::size_t custodian, std::size_t ward, class Base = default_call_policies>
+   struct with_custodian_and_ward_postcall : Base
+   {
+      static PyObject* postcall(PyObject* args, PyObject* result);
+   };
+}}
+
+
+
+ +
PyObject *postcall(PyObject* args, PyObject* result);
+
+

+
+
Requires
+

+ PyTuple_Check(args) + != 0, + result != + 0 +

+
Effects
+

+ Makes the lifetime of the object indicated by ward dependent on + the lifetime of the object indicated by custodian. +

+
Returns
+

+ 0 and PyErr_Occurred() + != 0 + upon failure, true + otherwise. +

+
+
+
+
+ +

+ The following example shows how with_custodian_and_ward_postcall + is used by the library to implement return_internal_reference +

+
template <std::size_t owner_arg = 1, class Base = default_call_policies>
+struct return_internal_reference
+    : with_custodian_and_ward_postcall<0, owner_arg, Base>
+{
+   typedef reference_existing_object result_converter;
+};
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/models_of_resultconverter.html b/doc/develop/html/reference/function_invocation_and_creation/models_of_resultconverter.html new file mode 100644 index 00000000..0231afa7 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/models_of_resultconverter.html @@ -0,0 +1,308 @@ + + + +Models of ResultConverter + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ + +
+ + +
<boost/python/to_python_indirect.hpp> supplies a way to construct new Python objects that hold wrapped C++ class instances via a pointer or smart pointer.
+[endsect]
+
+
+ +

+ Class template to_python_indirect + converts objects of its first argument type to python as extension + class instances, using the ownership policy provided by its 2nd argument. +

+
+++++ + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Description +

+
+

+ T +

+
+

+ Either U cv& + (where cv is any optional cv-qualification) or a Dereferenceable + type such that *x is convertible to U const&, where U is a class type. +

+
+

+ A type deferencing + a C++ class exposed to Python using class template class_. +

+
+

+ MakeHolder +

+
+

+ h = + MakeHolder::execute(p); +

+
+

+ A class whose static execute() creates an instance_holder. +

+
+

+ Instantiations of to_python_indirect are models of ResultConverter. +

+
namespace boost { namespace python
+{
+  template <class T, class MakeHolder>
+  struct to_python_indirect
+  {
+     static bool convertible();
+     PyObject* operator()(T ptr_or_reference) const;
+   private:
+     static PyTypeObject* type();
+  };
+}}
+
+
+
+ +
PyObject* operator()(T x) const;
+
+

+
+
Requires
+

+ x refers to an + object (if it is a pointer type, it is non-null). convertible() + == true. +

+
Effects
+

+ Creates an appropriately-typed Boost.Python extension class instance, + uses MakeHolder to create an instance_holder from x, installs + the instance_holder in the new extension class instance, and + returns a pointer to it. +

+
+
+
+
+ +
bool convertible()
+
+

+
+
Effects
+

+ Returns true iff any module has registered a Python type corresponding + to U. +

+
+
+
+
+
+ +

+ This example replicates the functionality of reference_existing_object, but + without some of the compile-time error checking. +

+
struct make_reference_holder
+{
+   typedef boost::python::objects::instance_holder* result_type;
+   template <class T>
+   static result_type execute(T* p)
+   {
+      return new boost::python::objects::pointer_holder<T*, T>(p);
+   }
+};
+
+struct reference_existing_object
+{
+   // metafunction returning the ResultConverter
+   template <class T>
+   struct apply
+   {
+      typedef boost::python::to_python_indirect<T,make_reference_holder> type;
+   };
+};
+
+
+
+
+ + +
+ +

+ to_python_value is a + model of ResultConverter + which copies its argument into a new Python object. +

+
+
+ +
namespace boost { namespace python
+{
+   template <class T>
+   struct to_python_value
+   {
+      typedef typename add_reference<
+         typename add_const<T>::type
+      >::type argument_type;
+
+      static bool convertible();
+      PyObject* operator()(argument_type) const;
+   };
+}}
+
+
+
+ +
static bool convertible();
+
+

+
+
Returns
+

+ true iff a converter + has been registered which can convert T + to python by-value. +

+
+
+
PyObject* operator()(argument_type x) const;
+
+

+
+
Requires
+

+ convertible() + == true +

+
Effects
+

+ converts x to python +

+
Returns
+

+ the resulting Python object iff a converter for T + has been registered, 0 + otherwise. +

+
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/function_invocation_and_creation/models_of_resultconvertergenerat.html b/doc/develop/html/reference/function_invocation_and_creation/models_of_resultconvertergenerat.html new file mode 100644 index 00000000..a9167452 --- /dev/null +++ b/doc/develop/html/reference/function_invocation_and_creation/models_of_resultconvertergenerat.html @@ -0,0 +1,683 @@ + + + +Models of ResultConverterGenerator + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ + +
+ +

+ copy_const_reference + is a model of ResultConverterGenerator + which can be used to wrap C++ functions returning a reference-to-const + type such that the referenced value is copied into a new Python object. +

+
namespace boost { namespace python
+{
+    struct copy_const_reference
+    {
+        template <class T> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Requires
+

+ T is U const& for some U. +

+
Returns
+

+ typedef to_python_value<T> type; +

+
+
+
+
+ +

+ C++ module definition: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/return_value_policy.hpp>
+
+// classes to wrap
+struct Bar { int x; }
+
+struct Foo {
+   Foo(int x) : { b.x = x; }
+   Bar const& get_bar() const { return b; }
+ private:
+   Bar b;
+};
+
+// Wrapper code
+using namespace boost::python;
+BOOST_PYTHON_MODULE(my_module)
+{
+    class_<Bar>("Bar");
+
+     class_<Foo>("Foo", init<int>())
+        .def("get_bar", &Foo::get_bar
+            , return_value_policy<copy_const_reference>())
+       ;
+}
+
+

+ Python code: +

+
>>> from my_module import *
+>>> f = Foo(3)         # create a Foo object
+>>> b = f.get_bar()    # make a copy of the internal Bar object
+
+
+
+
+ + +
+ +

+ copy_non_const_reference + is a model of ResultConverterGenerator + which can be used to wrap C++ functions returning a reference-to-non-const + type such that the referenced value is copied into a new Python object. +

+
namespace boost { namespace python
+{
+    struct copy_non_const_reference
+    {
+        template <class T> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Requires
+

+ T is U & + for some non-const U. +

+
Returns
+

+ typedef to_python_value<T> type; +

+
+
+
+
+ +

+ C++ module definition: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/copy_non_const_reference.hpp>
+#include <boost/python/return_value_policy.hpp>
+
+// classes to wrap
+struct Bar { int x; }
+
+struct Foo {
+   Foo(int x) : { b.x = x; }
+   Bar& get_bar() { return b; }
+ private:
+   Bar b;
+};
+
+// Wrapper code
+using namespace boost::python;
+BOOST_PYTHON_MODULE(my_module)
+{
+    class_<Bar>("Bar");
+
+     class_<Foo>("Foo", init<int>())
+        .def("get_bar", &Foo::get_bar
+            , return_value_policy<copy_non_const_reference>())
+       ;
+}
+
+

+ Python code: +

+
>>> from my_module import *
+>>> f = Foo(3)         # create a Foo object
+>>> b = f.get_bar()    # make a copy of the internal Bar object
+
+
+
+
+ + +
+ +

+ manage_new_object is + a model of ResultConverterGenerator + which can be used to wrap C++ functions which return a pointer to an + object allocated with a new-expression, and expect the caller to take + responsibility for deleting that object. +

+
namespace boost { namespace python
+{
+    struct manage_new_object
+    {
+        template <class T> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Requires
+

+ T is U* + for some U. +

+
Returns
+

+ typedef to_python_indirect<T> type; +

+
+
+
+
+ +

+ In C++: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/manage_new_object.hpp>
+#include <boost/python/return_value_policy.hpp>
+
+
+struct Foo {
+   Foo(int x) : x(x){}
+   int get_x() { return x; }
+   int x;
+};
+
+Foo* make_foo(int x) { return new Foo(x); }
+
+// Wrapper code
+using namespace boost::python;
+BOOST_PYTHON_MODULE(my_module)
+{
+    def("make_foo", make_foo, return_value_policy<manage_new_object>())
+    class_<Foo>("Foo")
+        .def("get_x", &Foo::get_x)
+        ;
+}
+
+

+ Python code: +

+
>>> from my_module import *
+>>> f = make_foo(3)     # create a Foo object
+>>> f.get_x()
+3
+
+
+
+
+ + +
+ +

+ reference_existing_object + is a model of ResultConverterGenerator + which can be used to wrap C++ functions which return a reference or pointer + to a C++ object. When the wrapped function is called, the value referenced + by its return value is not copied. A new Python object is created which + contains a pointer to the referent, and no attempt is made to ensure + that the lifetime of the referent is at least as long as that of the + corresponding Python object. Thus, it can be highly + dangerous to use reference_existing_object + without additional lifetime management from such models of CallPolicies + as with_custodian_and_ward. This + class is used in the implementation of return_internal_reference. +

+
namespace boost { namespace python
+{
+    struct reference_existing_object
+    {
+        template <class T> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Requires
+

+ T is U& + or U* + for some U. +

+
Returns
+

+ typedef to_python_indirect<T, V> type;, where V is a class whose static + execute function constructs an instance holder containing an unowned + U* + pointing to the referent of the wrapped function's return value. +

+
+
+
+
+ +

+ In C++: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/reference_existing_object.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <utility>
+
+// classes to wrap
+struct Singleton
+{
+   Singleton() : x(0) {}
+
+   int exchange(int n)  // set x and return the old value
+   {
+        std::swap(n, x);
+        return n;
+   }
+
+   int x;
+};
+
+Singleton& get_it()
+{
+   static Singleton just_one;
+   return just_one;
+}
+
+// Wrapper code
+using namespace boost::python;
+BOOST_PYTHON_MODULE(singleton)
+{
+    def("get_it", get_it,
+        return_value_policy<reference_existing_object>());
+
+    class_<Singleton>("Singleton")
+       .def("exchange", &Singleton::exchange)
+       ;
+}
+
+

+ Python code: +

+
>>> import singleton
+>>> s1 = singleton.get_it()
+>>> s2 = singleton.get_it()
+>>> id(s1) == id(s2)  # s1 and s2 are not the same object
+0
+>>> s1.exchange(42)   # but they reference the same C++ Singleton
+0
+>>> s2.exchange(99)
+42
+
+
+
+
+ + +
+ +

+ return_by_value is a + model of ResultConverterGenerator + which can be used to wrap C++ functions returning any reference or value + type such that the return value is copied into a new Python object. +

+
namespace boost { namespace python
+{
+    struct return_by_value
+    {
+        template <class T> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Returns
+

+ typedef to_python_value<T> type; +

+
+
+
+
+ +

+ In C++: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/return_by_value.hpp>
+#include <boost/python/return_value_policy.hpp>
+
+// classes to wrap
+struct Bar { };
+
+Bar global_bar;
+
+// functions to wrap:
+Bar b1();
+Bar& b2();
+Bar const& b3();
+
+// Wrapper code
+using namespace boost::python;
+template <class R>
+void def_void_function(char const* name, R (*f)())
+{
+   def(name, f, return_value_policy<return_by_value>());
+}
+
+BOOST_PYTHON_MODULE(my_module)
+{
+    class_<Bar>("Bar");
+    def_void_function("b1", b1);
+    def_void_function("b2", b2);
+    def_void_function("b3", b3);
+}
+
+

+ Python code: +

+
>>> from my_module import *
+>>> b = b1() # each of these calls
+>>> b = b2() # creates a brand
+>>> b = b3() # new Bar object
+
+
+
+
+ + +
+ +

+ return_opaque_pointer is a model of ResultConverterGenerator + which can be used to wrap C++ functions returning pointers to undefined + types such that the return value is copied into a new Python object. +

+

+ In addition to specifying the return_opaque_pointer + policy the BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID + macro must be used to define specializations for the type_id function on the type + pointed to by returned pointer. +

+
namespace boost { namespace python
+{
+    struct return_opaque_pointer
+    {
+        template <class R> struct apply;
+    };
+}}
+
+
+
+ +
template <class T> struct apply
+
+

+
+
Returns
+

+ detail::opaque_conversion_holder<R> + type; +

+
+
+
+
+ +

+ In C++: +

+
# include <boost/python/return_opaque_pointer.hpp>
+# include <boost/python/def.hpp>
+# include <boost/python/module.hpp>
+# include <boost/python/return_value_policy.hpp>
+
+typedef struct opaque_ *opaque;
+
+opaque the_op   = ((opaque) 0x47110815);
+
+opaque get () { return the_op; }
+void use (opaque op) {
+    if (op != the_op)
+	throw std::runtime_error (std::string ("failed"));
+}
+
+void failuse (opaque op) {
+    if (op == the_op)
+	throw std::runtime_error (std::string ("success"));
+}
+
+BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_)
+
+namespace bpl = boost::python;
+
+BOOST_PYTHON_MODULE(opaque_ext)
+{
+    bpl::def (
+        "get", &::get, bpl::return_value_policy<bpl::return_opaque_pointer>());
+    bpl::def ("use", &::use);
+    bpl::def ("failuse", &::failuse);
+}
+
+

+ Python code: +

+
"""
+>>> from opaque_ext import *
+>>> #
+>>> # Check for correct conversion
+>>> use(get())
+>>> failuse(get())
+Traceback (most recent call last):
+        ...
+RuntimeError: success
+>>> #
+>>> # Check that there is no conversion from integers ...
+>>> use(0)
+Traceback (most recent call last):
+        ...
+TypeError: bad argument type for built-in operation
+>>> #
+>>> # ... and from strings to opaque objects
+>>> use("")
+Traceback (most recent call last):
+        ...
+TypeError: bad argument type for built-in operation
+"""
+def run(args = None):
+    import sys
+    import doctest
+
+    if args is not None:
+        sys.argv = args
+    return doctest.testmod(sys.modules.get(__name__))
+
+if __name__ == '__main__':
+    print "running..."
+    import sys
+    sys.exit(run()[0])
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/glossary.html b/doc/develop/html/reference/glossary.html new file mode 100644 index 00000000..5ee64879 --- /dev/null +++ b/doc/develop/html/reference/glossary.html @@ -0,0 +1,80 @@ + + + +Chapter 9. Glossary + + + + + + + +
+
+
+PrevUpHome +
+
+

+Chapter 9. Glossary

+
+

+
+
arity
+

+ The number of argumnts accepted by a function or member function. Unless + otherwise specified, the hidden this + argument to member functions is not counted when specifying arity. +

+
ntbs
+

+ Null-Terminated Byte String, or 'C'-string. C++ string literals are + ntbses. An ntbs + must never be null. +

+
raise
+

+ Exceptions in Python are "raised", not "thrown", + as they are in C++. When this documentation says that some Python exception + is "raised" in the context of C++ code, it means that the corresponding + Python exception is set via the Python/'C' + API, and throw_error_already_set() is called. +

+
POD
+

+ A technical term from the C++ standard. Short for "Plain Ol'Data": + A POD-struct is an aggregate class that has no non-static data members + of type pointer to member, non-POD-struct, non-POD-union (or array of + such types) or reference, and has no user-defined copy assign- ment operator + and no user-defined destructor. Similarly, a POD-union is an aggregate + union that has no non-static data members of type pointer to member, + non-POD-struct, non-POD-union (or array of such types) or reference, + and has no user-defined copy assignment operator and no user-defined + destructor. A POD class is a class that is either a POD-struct or a POD-union. + An aggregate is an array or a class (clause 9) with no user-declared + constructors (12.1), no private or protected non-static data members + (clause 11), no base classes (clause 10), and no virtual functions (10.3). +

+
ODR
+

+ The "One Definition Rule", which says that any entity in a + C++ program must have the same definition in all translation units (object + files) which make up a program. +

+
+
+
+ + + +
+
+
+PrevUpHome +
+ + diff --git a/doc/develop/html/reference/high_level_components.html b/doc/develop/html/reference/high_level_components.html new file mode 100644 index 00000000..caaf64fa --- /dev/null +++ b/doc/develop/html/reference/high_level_components.html @@ -0,0 +1,1090 @@ + + + +Chapter 2. High Level Components + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 2. High Level Components

+
+

Table of Contents

+
+
boost/python/class.hpp
+
+
Introduction
+
Class + template class_<T, Bases, HeldType, NonCopyable>
+
Class + template bases<T1, T2, ...TN>
+
Examples
+
+
boost/python/def.hpp
+
+
Introduction
+
Functions
+
Example
+
+
boost/python/def_visitor.hpp
+
+
Introduction
+
Class + def_visitor
+
Example
+
+
boost/python/docstring_options.hpp
+
+
Introduction
+
Class + docstring_options
+
Class + dostring_options constructors
+
Class + docstring_options destructor
+
Class + docstring_options modifier + functions
+
Example
+
+
boost/python/enum.hpp
+
+
Introduction
+
Class + template enum_
+
Class + template enum_ constructors
+
Class + template enum_ modifier functions
+
Example
+
+
boost/python/errors.hpp
+
+
Introduction
+
Class + error_already_set
+
Functions
+
Example
+
+
boost/python/exception_translator.hpp
+
+
Introduction
+
Function + register_exception_translator
+
Example
+
+
boost/python/init.hpp
+
+
Introduction
+
Class + template init
+
Class + template optional
+
Example
+
+
boost/python/iterator.hpp
+
+
Introduction
+
Class + template iterator
+
Class + template iterator constructors
+
Class + template iterators
+
Class + template iterators nested types
+
Class + template iterators static functions
+
Functions
+
Example
+
+
boost/python/module.hpp
+
+
Introduction
+
Macros
+
Examples
+
+
boost/python/operators.hpp
+
+
Introduction
+
Class + self_ns::self_t
+
Class + template other
+
Class + template detail::operator_
+
Object + self
+
Example
+
+
boost/python/scope.hpp
+
+
Introduction
+
Class + scope
+
Class + scope constructors and destructor
+
Example
+
+
boost/python/stl_iterator.hpp
+
+
Introduction
+
Class + template stl_input_iterator
+
Class + template stl_input_iterator + constructors
+
Class + template stl_input_iterator + modifiers
+
Class + template stl_input_iterator + observers
+
Example
+
+
boost/python/wrapper.hpp
+
+
Introduction
+
Class + override
+
Class + override observer functions
+
Class + template wrapper
+
Class + template wrapper observer + functions
+
Example
+
+
+
+
+ + +
+ +

+ <boost/python/class.hpp> + defines the interface through which users expose their C++ classes to Python. + It declares the class_ + class template, which is parameterized on the class type being exposed. + It also exposes the init, + optional and bases utility class templates, which + are used in conjunction with class_. +

+

+ <boost/python/class_fwd.hpp> contains a forward declaration of the + class_ class template. +

+
+
+ + +

+ Creates a Python class associated with the C++ type passed as its first + parameter. Although it has four template parameters, only the first one + is required. The three optional arguments can actually be supplied in any order; Boost.Python determines the role of + the argument from its type. +

+
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Template Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Default +

+
+

+ T +

+
+

+ A class type. +

+
+

+ The class being wrapped +

+
+
+

+ Bases +

+
+

+ A specialization of bases<...> + which specifies previously-exposed C++ base classes of T. +

+
+

+ Registers from_python + conversions from wrapped T + instances to each of its exposed direct and indirect bases. For + each polymorphic base B, + registers conversions from indirectly-held wrapped B instances to T. +

+
+

+ bases<> +

+
+

+ HeldType +

+
+

+ Must be T, a + class derived from T, + or a Dereferenceable + type for which pointee<HeldType>::type + is T or a class + derived from T. +

+
+

+ Specifies the type that is actually embedded in a Python object + wrapping a T + instance when T's + constructor is called or when a T + or T* + is converted to Python without the use of ptr, + ref, or Call Policies such as + return_internal_reference. + More details below. +

+
+

+ T +

+
+

+ NonCopyable +

+
+

+ If supplied, must be boost::noncopyable. +

+
+

+ Suppresses automatic registration of to_python + conversions which copy T + instances. Required when T + has no publicly-accessible copy constructor. +

+
+

+ An unspecified type other than boost::noncopyable. +

+
+
+ +
    +
  1. + If HeldType is derived from T, + its exposed constructor(s) must accept an initial PyObject* argument which refers back to the + Python object that contains the HeldType instance, as shown in this + example. This argument is not included in the init-expression + passed to def(init_expr), + below, nor is it passed explicitly by users when Python instances + of T are created. + This idiom allows C++ virtual functions which will be overridden + in Python to access the Python object so the Python method can be + invoked. Boost.Python automatically registers additional converters + which allow wrapped instances of T + to be passed to wrapped C++ functions expecting HeldType arguments. +
  2. +
  3. + Because Boost.Python will always allow wrapped instances of T to be passed in place of HeldType + arguments, specifying a smart pointer for HeldType allows users to + pass Python T instances + where a smart pointer-to-T is expected. Smart pointers such as std::auto_ptr<> + or boost::shared_ptr<> + which contain a nested type element_type + designating the referent type are automatically supported; additional + smart pointer types can be supported by specializing pointee<HeldType>. +
  4. +
  5. + As in case 1 above, when HeldType is a smart pointer to a class derived + from T, the initial + PyObject* + argument must be supplied by all of HeldType's exposed constructors. +
  6. +
  7. + Except in cases 1 and 3, users may optionally specify that T itself + gets initialized with a similar initial PyObject* argument by specializing has_back_reference<T>. +
  8. +
+
+
+ +
namespace boost { namespace python
+{
+template <class T
+    , class Bases = bases<>
+          , class HeldType = T
+          , class NonCopyable = unspecified
+         >
+class class_ : public object
+{
+  // Constructors with default __init__
+  class_(char const* name);
+  class_(char const* name, char const* docstring);
+
+  // Constructors, specifying non-default __init__
+  template <class Init>
+  class_(char const* name, Init);
+  template <class Init>
+  class_(char const* name, char const* docstring, Init);
+
+  // Exposing additional __init__ functions
+  template <class Init>
+  class_& def(Init);
+
+  // defining methods
+  template <class F>
+  class_& def(char const* name, F f);
+  template <class Fn, class A1>
+  class_& def(char const* name, Fn fn, A1 const&);
+  template <class Fn, class A1, class A2>
+  class_& def(char const* name, Fn fn, A1 const&, A2 const&);
+  template <class Fn, class A1, class A2, class A3>
+  class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&);
+
+  // declaring method as static
+  class_& staticmethod(char const* name);
+
+  // exposing operators
+  template <unspecified>
+  class_& def(detail::operator_<unspecified>);
+
+  // Raw attribute modification
+  template <class U>
+  class_& setattr(char const* name, U const&);
+
+  // exposing data members
+  template <class D>
+  class_& def_readonly(char const* name, D T::*pm);
+
+  template <class D>
+  class_& def_readwrite(char const* name, D T::*pm);
+
+  // exposing static data members
+  template <class D>
+  class_& def_readonly(char const* name, D const& d);
+  template <class D>
+  class_& def_readwrite(char const* name, D& d);
+
+  // property creation
+  template <class Get>
+  void add_property(char const* name, Get const& fget, char const* doc=0);
+  template <class Get, class Set>
+  void add_property(
+      char const* name, Get const& fget, Set const& fset, char const* doc=0);
+
+  template <class Get>
+  void add_static_property(char const* name, Get const& fget);
+  template <class Get, class Set>
+  void add_static_property(char const* name, Get const& fget, Set const& fset);
+
+  // pickle support
+  template <typename PickleSuite>
+  self& def_pickle(PickleSuite const&);
+  self& enable_pickling();
+};
+}}
+
+
+
+ +
class_(char const* name);
+class_(char const* name, char const* docstring);
+template <class Init>
+class_(char const* name, Init init_spec);
+template <class Init>
+class_(char const* name, char const* docstring, Init init_spec);
+
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. If docstring is supplied, it must be an + ntbs. If init_spec + is supplied, it must be either the special enumeration constant + no_init or an + init-expression + compatible with T. +

+
Effects
+
+

+ Constructs a class_ + object holding a Boost.Python extension class named name. The named + attribute of the current + scope is bound to the new extension class. +

+
    +
  • + If supplied, the value of docstring is bound to the __doc__ attribute of the + extension class. +
  • +
  • + If init_spec + is no_init, + a special __init__ + function is generated which always raises a Python exception. + Otherwise, this->def(init_spec) is called. +
  • +
  • + If init_spec + is not supplied, this->def(init<>()) is called. +
  • +
+
+
Rationale
+

+ Allowing the user to specify constructor arguments in the class_<> + constructor helps her to avoid the common run-time errors which + result from invoking wrapped member functions without having exposed + an __init__ function + which creates the requisite T + instance. Types which are not default-constructible will cause + a compile-time error unless Init + is supplied. The user must always supply name as there is currently + no portable method to derive the text of the class name from its + type. +

+
+
+
+
+ +
template <class Init>
+class_& def(Init init_expr);
+
+
+

+
+
Requires
+

+ init_expr is the + result of an init-expression + compatible with T. +

+
Effects
+

+ For each valid + prefix P + of Init, adds an + __init__(...) + function overload to the extension class accepting P as arguments. + Each overload generated constructs an object of HeldType according + to the semantics described above, using a copy of init_expr's call + policies. If the longest valid + prefix of Init contains N types and init_expr holds M keywords, + an initial sequence of the keywords are used for all but the first + N - M arguments of each overload. +

+
Returns
+

+ *this +

+
Rationale
+

+ Allows users to easily expose a class' constructor to Python. +

+
+
+
template <class F>
+class_& def(char const* name, Fn fn);
+template <class Fn, class A1>
+class_& def(char const* name, Fn fn, A1 const& a1);
+template <class Fn, class A1, class A2>
+class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2);
+template <class Fn, class A1, class A2, class A3>
+class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3);
+
+
+

+
+
Requires
+
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. * If a1 is the result of an overload-dispatch-expression, + only the second form is allowed and fn must be a pointer to function + or pointer to member function whose arity + is the same as A1's maximum + arity. +

+

+ Effects: For each prefix P of Fn's + sequence of argument types, beginning with the one whose length + is A1's minimum + arity, adds a name(...) method overload to the extension + class. Each overload generated invokes a1's call-expression with + P, using a copy + of a1's call policies. If the longest valid prefix of A1 contains N + types and a1 holds M + keywords, an initial sequence of the keywords are used for all + but the first N - M + arguments of each overload. +

+
  • + Otherwise, a single method overload is built around fn, which + must not be null: +
      +
    • + If fn is a function pointer, its first argument must + be of the form U, U cv&, U cv*, or U cv* const&, + where T* is convertible to U*, and a1-a3, if supplied, + may be selected in any order from the table below. +
    • +
    • + Otherwise, if fn is a member function pointer, its target + must be T or one of its public base classes, and a1-a3, + if supplied, may be selected in any order from the table + below. +
    • +
    • +

      + Otherwise, Fn must be [derived from] object, + and a1-a2, if supplied, may be selcted in any order from + the first two rows of the table below. To be useful, + fn should be callable. +

      +
      +++++ + + + + + + + + + + + + + + + + + + + + + + +
      +

      + Mnemonic Name +

      +
      +

      + Requirements/Type properties +

      +
      +

      + Effects +

      +
      +

      + docstring +

      +
      +

      + Any ntbs +

      +
      +

      + Value will be bound to the __doc__ attribute + of the resulting method overload. If an earlier + overload supplied a docstring, two newline + characters and the new docstring are appended + to it. +

      +
      +

      + policies +

      +
      +

      + A model of CallPolicies +

      +
      +

      + A copy will be used as the call policies of + the resulting method overload. +

      +
      +

      + keywords +

      +
      +

      + The result of a keyword-expression + specifying no more arguments than the arity of fn. +

      +
      +

      + A copy will be used as the call policies of + the resulting method overload. +

      +
      +
    • +
    +
+
+
Returns
+

+ *this +

+
+
+
class_& staticmethod(char const* name);
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules, and corresponds to a method whose overloads + have all been defined. +

+
Effects
+

+ Replaces the existing named attribute x + with the result of invoking staticmethod(x) in Python. Specifies that the + corresponding method is static and therefore no object instance + will be passed to it. This is equivalent to the Python statement: +

+
+
+
setattr(self, name, staticmethod(getattr(self, name)))
+
+

+
+
Note
+

+ Attempting to invoke def(name,...) after invoking staticmethod(name) + will raise a RuntimeError. +

+
Returns
+

+ *this +

+
+
+
template <unspecified>
+class_& def(detail::operator_<unspecified>);
+
+
+

+
+
Effects
+

+ Adds a Python special + method as described here. +

+
Returns
+

+ *this +

+
+
+
template <class U>
+class_& setattr(char const* name, U const& u);
+
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. +

+
Effects
+
+

+ Converts u to Python + and adds it to the attribute dictionary of the extension class: +

+
PyObject_SetAttrString(this->ptr(), name, object(u).ptr());
+
+
Returns
+

+ *this +

+
+
+
template <class Get>
+void add_property(char const* name, Get const& fget, char const* doc=0);
+template <class Get, class Set>
+void add_property(
+      char const* name, Get const& fget, Set const& fset, char const* doc=0);
+
+
+

+
+
Requires
+

+ name is an ntbs which conform to Python's + identifier + naming rules. +

+
Effects
+

+ Creates a new Python property + class instance, passing object(fget) (and object(fset) in the second form) with an (optional) + docstring doc to + its constructor, then adds that property to the Python class object + under construction with the given attribute name. +

+
Returns
+

+ *this +

+
Rationale
+

+ Allows users to easily expose functions that can be invoked from + Python with attribute access syntax. +

+
+
+
template <class Get>
+void add_static_property(char const* name, Get const& fget);
+template <class Get, class Set>
+void add_static_property(char const* name, Get const& fget, Set const& fset);
+
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. +

+
Effects
+

+ Creates a Boost.Python.StaticProperty object, passing object(fget) + (and object(fset) + in the second form) to its constructor, then adds that property + to the Python class under construction with the given attribute + name. StaticProperty is a special subclass of Python's property + class which can be called without an initial self argument. +

+
Returns
+

+ *this +

+
Rationale
+

+ Allows users to easily expose functions that can be invoked from + Python with static attribute access syntax. +

+
+
+
template <class D>
+class_& def_readonly(char const* name, D T::*pm, char const* doc=0);
+template <class D>
+class_& def_readonly(char const* name, D const& d);
+
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. doc + is also an ntbs. +

+
Effects
+
+
this->add_property(name, make_getter(pm), doc);
+

+ and +

+
this->add_static_property(name, make_getter(d));
+

+ respectively. +

+
+
Returns
+

+ *this +

+
Rationale
+

+ Allows users to easily expose a class' data member or free variable + such that it can be inspected from Python with a natural syntax. +

+
+
+
template <class D>
+class_& def_readwrite(char const* name, D T::*pm, char const* doc=0);
+template <class D>
+class_& def_readwrite(char const* name, D& d);
+
+
+

+
+
Effects
+
+
this->add_property(name, make_getter(pm), make_setter(pm), doc);
+

+ and +

+
this->add_static_property(name, make_getter(d), make_setter(d));
+

+ respectively. +

+
+
Returns
+

+ *this +

+
Rationale
+

+ Allows users to easily expose a class' data or free variable member + such that it can be inspected and set from Python with a natural + syntax. +

+
+
+
template <typename PickleSuite>
+class_& def_pickle(PickleSuite const&);
+
+
+

+
+
Requires
+

+ PickleSuite must be publically derived from pickle_suite. +

+
Effects
+

+ Defines a legal combination of the special attributes and methods: + __getinitargs__, __getstate__, __setstate__, __getstate_manages_dict__, + __safe_for_unpickling__, __reduce__ +

+
Returns
+

+ *this +

+
Rationale
+

+ Provides an easy + to use high-level interface for establishing complete pickle support + for the wrapped class. The user is protected by compile-time consistency + checks. +

+
+
+
class_& enable_pickling();
+
+

+
+
Effects
+

+ Defines the __reduce__ method and the __safe_for_unpickling__ attribute. +

+
Returns
+

+ *this +

+
Rationale
+

+ Light-weight alternative to def_pickle(). Enables implementation + of pickle support from Python. +

+
+
+
+
+
+ + +

+ An MPL sequence which can be used in class_<...> instantiations indicate + a list of base classes. +

+
+ +
namespace boost { namespace python
+{
+  template <T1 = unspecified,...Tn = unspecified>
+  struct bases
+  {};
+}}
+
+
+
+
+ +

+ Given a C++ class declaration: +

+
class Foo : public Bar, public Baz
+{
+ public:
+   Foo(int x, char const* y);
+   Foo(double);
+
+   std::string const& name() { return m_name; }
+   void name(char const*);
+
+   double value; // public data
+ private:
+   ...
+};
+
+

+ A corresponding Boost.Python extension class can be created with: +

+
using namespace boost::python;
+
+class_<Foo,bases<Bar,Baz> >("Foo",
+          "This is Foo's docstring."
+          "It describes our Foo extension class",
+
+          init<int,char const*>(args("x","y"), "__init__ docstring")
+          )
+   .def(init<double>())
+   .def("get_name", &Foo::get_name, return_internal_reference<>())
+   .def("set_name", &Foo::set_name)
+   .def_readwrite("value", &Foo::value);
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_def_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_def_hpp.html new file mode 100644 index 00000000..72ea270c --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_def_hpp.html @@ -0,0 +1,220 @@ + + + +boost/python/def.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ def() + is the function which can be used to expose C++ functions and callable + objects as Python functions in the current + scope. +

+
+
+ +
template <class F>
+void def(char const* name, F f);
+
+template <class Fn, class A1>
+void def(char const* name, Fn fn, A1 const&);
+
+template <class Fn, class A1, class A2>
+void def(char const* name, Fn fn, A1 const&, A2 const&);
+
+template <class Fn, class A1, class A2, class A3>
+void def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&);
+
+
+

+
+
Requires
+
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. +

+
    +
  • + If Fn is [derived + from] object, + it will be added to the current + scope as a single overload. To be useful, fn should be callable. +
  • +
  • +

    + If a1 is the + result of an overload-dispatch-expression, + only the second form is allowed and fn + must be a pointer to function or pointer to member function whose + arity is the same as A1's maximum + arity. +

    +

    + Effects: For each prefix P of Fn's + sequence of argument types, beginning with the one whose length + is A1's minimum + arity, adds a name(...) function overload to the + current + scope. Each overload generated invokes a1's call-expression + with P, using a copy of a1's call policies. If the longest valid + prefix of A1 contains N types and a1 holds M keywords, an initial + sequence of the keywords are used for all but the first N - M + arguments of each overload. +

    +
  • +
  • +

    + Otherwise, fn must be a non-null function or member function + pointer, and a single function overload built around fn is added + to the current scope. If any of a1-a3 are supplied, they may + be selected in any order from the table below. +

    +
    +++++ + + + + + + + + + + + + + + + + + + + + + + +
    +

    + Mnemonic Name +

    +
    +

    + Requirements/Type properties +

    +
    +

    + Effects +

    +
    +

    + docstring +

    +
    +

    + Any ntbs +

    +
    +

    + Value will be bound to the __doc__ + attribute of the resulting method overload. +

    +
    +

    + policies +

    +
    +

    + A model of CallPolicies +

    +
    +

    + A copy will be used as the call policies of the resulting + method overload. +

    +
    +

    + keywords +

    +
    +

    + The result of a keyword-expression + specifying no more arguments than the arity + of fn. +

    +
    +

    + A copy will be used as the call policies of the resulting + method overload. +

    +
    +
  • +
+
+
+
+
+
+ +
#include <boost/python/def.hpp>
+#include <boost/python/module.hpp>
+#include <boost/python/args.hpp>
+
+using namespace boost::python;
+
+char const* foo(int x, int y) { return "foo"; }
+
+BOOST_PYTHON_MODULE(def_test)
+{
+    def("foo", foo, args("x", "y"), "foo's docstring");
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_def_visitor_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_def_visitor_hpp.html new file mode 100644 index 00000000..641cc73d --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_def_visitor_hpp.html @@ -0,0 +1,208 @@ + + + +boost/python/def_visitor.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/def_visitor.hpp> provides a generic visitation interface + through which the class_ + def member functionality can be extended non-intrusively to avoid cluttering + the class_ + interface. It declares the def_visitor<T> class template, which is parameterized + on the derived type DerivedVisitor, + which provides the actual def + functionality through its visit + member functions. +

+
+
+ +

+ The class def_visitor is + a base class paramaterized by its derived class. The def_visitor + class is a protocol class. Its derived class, DerivedVisitor, is expected + to have a member function visit. + The def_visitor class is + never instantiated directly. Instead, an instance of its subclass, DerivedVisitor, + is passed on as an argument to the class_ + def member function. +

+
namespace boost { namespace python {
+
+    template <class DerivedVisitor>
+    class def_visitor {};
+}
+
+
+

+
+
Requires
+
+

+ The client supplied class DerivedVisitor template parameter is expected + to: * be privately derived from def_visitor * grant friend access + to class def_visitor_access * define either or both visit member + functions listed in the table below: +

+
++++++ + + + + + + + + + + + + + + + + + + + + +
+

+ Expression +

+
+

+ Return Type +

+
+

+ Requirements +

+
+

+ Effects +

+
+

+ visitor.visit(cls) +

+
+

+ void +

+
+

+ cls is + an instance of a class_ + being wrapped to Python. visitor + is a def_visitor + derived class. +

+
+

+ A call to cls.def(visitor) forwards to this member + function. +

+
+

+ visitor.visit(cls, name, options) +

+
+

+ void +

+
+

+ cls is + a class_ + instance, name is a C string. visitor + is a def_visitor + derived class. options is a context specific optional argument. +

+
+

+ A call to cls.def(name, visitor) or cls.def(name, visitor, options) forwards to this member + function. +

+
+
+
+
+
+
+ +
class X {/*...*/};
+
+class my_def_visitor : boost::python::def_visitor<my_def_visitor>
+{
+  friend class def_visitor_access;
+
+  template <class classT>
+  void visit(classT& c) const
+  {
+    c.def("foo", &my_def_visitor::foo);
+    c.def("bar", &my_def_visitor::bar);
+  }
+
+  static void foo(X& self);
+  static void bar(X& self);
+};
+
+BOOST_PYTHON_MODULE(my_ext)
+{
+  class_<X>("X")
+    .def(my_def_visitor());
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_docstring_options_h.html b/doc/develop/html/reference/high_level_components/boost_python_docstring_options_h.html new file mode 100644 index 00000000..40458a05 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_docstring_options_h.html @@ -0,0 +1,363 @@ + + + +boost/python/docstring_options.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Boost.Python supports user-defined docstrings with automatic appending + of C++ signatures. These features are enabled by default. The class docstring_options + is available to selectively suppress the user-defined docstrings, signatures, + or both. +

+
+
+ +

+ Controls the appearance of docstrings of wrapped functions and member functions + for the life-time of the instance. The instances are noncopyable to eliminate + the possibility of surprising side effects. +

+
namespace boost { namespace python {
+
+  class docstring_options : boost::noncopyable
+  {
+  public:
+    docstring_options(bool show_all=true);
+    docstring_options(bool show_user_defined, bool show_signatures);
+    docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures);
+    ~docstring_options();
+    void disable_user_defined();
+    void enable_user_defined();
+    void disable_signatures();
+    void enable_signatures();
+    void disable_py_signatures();
+    void enable_py_signatures();
+    void disable_cpp_signatures();
+    void enable_cpp_signatures();
+    void disable_all();
+    void enable_all();
+  };
+}}
+
+
+
+ +
docstring_options(bool show_all=true);
+
+
+

+
+
Effects
+

+ Constructs a docstring_options object which controls the appearance + of function and member-function docstrings defined in the code that + follows. If show_all is true, both the user-defined docstrings and + the automatically generated Python and C++ signatures are shown. + If show_all is false the __doc__ + attributes are None. +

+
+
+
docstring_options(bool show_user_defined, bool show_signatures);
+
+
+

+
+
Effects
+

+ Constructs a docstring_options + object which controls the appearance of function and member-function + docstrings defined in the code that follows. Iff show_user_defined + is true, the user-defined + docstrings are shown. Iff show_signatures + is true, Python and + C++ signatures are automatically added. If both show_user_defined + and show_signatures + are false, the __doc__ attributes are None. +

+
+
+
docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures);
+
+
+

+
+
Effects
+

+ Constructs a docstring_options + object which controls the appearance of function and member-function + docstrings defined in the code that follows. Iff show_user_defined + is true, the user-defined + docstrings are shown. Iff show_py_signatures + is true, Python signatures + are automatically added. Iff show_cpp_signatures + is true, C++ signatures are automatically added. If all parameters + are false, the __doc__ attributes are None. +

+
+
+
+
+ +
~docstring_options();
+
+

+
+
Effects
+

+ Restores the previous state of the docstring options. In particular, + if docstring_options + instances are in nested C++ scopes the settings effective in the + enclosing scope are restored. If the last docstring_options + instance goes out of scope the default "all on" settings + are restored. +

+
+
+
+
+ +
void disable_user_defined();
+void enable_user_defined();
+void disable_signatures();
+void enable_signatures();
+void disable_py_signatures();
+void enable_py_signatures();
+void disable_cpp_signatures();
+void enable_cpp_signatures();
+void disable_all();
+void enable_all();
+
+

+ These member functions dynamically change the appearance of docstrings + in the code that follows. The *_user_defined() + and *_signatures() member functions are provided for fine-grained + control. The *_all() member functions are convenient shortcuts + to manipulate all settings simultaneously. +

+
+
+ + +
+ +
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/docstring_options.hpp>
+
+void foo() {}
+
+BOOST_PYTHON_MODULE(demo)
+{
+    using namespace boost::python;
+    docstring_options doc_options(DEMO_DOCSTRING_SHOW_ALL);
+    def("foo", foo, "foo doc");
+}
+
+

+ If compiled with -DDEMO_DOCSTRING_SHOW_ALL=true: +

+
>>> import demo
+>>> print demo.foo.__doc__
+foo() -> None : foo doc
+C++ signature:
+    foo(void) -> void
+
+

+ If compiled with -DDEMO_DOCSTRING_SHOW_ALL=false: +

+
>>> import demo
+>>> print demo.foo.__doc__
+None
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/docstring_options.hpp>
+
+int foo1(int i) { return i; }
+int foo2(long l) { return static_cast<int>(l); }
+int foo3(float f) { return static_cast<int>(f); }
+int foo4(double d) { return static_cast<int>(d); }
+
+BOOST_PYTHON_MODULE(demo)
+{
+    using namespace boost::python;
+    docstring_options doc_options;
+    def("foo1", foo1, arg("i"), "foo1 doc");
+    doc_options.disable_user_defined();
+    def("foo2", foo2, arg("l"), "foo2 doc");
+    doc_options.disable_signatures();
+    def("foo3", foo3, arg("f"), "foo3 doc");
+    doc_options.enable_user_defined();
+    def("foo4", foo4, arg("d"), "foo4 doc");
+    doc_options.enable_py_signatures();
+    def("foo5", foo4, arg("d"), "foo5 doc");
+    doc_options.disable_py_signatures();
+    doc_options.enable_cpp_signatures();
+    def("foo6", foo4, arg("d"), "foo6 doc");
+}
+
+

+ Python code: +

+
>>> import demo
+>>> print demo.foo1.__doc__
+foo1( (int)i) -> int : foo1 doc
+C++ signature:
+    foo1(int i) -> int
+>>> print demo.foo2.__doc__
+foo2( (int)l) -> int :
+C++ signature:
+    foo2(long l) -> int
+>>> print demo.foo3.__doc__
+None
+>>> print demo.foo4.__doc__
+foo4 doc
+>>> print demo.foo5.__doc__
+foo5( (float)d) -> int : foo5 doc
+>>> print demo.foo6.__doc__
+foo6 doc
+C++ signature:
+    foo6(double d) -> int
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/docstring_options.hpp>
+
+int foo1(int i) { return i; }
+int foo2(long l) { return static_cast<int>(l); }
+
+int bar1(int i) { return i; }
+int bar2(long l) { return static_cast<int>(l); }
+
+namespace {
+
+    void wrap_foos()
+    {
+        using namespace boost::python;
+        // no docstring_options here
+        //   -> settings from outer C++ scope are in effect
+        def("foo1", foo1, arg("i"), "foo1 doc");
+        def("foo2", foo2, arg("l"), "foo2 doc");
+    }
+
+    void wrap_bars()
+    {
+        using namespace boost::python;
+        bool show_user_defined = true;
+        bool show_signatures = false;
+        docstring_options doc_options(show_user_defined, show_signatures);
+        def("bar1", bar1, arg("i"), "bar1 doc");
+        def("bar2", bar2, arg("l"), "bar2 doc");
+    }
+}
+
+BOOST_PYTHON_MODULE(demo)
+{
+    boost::python::docstring_options doc_options(false);
+    wrap_foos();
+    wrap_bars();
+}
+
+

+ Python code: +

+
>>> import demo
+>>> print demo.foo1.__doc__
+None
+>>> print demo.foo2.__doc__
+None
+>>> print demo.bar1.__doc__
+bar1 doc
+>>> print demo.bar2.__doc__
+bar2 doc
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_enum_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_enum_hpp.html new file mode 100644 index 00000000..fcacb606 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_enum_hpp.html @@ -0,0 +1,217 @@ + + + +boost/python/enum.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/enum.hpp> defines the interface through which users + expose their C++ enumeration types to Python. It declares the enum_ class template, which is parameterized + on the enumeration type being exposed. +

+
+
+ +

+ Creates a Python class derived from Python's int + type which is associated with the C++ type passed as its first parameter. +

+
namespace boost { namespace python
+{
+  template <class T>
+  class enum_ : public object
+  {
+    enum_(char const* name, char const* doc = 0);
+    enum_<T>& value(char const* name, T);
+    enum_<T>& export_values();
+  };
+}}
+
+
+
+ +
enum_(char const* name, char const* doc=0);
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. +

+
Effects
+

+ Constructs an enum_ + object holding a Python extension type derived from int which is named name. + The named attribute of the current + scope is bound to the new extension type. +

+
+
+
+
+ +
enum_<T>& value(char const* name, T x);
+
+

+
+
Requires
+

+ name is an ntbs which conforms to Python's + identifier + naming rules. +

+
Effects
+

+ adds an instance of the wrapped enumeration type with value x to + the type's dictionary as the named attribute. +

+
Returns
+

+ *this +

+
+
+
enum_<T>& export_values();
+
+

+
+
Effects
+

+ sets attributes in the current + scope with the same names and values as all enumeration values + exposed so far by calling value(). +

+
Returns
+

+ *this +

+
+
+
+
+ +

+ C++ module definition +

+
#include <boost/python/enum.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/module.hpp>
+
+using namespace boost::python;
+
+enum color { red = 1, green = 2, blue = 4 };
+
+color identity_(color x) { return x; }
+
+BOOST_PYTHON_MODULE(enums)
+{
+  enum_<color>("color")
+    .value("red", red)
+    .value("green", green)
+    .export_values()
+    .value("blue", blue)
+    ;
+
+  def("identity", identity_);
+}
+
+

+ Interactive Python: +

+
>>> from enums import *
+
+>>> identity(red)
+enums.color.red
+
+>>> identity(color.red)
+enums.color.red
+
+>>> identity(green)
+enums.color.green
+
+>>> identity(color.green)
+enums.color.green
+
+>>> identity(blue)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+NameError: name 'blue' is not defined
+
+>>> identity(color.blue)
+enums.color.blue
+
+>>> identity(color(1))
+enums.color.red
+
+>>> identity(color(2))
+enums.color.green
+
+>>> identity(color(3))
+enums.color(3)
+
+>>> identity(color(4))
+enums.color.blue
+
+>>> identity(1)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+TypeError: bad argument type for built-in operation
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_errors_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_errors_hpp.html new file mode 100644 index 00000000..d01aece5 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_errors_hpp.html @@ -0,0 +1,278 @@ + + + +boost/python/errors.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/errors.hpp> provides types and functions for managing + and translating between Python and C++ exceptions. This is relatively low-level + functionality that is mostly used internally by Boost.Python. Users should + seldom need it. +

+
+
+ +

+ error_already_set is an exception type which can be thrown to indicate + that a Python error has occurred. If thrown, the precondition is that + PyErr_Occurred() + returns a value convertible to true. + Portable code shouldn't throw this exception type directly, but should + instead use throw_error_already_set(), + below. +

+
namespace boost { namespace python
+{
+    class error_already_set {};
+}}
+
+
+
+ +
template <class T> bool handle_exception(T f) throw();
+void handle_exception() throw();
+
+
+

+
+
Requires
+

+ The first form requires that the expression function0<void>(f) + is valid. The second form requires that a C++ exception is currently + being handled (see section 15.1 in the C++ standard). +

+
Effects
+

+ The first form calls f() inside a try block which first attempts + to use all registered exception + translators. If none of those translates the exception, the + catch clauses then set an appropriate Python exception for the C++ + exception caught, returning true if an exception was thrown, false + otherwise. The second form passes a function which rethrows the exception + currently being handled to the first form. +

+
Postconditions
+

+ No exception is being handled +

+
Throws
+

+ nothing +

+
Rationale
+

+ At inter-language boundaries it is important to ensure that no C++ + exceptions escape, since the calling language usually doesn't have + the equipment necessary to properly unwind the stack. Use handle_exception + to manage exception translation whenever your C++ code is called + directly from the Python API. This is done for you automatically + by the usual function wrapping facilities: make_function(), + make_constructor(), + def() + and class_::def(). + The second form can be more convenient to use (see the example below), + but various compilers have problems when exceptions are rethrown + from within an enclosing try block. +

+
+
+
template <class T> T* expect_non_null(T* x);
+
+

+
+
Returns
+

+ x +

+
Throws
+

+ error_already_set() iff x == 0. +

+
Rationale
+

+ Simplifies error-handling when calling functions in the Python/C + API which return 0 on error. +

+
+
+
void throw_error_already_set();
+
+

+
+
Effects
+

+ throw error_already_set(); +

+
Rationale
+

+ Simplifies error-handling when calling functions in the Python/C + API which return 0 on error. +

+
+
+
void throw_error_already_set();
+
+

+
+
Effects
+

+ throw error_already_set(); +

+
Rationale
+

+ Many platforms and compilers are not able to consistently catch exceptions + thrown across shared library boundaries. Using this function from + the Boost.Python library ensures that the appropriate catch block + in handle_exception() can catch the exception. +

+
+
+
+
+ +
#include <string>
+#include <boost/python/errors.hpp>
+#include <boost/python/object.hpp>
+#include <boost/python/handle.hpp>
+
+// Returns a std::string which has the same value as obj's "__name__"
+// attribute.
+std::string get_name(boost::python::object obj)
+{
+   // throws if there's no __name__ attribute
+   PyObject* p = boost::python::expect_non_null(
+      PyObject_GetAttrString(obj.ptr(), "__name__"));
+
+   char const* s = PyString_AsString(p);
+   if (s != 0)
+        Py_DECREF(p);
+
+   // throws if it's not a Python string
+   std::string result(
+      boost::python::expect_non_null(
+         PyString_AsString(p)));
+
+   Py_DECREF(p); // Done with p
+
+   return result;
+}
+
+//
+// Demonstrate form 1 of handle_exception
+//
+
+// Place into result a Python Int object whose value is 1 if a and b have
+// identical "__name__" attributes, 0 otherwise.
+void same_name_impl(PyObject*& result, boost::python::object a, boost::python::object b)
+{
+   result = PyInt_FromLong(
+      get_name(a) == get_name(a2));
+}
+
+object borrowed_object(PyObject* p)
+{
+   return boost::python::object(
+        boost::python::handle<>(
+             boost::python::borrowed(a1)));
+}
+
+// This is an example Python 'C' API interface function
+extern "C" PyObject*
+same_name(PyObject* args, PyObject* keywords)
+{
+   PyObject* a1;
+   PyObject* a2;
+   PyObject* result = 0;
+
+   if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
+      return 0;
+
+   // Use boost::bind to make an object compatible with
+   // boost::Function0<void>
+   if (boost::python::handle_exception(
+         boost::bind<void>(same_name_impl, boost::ref(result), borrowed_object(a1), borrowed_object(a2))))
+   {
+      // an exception was thrown; the Python error was set by
+      // handle_exception()
+      return 0;
+   }
+
+   return result;
+}
+
+//
+// Demonstrate form 2 of handle_exception. Not well-supported by all
+// compilers.
+//
+extern "C" PyObject*
+same_name2(PyObject* args, PyObject* keywords)
+{
+   PyObject* a1;
+   PyObject* a2;
+   PyObject* result = 0;
+
+   if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
+      return 0;
+
+   try {
+      return PyInt_FromLong(
+         get_name(borrowed_object(a1)) == get_name(borrowed_object(a2)));
+   }
+   catch(...)
+   {
+      // If an exception was thrown, translate it to Python
+      boost::python::handle_exception();
+      return 0;
+   }
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_exception_translato.html b/doc/develop/html/reference/high_level_components/boost_python_exception_translato.html new file mode 100644 index 00000000..cb34fad2 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_exception_translato.html @@ -0,0 +1,130 @@ + + + +boost/python/exception_translator.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ As described here, + it is important to make sure that exceptions thrown by C++ code do not + pass into the Python interpreter core. By default, Boost.Python translates + all C++ exceptions thrown by wrapped functions and module init functions + into Python, but the default translators are extremely limited: most C++ + exceptions will appear in Python as a RuntimeError + exception whose representation is 'Unidentifiable C++ Exception'. To produce + better error messages, users can register additional exception translators + as described below. +

+
+
+ +
template<class ExceptionType, class Translate>
+void register_exception_translator(Translate translate);
+
+
+

+
+
Requires
+
+

+ Translate is CopyConstructible, and the following code must be well-formed: +

+
void f(ExceptionType x) { translate(x); }
+

+ . The expression translate(x) must either throw a C++ exception, + or a subsequent call to PyErr_Occurred() must return 1. +

+
+
Effects
+

+ Adds a copy of translate to the sequence of exception translators + tried when Boost.Python catches an exception that is about to pass + into Python's core interpreter. The new translator will get "first + shot" at translating all exceptions matching the catch clause + shown above. Any subsequently-registered translators will be allowed + to translate the exception earlier. A translator which cannot translate + a given C++ exception can re-throw it, and it will be handled by + a translator which was registered earlier (or by the default translator). +

+
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/exception_translator.hpp>
+#include <exception>
+
+struct my_exception : std::exception
+{
+  char const* what() throw() { return "One of my exceptions"; }
+};
+
+void translate(my_exception const& e)
+{
+    // Use the Python 'C' API to set up an exception object
+    PyErr_SetString(PyExc_RuntimeError, e.what());
+}
+
+void something_which_throws()
+{
+    ...
+    throw my_exception();
+    ...
+}
+
+BOOST_PYTHON_MODULE(exception_translator_ext)
+{
+  using namespace boost::python;
+  register_exception_translator<my_exception>(&translate);
+
+  def("something_which_throws", something_which_throws);
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_init_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_init_hpp.html new file mode 100644 index 00000000..77fe1a89 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_init_hpp.html @@ -0,0 +1,233 @@ + + + +boost/python/init.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ + +

+ <boost/python/init.hpp> defines the interface for exposing C++ constructors + to Python as extension class __init__ + functions. +

+
+ +

+ An init-expression is used to describe a family of __init__ + methods to be generated for an extension class, and the result has the + following properties: +

+
+

+
+
docstring
+

+ An ntbs whose value will bound to the + method's __doc__ + attribute +

+
keywords
+

+ A keyword-expression + which will be used to name (a trailing subsequence of) the arguments + to the generated __init__ + function(s). +

+
call_policies
+

+ An instance of a model of CallPolicies. +

+
argument_types
+

+ An MPL sequence of C++ argument types which will be used to construct + the wrapped C++ object. An init expression has one or more valid + prefixes which are given by a sequence of prefixes of its argument + types. +

+
+
+
+
+
+ + +

+ A MPL sequence which can be used to specify a family of one or more __init__ + functions. Only the last Ti supplied may be an instantiation of optional<...>. +

+
namespace boost { namespace python
+{
+  template <T1 = unspecified,...Tn = unspecified>
+  struct init
+  {
+    init(char const* doc = 0);
+    template <class Keywords> init(Keywords const& kw, char const* doc = 0);
+    template <class Keywords> init(char const* doc, Keywords const& kw);
+
+    template <class CallPolicies>
+    unspecified operator[](CallPolicies const& policies) const
+  };
+}}
+
+
+ +
init(char const* doc = 0);
+template <class Keywords> init(Keywords const& kw, char const* doc = 0);
+template <class Keywords> init(char const* doc, Keywords const& kw);
+
+
+

+
+
Requires
+

+ If supplied, doc is an ntbs. If supplied, + kw is the result of a +

+
Effects
+
+

+ The result is an init-expression whose docstring is doc and whose + keywords are a reference to kw. If the first form is used, the + resulting expression's keywords are empty. The expression's call + policies are an instance of default_call_policies. + If Tn is optional<U1, + U2,... Um>, the expression's valid prefixes are given + by: +

+
(T1, T2,...Tn-1), (T1, T2,...Tn-1 , U1), (T1, T2,...Tn-1 , U1, U2), ...(T1, T2,...Tn-1 , U1, U2,...Um)
+

+ . Otherwise, the expression has one valid prefix given by the template + arguments the user specified. +

+
+
+
+
+
+ +
template <class Policies>
+unspecified operator[](Policies const& policies) const
+
+
+

+
+
Requires
+

+ Policies is a model of CallPolicies. +

+
Effects
+

+ Returns a new init-expression + with all the same properties as the init object except that its + call policies are replaced by a reference to policies. +

+
+
+
+
+
+ +

+ A MPL sequence which can be used to specify the optional arguments to an + __init__ function. +

+
namespace boost { namespace python
+{
+  template <T1 = unspecified,...Tn = unspecified>
+  struct optional {};
+}}
+
+
+
+ +

+ Given the C++ declarations: +

+
class Y;
+class X
+{
+ public:
+   X(int x, Y* y) : m_y(y) {}
+   X(double);
+ private:
+   Y* m_y;
+};
+
+

+ A corresponing Boost.Python extension class can be created with: +

+
using namespace boost::python;
+
+class_<X>("X", "This is X's docstring.",
+          init<int,char const*>(args("x","y"), "X.__init__'s docstring")[
+                with_custodian_and_ward<1,3>()]
+          )
+   .def(init<double>())
+   ;
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_iterator_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_iterator_hpp.html new file mode 100644 index 00000000..a63350c3 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_iterator_hpp.html @@ -0,0 +1,398 @@ + + + +boost/python/iterator.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/iterator.hpp> provides types and functions for creating + Python + iterators from C++ Containers and Iterators. Note that if your + class_ supports random-access + iterators, implementing __getitem__ + (also known as the Sequence Protocol) may serve you better than using this + facility: Python will automatically create an iterator type for you (see + iter()), + and each access can be range-checked, leaving no possiblity of accessing + through an invalidated C++ iterator. +

+
+
+ +

+ Instances of iterator<C,P> hold a reference to a callable Python + object which, when invoked from Python, expects a single argument c convertible + to C and creates a Python iterator that traverses [c.begin(), c.end()). The optional CallPolicies + P can be used to control + how elements are returned during iteration. +

+

+ In the table below, c is an instance of Container. +

+
++++++ + + + + + + + + + + + + + + + + + + + + +
+

+ Template Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Default +

+
+

+ Container +

+
+

+ [c.begin(),c.end()) is a valid Iterator range. +

+
+

+ The result will convert its argument to c and call c.begin() + and c.end() to acquire iterators. To invoke Container's const + begin() + and end() + functions, make it const. +

+
+
+

+ NextPolicies +

+
+

+ A default-constructible model of CallPolicies. +

+
+

+ Applied to the resulting iterators' next() method. +

+
+

+ An unspecified model of CallPolicies + which always makes a copy of the result of deferencing the underlying + C++ iterator +

+
+
namespace boost { namespace python
+  {
+    template <class Container, class NextPolicies = unspecified>
+    struct iterator : object
+    {
+      iterator();
+    };
+  }}
+
+
+
+ +
iterator()
+
+

+
+
Effects
+
+

+ Initializes its base class with the result of: +

+
range<NextPolicies>(&iterators<Container>::begin, &iterators<Container>::end)
+
+
Postconditions
+

+ this->get() + points to a Python callable object which creates a Python iterator + as described above. +

+
Rationale
+

+ Provides an easy way to create iterators for the common case where + a C++ class being wrapped provides begin() and end(). +

+
+
+
+
+ +

+ A utility class template which provides a way to reliably call its argument's + begin() + and end() + member functions. Note that there is no portable way to take the address + of a member function of a C++ standard library container, so iterators<> + can be particularly helpful when wrapping them. +

+

+ In the table below, x is an instance of C. +

+
++++ + + + + + + + + + + + + + + +
+

+ Required Valid Expression +

+
+

+ Type +

+
+

+ x.begin() +

+
+

+ Convertible to C::const_iterator if C is a const type; convertible + to C::iterator otherwise. +

+
+

+ x.end() +

+
+

+ Convertible to C::const_iterator if C is a const type; convertible + to C::iterator otherwise. +

+
+
namespace boost { namespace python
+{
+  template <class C>
+  struct iterators
+  {
+      typedef typename C::const_iterator iterator;
+      static iterator begin(C& x);
+      static iterator end(C& x);
+  };
+}}
+
+
+
+ +

+ If C is a const type, +

+
typedef typename C::const_iterator iterator;
+

+ Otherwise: +

+
typedef typename C::iterator iterator;
+
+
+ +
static iterator begin(C&);
+
+

+
+
Returns
+

+ x.begin() +

+
+
+
static iterator end(C&);
+
+

+
+
Returns
+

+ x.end() +

+
+
+
+
+ +
template <class NextPolicies, class Target, class Accessor1, class Accessor2>
+object range(Accessor1 start, Accessor2 finish);
+
+template <class NextPolicies, class Accessor1, class Accessor2>
+object range(Accessor1 start, Accessor2 finish);
+
+template <class Accessor1, class Accessor2>
+object range(Accessor1 start, Accessor2 finish);
+
+
+

+
+
Requires
+

+ NextPolicies is a default-constructible model of CallPolicies. +

+
Effects
+
+

+ The first form creates a Python callable object which, when invoked, + converts its argument to a Target object x, and creates a Python + iterator which traverses [bind(start,_1)(x), bind(finish,_1)(x)), + applying NextPolicies to the iterator's next() function. The second form is identical + to the first, except that Target is deduced from Accessor1 as follows: +

+
    +
  1. + If Accessor1 is a function type, Target is the type of its first + argument. +
  2. +
  3. + If Accessor1 is a data member pointer of the form R (T::*), + Target is identical to T. +
  4. +
  5. + If Accessor1 is a member function pointer of the form R (T::*)(arguments...) + cv-opt, where cv-opt is an optional + cv-qualifier, Target is identical to T. +
  6. +
+

+ The third form is identical to the second, except that NextPolicies + is an unspecified model of CallPolicies + which always makes a copy of the result of deferencing the underlying + C++ iterator +

+
+
Rationale
+

+ The use of boost::bind() allows C++ iterators to be accessed + through functions, member functions or data member pointers. Customization + of NextPolicies (e.g. using return_internal_reference) + is useful when it is expensive to copy sequence elements of a wrapped + class type. Customization of Target is useful when Accessor1 is a + function object, or when a base class of the intended target type + would otherwise be deduced. +

+
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+
+#include <vector>
+
+using namespace boost::python;
+BOOST_PYTHON_MODULE(demo)
+{
+    class_<std::vector<double> >("dvec")
+        .def("__iter__", iterator<std::vector<double> >())
+        ;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_module_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_module_hpp.html new file mode 100644 index 00000000..c3cd3be3 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_module_hpp.html @@ -0,0 +1,111 @@ + + + +boost/python/module.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ This header provides the basic facilities needed to create a Boost.Python + extension module. +

+
+
+

+Macros +

+

+ BOOST_PYTHON_MODULE(name) + is used to declare Python module + initialization functions. The name argument must exactly match + the name of the module to be initialized, and must conform to Python's + identifier + naming rules. Where you would normally write +

+
extern "C" void initname()
+{
+   ...
+}
+
+

+ Boost.Python modules should be initialized with +

+
BOOST_PYTHON_MODULE(name)
+{
+   ...
+}
+
+

+ This macro generates two functions in the scope where it is used: extern "C" + void initname(), and void + init_module_name(), + whose body must follow the macro invocation. init_name + passes init_module_name + to handle_exception() + so that any C++ exceptions generated are safely processeed. During the + body of init_name, the + current scope + refers to the module being initialized. +

+
+
+ +

+ C++ module definition: +

+
#include <boost/python/module.hpp>
+
+BOOST_PYTHON_MODULE(xxx)
+{
+    throw "something bad happened"
+}
+
+

+ Interactive Python: +

+
>>> import xxx
+Traceback (most recent call last):
+  File "", line 1, in ?
+RuntimeError: Unidentifiable C++ Exception
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_operators_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_operators_hpp.html new file mode 100644 index 00000000..efec22fd --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_operators_hpp.html @@ -0,0 +1,1558 @@ + + + +boost/python/operators.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/operators.hpp> provides types and functions for automatically + generating Python special + methods from the corresponding C++ constructs. Most of these constructs + are operator expressions, hence the name. To use the facility, substitute + the self + object for an object of the class type being wrapped in the expression + to be exposed, and pass the result to class_<>::def(). + Much of what is exposed in this header should be considered part of the + implementation, so is not documented in detail here. +

+
+
+ + +

+ self_ns::self_t is the actual type of the self + object. The library isolates self_t + in its own namespace, self_ns, + in order to prevent the generalized operator templates which operate on + it from being found by argument-dependent lookup in other contexts. This + should be considered an implementation detail, since users should never + have to mention self_t + directly. +

+
namespace boost { namespace python { namespace self_ns {
+{
+   unspecified-type-declaration self_t;
+
+   // inplace operators
+   template <class T> operator_<unspecified> operator+=(self_t, T);
+   template <class T> operator_<unspecified> operator-=(self_t, T);
+   template <class T> operator_<unspecified> operator*=(self_t, T);
+   template <class T> operator_<unspecified> operator/=(self_t, T);
+   template <class T> operator_<unspecified> operator%=(self_t, T);
+   template <class T> operator_<unspecified> operator>>=(self_t, T);
+   template <class T> operator_<unspecified> operator<<=(self_t, T);
+   template <class T> operator_<unspecified> operator&=(self_t, T);
+   template <class T> operator_<unspecified> operator^=(self_t, T);
+   template <class T> operator_<unspecified> operator|=(self_t, T);
+
+   // comparisons
+   template <class L, class R> operator_<unspecified> operator==(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator!=(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator<(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator>(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator<=(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator>=(L const&, R const&);
+
+   // non-member operations
+   template <class L, class R> operator_<unspecified> operator+(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator-(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator*(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator/(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator%(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator>>(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator<<(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator&(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator^(L const&, R const&);
+   template <class L, class R> operator_<unspecified> operator|(L const&, R const&);
+   template <class L, class R> operator_<unspecified> pow(L const&, R const&);
+
+   // unary operations
+   operator_<unspecified> operator-(self_t);
+   operator_<unspecified> operator+(self_t);
+   operator_<unspecified> operator~(self_t);
+   operator_<unspecified> operator!(self_t);
+
+   // value operations
+   operator_<unspecified> int_(self_t);
+   operator_<unspecified> long_(self_t);
+   operator_<unspecified> float_(self_t);
+   operator_<unspecified> complex_(self_t);
+   operator_<unspecified> str(self_t);
+
+   operator_<unspecified> repr(self_t);
+}}};
+
+

+ The tables below describe the methods generated when the results of the + expressions described are passed as arguments to class_<>::def(). + x is an object of the class + type being wrapped. +

+
+ +

+ In the table below, If r + is an object of type other<T>, + y is an object of type + T; otherwise, y is an object of the same type as + r. +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ C++ Expression +

+
+

+ Python Method Name +

+
+

+ C++ Implementation +

+
+

+ self += + r +

+
+

+ __iadd__ +

+
+

+ x += + y +

+
+

+ self -= + r +

+
+

+ __isub__ +

+
+

+ x -= + y +

+
+

+ self *= + r +

+
+

+ __imul__ +

+
+

+ x *= + y +

+
+

+ self /= + r +

+
+

+ __idiv__ +

+
+

+ x /= + y +

+
+

+ self %= + r +

+
+

+ __imod__ +

+
+

+ x %= + y +

+
+

+ self >>= + r +

+
+

+ __irshift__ +

+
+

+ x >>= + y +

+
+

+ self <<= + r +

+
+

+ __ilshift__ +

+
+

+ x <<= + y +

+
+

+ self &= + r +

+
+

+ __iand__ +

+
+

+ x &= + y +

+
+

+ self ^= + r +

+
+

+ __ixor__ +

+
+

+ x ^= + y +

+
+

+ self |= + r +

+
+

+ __ior__ +

+
+

+ x |= + y +

+
+
+
+ +

+ In the tables below, if r + is of type self_t, + y is an object of the + same type as x; if l or r + is an object of type other<T>, + y is an object of type + T; otherwise, y is an object of the same type as + l or r. + l is never of type self_t. +

+

+ The column of Python Expressions illustrates the expressions that will + be supported in Python for objects convertible to the types of x and + y. The secondary operation arises due to Python's reflection + rules for rich comparison operators, and are only used when the + corresponding operation is not defined as a method of the y object. +

+
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ C++ Expression +

+
+

+ Python Method Name +

+
+

+ C++ Implementation +

+
+

+ Python Expression (primary, secondary) +

+
+

+ self == + r +

+
+

+ __eq__ +

+
+

+ x == + y +

+
+

+ x == + y, y == + x +

+
+

+ l == + self +

+
+

+ __eq__ +

+
+

+ y == + x +

+
+

+ y == + x, x == + y +

+
+

+ self != + r +

+
+

+ __ne__ +

+
+

+ x != + y +

+
+

+ x != + y, y != + x +

+
+

+ l != + self +

+
+

+ __ne__ +

+
+

+ y != + x +

+
+

+ y != + x, x != + y +

+
+

+ self < + r +

+
+

+ __lt__ +

+
+

+ x < + y +

+
+

+ x < + y, y > + x +

+
+

+ l < + self +

+
+

+ __gt__ +

+
+

+ y < + x +

+
+

+ y > + x, x < + y +

+
+

+ self > + r +

+
+

+ __gt__ +

+
+

+ x > + y +

+
+

+ x > + y, y < + x +

+
+

+ l > + self +

+
+

+ __lt__ +

+
+

+ y > + x +

+
+

+ y < + x, x > + y +

+
+

+ self <= + r +

+
+

+ __le__ +

+
+

+ x <= + y +

+
+

+ x <= + y, y >= + x +

+
+

+ l <= + self +

+
+

+ __ge__ +

+
+

+ y <= + x +

+
+

+ y >= + x, x <= + y +

+
+

+ self >= + r +

+
+

+ __ge__ +

+
+

+ x >= + y +

+
+

+ x >= + y, y <= + x +

+
+

+ l <= + self +

+
+

+ __le__ +

+
+

+ y >= + x +

+
+

+ y <= + x, x >= + y +

+
+
+
+ +

+ The operations whose names begin with "__r" below will only + be called if the left-hand operand does not already support the given + operation, as described here. +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ C++ Expression +

+
+

+ Python Method Name +

+
+

+ C++ Implementation +

+
+

+ self + + r +

+
+

+ __add__ +

+
+

+ x + + y +

+
+

+ l + + self +

+
+

+ __radd__ +

+
+

+ y + + x +

+
+

+ self - + r +

+
+

+ __sub__ +

+
+

+ x - + y +

+
+

+ l - + self +

+
+

+ __rsub__ +

+
+

+ y - + x +

+
+

+ self * + r +

+
+

+ __mult__ +

+
+

+ x * + y +

+
+

+ l * + self +

+
+

+ __rmult__ +

+
+

+ y * + x +

+
+

+ self / + r +

+
+

+ __div__ +

+
+

+ x / + y +

+
+

+ l / + self +

+
+

+ __rdiv__ +

+
+

+ y / + x +

+
+

+ self % + r +

+
+

+ __mod__ +

+
+

+ x % + y +

+
+

+ l % + self +

+
+

+ __rmod__ +

+
+

+ y % + x +

+
+

+ self >> + r +

+
+

+ __rshift__ +

+
+

+ x >> + y +

+
+

+ l >> + self +

+
+

+ __rrshift__ +

+
+

+ y >> + x +

+
+

+ self << + r +

+
+

+ __lshift__ +

+
+

+ x << + y +

+
+

+ l << + self +

+
+

+ __rlshift__ +

+
+

+ y << + x +

+
+

+ self & + r +

+
+

+ __and__ +

+
+

+ x & + y +

+
+

+ l & + self +

+
+

+ __rand__ +

+
+

+ y & + x +

+
+

+ self ^ + r +

+
+

+ __xor__ +

+
+

+ x ^ + y +

+
+

+ l ^ + self +

+
+

+ __rxor__ +

+
+

+ y ^ + x +

+
+

+ self | + r +

+
+

+ __or__ +

+
+

+ x | + y +

+
+

+ l | + self +

+
+

+ __ror__ +

+
+

+ y | + x +

+
+

+ pow(self, + r) +

+
+

+ __pow__ +

+
+

+ x ** + y +

+
+

+ pow(l, + self) +

+
+

+ __rpow__ +

+
+

+ y ** + x +

+
+
+
+ +
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ C++ Expression +

+
+

+ Python Method Name +

+
+

+ C++ Implementation +

+
+

+ -self +

+
+

+ __neg__ +

+
+

+ -x +

+
+

+ +self +

+
+

+ __pos__ +

+
+

+ +x +

+
+

+ ~self +

+
+

+ __invert__ +

+
+

+ ~x +

+
+

+ not self + or !self +

+
+

+ __nonzero__ +

+
+

+ !!x +

+
+
+
+ +
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ C++ Expression +

+
+

+ Python Method Name +

+
+

+ C++ Implementation +

+
+

+ int_(self) +

+
+

+ __int__ +

+
+

+ long(x) +

+
+

+ long_(self) +

+
+

+ __long__ +

+
+

+ PyLong_FromLong(x) +

+
+

+ float_(self) +

+
+

+ __float__ +

+
+

+ double(x) +

+
+

+ complex_(self) +

+
+

+ __complex__ +

+
+

+ std::complex<double>(x) +

+
+

+ str(self) +

+
+

+ __str__ +

+
+

+ lexical_cast<std::string>(x) +

+
+

+ repr(self) +

+
+

+ __repr__ +

+
+

+ lexical_cast<std::string>(x) +

+
+
+
+
+ +

+ Instances of other<T> + can be used in operator expressions with self; + the result is equivalent to the same expression with a T + object in place of other<T>. Use other<T> to prevent construction of a T object in case it is heavyweight, when + no constructor is available, or simply for clarity. +

+
namespace boost { namespace python
+{
+  template <class T>
+  struct other
+  {
+  };
+}}
+
+
+
+ +

+ Instantiations of detail::operator_<> are used as the return type of + operator expressions involving self. + This should be considered an implementation detail and is only documented + here as a way of showing how the result of self-expressions match calls + to class_<>::def(). +

+
namespace boost { namespace python { namespace detail
+{
+  template <unspecified>
+  struct operator_
+  {
+  };
+}}}
+
+
+
+ +
namespace boost { namespace python
+{
+  using self_ns::self;
+}}
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/operators.hpp>
+#include <boost/operators.hpp>
+
+struct number
+   : boost::integer_arithmetic<number>
+{
+    explicit number(long x_) : x(x_) {}
+    operator long() const { return x; }
+
+    template <class T>
+    number& operator+=(T const& rhs)
+    { x += rhs; return *this; }
+
+    template <class T>
+    number& operator-=(T const& rhs)
+    { x -= rhs; return *this; }
+
+    template <class T>
+    number& operator*=(T const& rhs)
+    { x *= rhs; return *this; }
+
+    template <class T>
+    number& operator/=(T const& rhs)
+    { x /= rhs; return *this; }
+
+    template <class T>
+    number& operator%=(T const& rhs)
+    { x %= rhs; return *this; }
+
+   long x;
+};
+
+using namespace boost::python;
+BOOST_PYTHON_MODULE(demo)
+{
+   class_<number>("number", init<long>())
+      // interoperate with self
+      .def(self += self)
+      .def(self + self)
+      .def(self -= self)
+      .def(self - self)
+      .def(self *= self)
+      .def(self * self)
+      .def(self /= self)
+      .def(self / self)
+      .def(self %= self)
+      .def(self % self)
+
+      // Convert to Python int
+      .def(int_(self))
+
+      // interoperate with long
+      .def(self += long())
+      .def(self + long())
+      .def(long() + self)
+      .def(self -= long())
+      .def(self - long())
+      .def(long() - self)
+      .def(self *= long())
+      .def(self * long())
+      .def(long() * self)
+      .def(self /= long())
+      .def(self / long())
+      .def(long() / self)
+      .def(self %= long())
+      .def(self % long())
+      .def(long() % self)
+      ;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_scope_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_scope_hpp.html new file mode 100644 index 00000000..6214d914 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_scope_hpp.html @@ -0,0 +1,160 @@ + + + +boost/python/scope.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Defines facilities for querying and controlling the Python scope (namespace) + which will contain new wrapped classes and functions. +

+
+
+ +

+ The scope class has an associated global Python object which controls the + Python namespace in which new extension classes and wrapped functions will + be defined as attributes. Default-constructing a new scope object binds + it to the associated global Python object. Constructing a scope object + with an argument changes the associated global Python object to the one + held by the argument, until the lifetime of the scope object ends, at which + time the associated global Python object reverts to what it was before + the scope object was constructed. +

+
namespace boost { namespace python
+{
+  class scope : public object
+  {
+   public:
+      scope(scope const&);
+      scope(object const&);
+      scope();
+      ~scope()
+   private:
+      void operator=(scope const&);
+  };
+}}
+
+
+
+ +
explicit scope(scope const& x);
+explicit scope(object const& x);
+
+

+ Stores a reference to the current associated scope object, and sets the + associated scope object to the one referred to by x.ptr(). The object base + class is initialized with x. +

+
scope();
+

+ Stores a reference to the current associated scope object. The object base + class is initialized with the current associated scope object. Outside + any module initialization function, the current associated Python object + is None. +

+
~scope()
+

+ Sets the current associated Python object to the stored object. +

+
+
+ +

+ The following example shows how scope setting can be used to define nested + classes. +

+

+ C++ Module definition: +

+
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/scope.hpp>
+using namespace boost::python;
+
+struct X
+{
+  void f() {}
+
+  struct Y { int g() { return 42; } };
+};
+
+BOOST_PYTHON_MODULE(nested)
+{
+   // add some constants to the current (module) scope
+   scope().attr("yes") = 1;
+   scope().attr("no") = 0;
+
+   // Change the current scope 
+   scope outer
+       = class_<X>("X")
+            .def("f", &X::f)
+            ;
+
+   // Define a class Y in the current scope, X
+   class_<X::Y>("Y")
+      .def("g", &X::Y::g)
+      ;
+}
+
+

+ Interactive Python: +

+
>>> import nested
+>>> nested.yes
+1
+>>> y = nested.X.Y()
+>>> y.g()
+42
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_stl_iterator_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_stl_iterator_hpp.html new file mode 100644 index 00000000..e242d930 --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_stl_iterator_hpp.html @@ -0,0 +1,311 @@ + + + +boost/python/stl_iterator.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/stl_iterator.hpp> provides types for creating C++ Iterators + from Python + iterables. +

+
+
+ +

+ Instances of stl_input_iterator<T> hold a Python iterator and adapt it + for use with STL algorithms. stl_input_iterator<T> satisfies the requirements for an Input + Iterator. +

+
++++++ + + + + + + + + + + + + +
+

+ Template Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Default +

+
+

+ ValueType +

+
+

+ ValueType must be CopyConstructible. +

+
+

+ Dereferencing an instance of stl_input_iterator<ValueType> will return an rvalue of + type ValueType. +

+
+

+ None +

+
+
namespace boost { namespace python
+{
+  template <class ValueType>
+  struct stl_input_iterator
+  {
+      typedef std::ptrdiff_t difference_type;
+      typedef ValueType value_type;
+      typedef ValueType* pointer;
+      typedef ValueType reference;
+      typedef std::input_iterator_tag iterator_category;
+
+      stl_input_iterator();
+      stl_input_iterator(object const& ob);
+
+      stl_input_iterator& operator++();
+      stl_input_iterator operator++(int);
+
+      ValueType operator*() const;
+
+      friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs);
+      friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs);
+  private:
+      object it; // For exposition only
+      object ob; // For exposition only
+  };
+}}
+
+
+
+ +
stl_input_iterator()
+
+
+

+
+
Effects
+

+ Creates a past-the-end input iterator, useful for signifying the + end of a sequence. +

+
Postconditions
+

+ this is past-the-end +

+
Throws
+

+ Nothing. +

+
+
+
stl_input_iterator(object const& ob)
+
+

+
+
Effects
+

+ Calls ob.attr("__iter__")() and stores the resulting Python + iterator object in this->it. Then, calls this->it.attr("next")() + and stores the result in this->ob. If the sequence is exhausted, + sets this->ob to object(). +

+
Postconditions
+

+ this is a dereferenceable or past-the-end. +

+
+
+
+
+ +
stl_input_iterator &operator++()
+
+
+

+
+
Effects
+

+ Calls this->it.attr("next")() and stores the result + in this->ob. If the sequence is exhausted, sets this->ob to + object(). +

+
Postconditions
+

+ this is a dereferenceable or past-the-end. +

+
Returns
+

+ *this +

+
+
+
stl_input_iterator &operator++(int)
+
+

+
+
Effects
+

+ stl_input_iterator tmp = + *this; ++*this; return tmp; +

+
Postconditions
+

+ this is a dereferenceable or past-the-end. +

+
+
+
+
+ +
ValueType operator*() const
+
+
+

+
+
Effects
+

+ Returns the current element in the sequence. +

+
Returns
+

+ extract<ValueType>(this->ob); +

+
+
+
friend bool operator==(stl_input_iterator const& lhs, stl_input_iterator const& rhs)
+
+
+

+
+
Effects
+

+ Returns true if both iterators are dereferenceable or if both iterators + are past-the-end, false otherwise. +

+
Returns
+

+ (lhs.ob == object()) == (rhs.ob == object()) +

+
+
+
friend bool operator!=(stl_input_iterator const& lhs, stl_input_iterator const& rhs)
+
+
+

+
+
Effects
+

+ Returns false if both iterators are dereferenceable or if both iterators + are past-the-end, true otherwise. +

+
Returns
+

+ !(lhs + == rhs) +

+
+
+
+
+ +
#include <boost/python/object.hpp>
+#include <boost/python/stl_iterator.hpp>
+
+#include <list>
+
+using namespace boost::python;
+std::list<int> sequence_to_int_list(object const& ob)
+{
+    stl_input_iterator<int> begin(ob), end;
+    return std::list<int>(begin, end);
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/high_level_components/boost_python_wrapper_hpp.html b/doc/develop/html/reference/high_level_components/boost_python_wrapper_hpp.html new file mode 100644 index 00000000..a857973f --- /dev/null +++ b/doc/develop/html/reference/high_level_components/boost_python_wrapper_hpp.html @@ -0,0 +1,222 @@ + + + +boost/python/wrapper.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ To wrap a class T such that its virtual functions can be "overridden + in Python"—so that the corresponding method of a Python derived + class will be called when the virtual function is invoked from C++—you + must create a C++ wrapper class derived from T + that overrides those virtual functions so that they call into Python. This + header contains classes that can be used to make that job easier. +

+
+
+ +

+ Encapsulates a Python override of a C++ virtual function. An override object + either holds a callable Python object or None. +

+
namespace boost
+{
+  class override : object
+  {
+   public:
+      unspecified operator() const;
+      template <class A0>
+      unspecified operator(A0) const;
+      template <class A0, class A1>
+      unspecified operator(A0, A1) const;
+      ...
+      template <class A0, class A1, ...class An>
+      unspecified operator(A0, A1, ...An) const;
+  };
+};
+
+
+
+ +
unspecified operator() const;
+template <class A0>
+unspecified operator(A0) const;
+template <class A0, class A1>
+unspecified operator(A0, A1) const;
+...
+template <class A0, class A1, ...class An>
+unspecified operator(A0, A1, ...An) const;
+
+
+

+
+
Effects
+

+ If *this holds a callable Python object, it is invoked with the specified + arguments in the manner specified here. Otherwise, throws error_already_set. +

+
Returns
+

+ An object of unspecified type that holds the Python result of the + invocation and, when converted to a C++ type R, attempts to convert + that result object to R. If that conversion fails, throws error_already_set. +

+
+
+
+
+ +

+ Deriving your wrapper class from both T + and wrapper<T> + makes writing that derived class easier. +

+
namespace boost
+{
+  class wrapper
+  {
+   protected:
+      override get_override(char const* name) const;
+  };
+};
+
+
+
+ +
override get_override(char const* name) const;
+
+

+
+
Requires
+

+ name is a ntbs. +

+
Returns
+

+ If *this + is the C++ base class subobject of a Python derived class instance + that overrides the named function, returns an override object that + delegates to the Python override. Otherwise, returns an override + object that holds None. +

+
+
+
+
+ +
#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/wrapper.hpp>
+#include <boost/python/call.hpp>
+
+using namespace boost::python;
+
+// Class with one pure virtual function
+struct P
+{
+    virtual ~P(){}
+    virtual char const* f() = 0;
+    char const* g() { return "P::g()"; }
+};
+
+struct PCallback : P, wrapper<P>
+{
+    char const* f()
+    {
+        return this->get_override("f")();
+    }
+};
+
+// Class with one non-pure virtual function
+struct A
+{
+    virtual ~A(){}
+    virtual char const* f() { return "A::f()"; }
+};
+
+struct ACallback :  A, wrapper<A>
+{
+    char const* f()
+    {
+        if (override f = this->get_override("f"))
+            return f();
+        return A::f();
+    }
+
+    char const* default_f() { return this->A::f(); }
+};
+
+BOOST_PYTHON_MODULE_INIT(polymorphism)
+{
+    class_<PCallback,boost::noncopyable>("P")
+        .def("f", pure_virtual(&P::f))
+        ;
+
+    class_<ACallback,boost::noncopyable>("A")
+        .def("f", &A::f, &ACallback::default_f)
+        ;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/index.html b/doc/develop/html/reference/index.html new file mode 100644 index 00000000..ad770a94 --- /dev/null +++ b/doc/develop/html/reference/index.html @@ -0,0 +1,136 @@ + + + +Boost.Python Reference Manual + + + + + + +
+
+
Next
+
+
+
+

+Boost.Python Reference Manual

+
+

+David Abrahams +

+

+Stefan Seefeld +

+
+
+
+

+ Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt +

+
+
+
+
+
+

Table of Contents

+
+
1. Concepts
+
+
CallPolicies
+
Dereferenceable
+
Extractor
+
HolderGenerator
+
ResultConverter
+
ObjectWrapper
+
+
2. High Level Components
+
+
boost/python/class.hpp
+
boost/python/def.hpp
+
boost/python/def_visitor.hpp
+
boost/python/docstring_options.hpp
+
boost/python/enum.hpp
+
boost/python/errors.hpp
+
boost/python/exception_translator.hpp
+
boost/python/init.hpp
+
boost/python/iterator.hpp
+
boost/python/module.hpp
+
boost/python/operators.hpp
+
boost/python/scope.hpp
+
boost/python/stl_iterator.hpp
+
boost/python/wrapper.hpp
+
+
3. Object Wrappers
+
+
boost/python/dict.hpp
+
boost_python_list.hpp
+
boost/python/long.hpp
+
boost/python/object.hpp
+
boost/python/str.hpp
+
boost/python/slice.hpp
+
boost/python/tuple.hpp
+
+
4. Function Invocation and Creation
+
+
boost/python/args.hpp
+
boost/python/call.hpp
+
boost/python/call_method.hpp
+
boost/python/data_members.hpp
+
boost/python/make_function.hpp
+
boost/python/overloads.hpp
+
boost/python/ptr.hpp
+
boost/python/raw_function.hpp
+
Function + documentation
+
Models + of CallPolicies
+
Models + of ResultConverter
+
Models + of ResultConverterGenerator
+
+
5. To/From Python Type Conversion
+
+
boost/python/extract.hpp
+
boost/python/implicit.hpp
+
boost/python/lvalue_from_pytype.hpp
+
boost/python/opaque_pointer_converter.hpp
+
boost/python/to_python_converter.hpp
+
boost/python/register_ptr_to_python.hpp
+
+
6. Embedding
+
+
boost/python/exec.hpp
+
boost/python/import.hpp
+
+
7. Utility and Infrastructure
+
+
boost/python/has_back_reference.hpp
+
boost/python/instance_holder.hpp
+
boost/python/pointee.hpp
+
boost/python/handle.hpp
+
boost/python/type_id.hpp
+
boost/python/ssize_t.hpp
+
+
8. Topics
+
+
Calling Python + Functions and Methods
+
Pickle support
+
Indexing support
+
+
9. Glossary
+
+
+
+ + + +

Last revised: December 25, 2020 at 18:34:33 GMT

+
+
Next
+ + diff --git a/doc/develop/html/reference/object_wrappers.html b/doc/develop/html/reference/object_wrappers.html new file mode 100644 index 00000000..e0d08e76 --- /dev/null +++ b/doc/develop/html/reference/object_wrappers.html @@ -0,0 +1,249 @@ + + + +Chapter 3. Object Wrappers + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 3. Object Wrappers

+ +
+ + +
+ +

+ Exposes a TypeWrapper + for the Python dict type. +

+
+
+ +

+ Exposes the mapping + protocol of Python's built-in dict + type. The semantics of the constructors and member functions defined below + can be fully understood by reading the TypeWrapper + concept definition. Since dict + is publicly derived from object, the public object interface applies to dict instances as well. +

+
namespace boost { namespace python
+{
+   class dict : public object
+   {
+      dict();
+
+      template< class T >
+      dict(T const & data);
+
+      // modifiers
+      void clear();
+      dict copy();
+
+      template <class T1, class T2>
+      tuple popitem();
+
+      template <class T>
+      object setdefault(T const &k);
+
+      template <class T1, class T2>
+      object setdefault(T1 const & k, T2 const & d);
+
+      void update(object_cref E);
+
+      template< class T >
+      void update(T const & E);
+
+      // observers
+      list values() const;
+
+      object get(object_cref k) const;
+
+      template<class T>
+      object get(T const & k) const;
+
+      object get(object_cref k, object_cref d) const;
+      object get(T1 const & k, T2 const & d) const;
+
+      bool has_key(object_cref k) const;
+
+      template< class T >
+      bool has_key(T const & k) const;
+
+      list items() const;
+      object iteritems() const;
+      object iterkeys() const;
+      object itervalues() const;
+      list keys() const;
+  };
+}}
+
+
+
+ +
using namespace boost::python;
+dict swap_object_dict(object target, dict d)
+{
+    dict result = extract<dict>(target.attr("__dict__"));
+    target.attr("__dict__") = d;
+    return result;
+}
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/object_wrappers/boost_python_list_hpp.html b/doc/develop/html/reference/object_wrappers/boost_python_list_hpp.html new file mode 100644 index 00000000..657fa1fd --- /dev/null +++ b/doc/develop/html/reference/object_wrappers/boost_python_list_hpp.html @@ -0,0 +1,120 @@ + + + +boost_python_list.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Exposes a TypeWrapper + for the Python list + type. +

+
+
+ +

+ Exposes the mapping + protocol of Python's built-in list + type. The semantics of the constructors and member functions defined below + can be fully understood by reading the TypeWrapper + concept definition. Since list + is publicly derived from object, the public object interface applies to list instances as well. +

+
namespace boost { namespace python
+{
+  class list : public object
+  {
+   public:
+      list(); // new list
+
+      template <class T>
+      explicit list(T const& sequence);
+
+      template <class T>
+      void append(T const& x);
+
+      template <class T>
+      long count(T const& value) const;
+
+      template <class T>
+      void extend(T const& x);
+
+      template <class T>
+      long index(T const& x) const;
+
+      template <class T>
+      void insert(object const& index, T const& x); // insert object before index
+
+      object pop(); // remove and return item at index (default last)
+      object pop(long index);
+      object pop(object const& index);
+
+      template <class T>
+      void remove(T const& value);
+
+      void reverse(); // reverse *IN PLACE*
+
+      void sort(); //  sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
+
+      template <class T>
+      void sort(T const& value);
+  };
+}}
+
+
+
+ +
using namespace boost::python;
+
+// Return the number of zeroes in the list
+long zeroes(list l)
+{
+   return l.count(0);
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/object_wrappers/boost_python_long_hpp.html b/doc/develop/html/reference/object_wrappers/boost_python_long_hpp.html new file mode 100644 index 00000000..253f0c81 --- /dev/null +++ b/doc/develop/html/reference/object_wrappers/boost_python_long_hpp.html @@ -0,0 +1,97 @@ + + + +boost/python/long.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Exposes a TypeWrapper + for the Python long + integer type. +

+
+
+ +

+ Exposes the numeric + type protocol of Python's built-in long + type. The semantics of the constructors and member functions defined below + can be fully understood by reading the TypeWrapper + concept definition. Since long_ + is publicly derived from object, the public object interface applies to long_ instances as well. +

+
namespace boost { namespace python
+{
+  class long_ : public object
+  {
+   public:
+      long_(); // new long_
+
+      template <class T>
+      explicit long_(T const& rhs);
+
+      template <class T, class U>
+      long_(T const& rhs, U const& base);
+  };
+}}
+
+
+
+ +
namespace python = boost::python;
+
+// compute a factorial without overflowing
+python::long_ fact(long n)
+{
+   if (n == 0)
+      return python::long_(1);
+   else
+      return n * fact(n - 1);
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/object_wrappers/boost_python_object_hpp.html b/doc/develop/html/reference/object_wrappers/boost_python_object_hpp.html new file mode 100644 index 00000000..4f89cc98 --- /dev/null +++ b/doc/develop/html/reference/object_wrappers/boost_python_object_hpp.html @@ -0,0 +1,1148 @@ + + + +boost/python/object.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Exposes the generic Python object wrapper class object, and related classes. + In order to avoid some potenential problems with argument-dependent lookup + and the generalized operators defined on object, all these facilities are + defined in namespace boost::python::api, and object is imported into namespace + boost::python with a using-declaration. +

+
+
+ +
class slice_nil;
+static const _ = slice_nil();
+
+

+ A type that can be used to get the effect of leaving out an index in a + Python slice expression: +

+
>>> x[:-1]
+>>> x[::-1]
+
+

+ C++ equivalent: +

+
x.slice(_,-1)
+x[slice(_,_,-1)]
+
+
+
+ +

+ The policies which are used for proxies representing an attribute access + to a const object. +

+
namespace boost { namespace python { namespace api
+{
+  struct const_attribute_policies
+  {
+      typedef char const* key_type;
+      static object get(object const& target, char const* key);
+  };
+}}}
+
+
+
+ +
static object get(object const& target, char const* key);
+
+
+

+
+
Requires
+

+ key is an ntbs. +

+
Effects
+

+ accesses the attribute of target named by key. +

+
Returns
+

+ An object managing the result of the attribute access. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an attribute access + to a mutable object. +

+
namespace boost { namespace python { namespace api
+{
+  struct attribute_policies : const_attribute_policies
+  {
+      static object const& set(object const& target, char const* key, object const& value);
+      static void del(object const&target, char const* key);
+  };
+}}}
+
+
+
+ +
static object const& set(object const& target, char const* key, object const& value);
+
+
+

+
+
Requires
+

+ key is an ntbs. +

+
Effects
+

+ sets the attribute of target named by key to value. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
static void del(object const&target, char const* key);
+
+
+

+
+
Requires
+

+ key is an ntbs. +

+
Effects
+

+ deletes the attribute of target named by key. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an attribute access + to a const object when the attribute name is given as a const object. +

+
namespace boost { namespace python { namespace api
+{
+  struct const_objattribute_policies
+  {
+      typedef object const& key_type;
+      static object get(object const& target, object const& key);
+  };
+}}}
+
+
+
+ +
static object get(object const& target, object const& key);
+
+
+

+
+
Requires
+

+ key is an object holding a string. +

+
Effects
+

+ accesses the attribute of target named by key. +

+
Returns
+

+ An object managing the result of the attribute access. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an attribute access + to a mutable object when the attribute name is given as a const object. +

+
namespace boost { namespace python { namespace api
+{
+  struct objattribute_policies : const_objattribute_policies
+  {
+      static object const& set(object const& target, object const& key, object const& value);
+      static void del(object const&target, object const& key);
+  };
+}}}
+
+
+
+ +
static object const& set(object const& target, object const& key, object const& value);
+
+
+

+
+
Requires
+

+ key is an object holding a string. +

+
Effects
+

+ sets the attribute of target named by key to value. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
static void del(object const&target, object const& key);
+
+
+

+
+
Requires
+

+ key is an object holding a string. +

+
Effects
+

+ deletes the attribute of target named by key. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an item access (via + the Python bracket operators []) to a const object. +

+
namespace boost { namespace python { namespace api
+{
+  struct const_item_policies
+  {
+      typedef object key_type;
+      static object get(object const& target, object const& key);
+  };
+}}}
+
+
+
+ +
static object get(object const& target, object const& key);
+
+
+

+
+
Effects
+

+ accesses the item of target specified by key. +

+
Returns
+

+ An object managing the result of the item access. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an item access (via + the Python bracket operators []) to a mutable object. +

+
namespace boost { namespace python { namespace api
+{
+  struct item_policies : const_item_policies
+  {
+      static object const& set(object const& target, object const& key, object const& value);
+      static void del(object const& target, object const& key);
+  };
+}}}
+
+
+
+ +
static object const& set(object const& target, object const& key, object const& value);
+
+
+

+
+
Effects
+

+ sets the item of target specified by key to value. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
static void del(object const& target, object const& key);
+
+
+

+
+
Effects
+

+ deletes the item of target specified by key. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an slice access (via + the Python slice notation [x:y]) to a const object. +

+
namespace boost { namespace python { namespace api
+{
+  struct const_slice_policies
+  {
+      typedef std::pair<handle<>, handle<> > key_type;
+      static object get(object const& target, key_type const& key);
+  };
+}}}
+
+
+
+ +
static object get(object const& target, key_type const& key);
+
+
+

+
+
Effects
+

+ accesses the slice of target specified by key. +

+
Returns
+

+ An object managing the result of the slice access. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ The policies which are used for proxies representing an slice access to + a mutable object. +

+
namespace boost { namespace python { namespace api
+{
+  struct slice_policies : const_slice_policies
+  {
+      static object const& set(object const& target, key_type const& key, object const& value);
+      static void del(object const& target, key_type const& key);
+  };
+}}}
+
+
+
+ +
static object const& set(object const& target, key_type const& key, object const& value);
+
+
+

+
+
Effects
+

+ sets the slice of target specified by key to value. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
static void del(object const& target, key_type const& key);
+
+
+

+
+
Effects
+

+ deletes the slice of target specified by key. +

+
Throws
+

+ error_already_set + if a Python exception is raised. +

+
+
+
+
+ +

+ This is the base class of object and its proxy template used to supply + common interface: member functions, and operators which must be defined + within the class body. Its template parameter U is expected to be a class + derived from object_operators<U>. In practice users should never + use this class directly, but it is documented here because it supplies + important interface to object and its proxies. +

+
namespace boost { namespace python { namespace api
+{
+  template <class U>
+  class object_operators
+  {
+   public:
+      // function call
+      //
+      object operator()() const;
+
+      template <class A0>
+      object operator()(A0 const&) const;
+      template <class A0, class A1>
+      object operator()(A0 const&, A1 const&) const;
+      ...
+      template <class A0, class A1,...class An>
+      object operator()(A0 const&, A1 const&,...An const&) const;
+
+      detail::args_proxy operator* () const;
+      object operator()(detail::args_proxy const &args) const;
+      object operator()(detail::args_proxy const &args,
+                        detail::kwds_proxy const &kwds) const;
+
+      // truth value testing
+      //
+      typedef unspecified bool_type;
+      operator bool_type() const;
+
+      // Attribute access
+      //
+      proxy<const_object_attribute> attr(char const*) const;
+      proxy<object_attribute> attr(char const*);
+      proxy<const_object_objattribute> attr(object const&) const;
+      proxy<object_objattribute> attr(object const&);
+
+      // item access
+      //
+      template <class T>
+      proxy<const_object_item> operator[](T const& key) const;
+
+      template <class T>
+      proxy<object_item> operator[](T const& key);
+
+      // slicing
+      //
+      template <class T, class V>
+      proxy<const_object_slice> slice(T const& start, V const& end) const
+
+      template <class T, class V>
+      proxy<object_slice> slice(T const& start, V const& end);
+  };
+}}}
+
+
+
+ +
object operator()() const;
+template <class A0>
+object operator()(A0 const&) const;
+template <class A0, class A1>
+object operator()(A0 const&, A1 const&) const;
+...
+template <class A0, class A1,...class An>
+object operator()(A0 const& a1, A1 const& a2,...An const& aN) const;
+
+
+

+
+
Effects
+

+ call<object>(object(*static_cast<U*>(this)).ptr(), + a1, + a2,...aN) +

+
+
+
object operator()(detail::args_proxy const &args) const;
+
+

+
+
Effects
+

+ call object + with arguments + given by + the tuple + args +

+
+
+
object operator()(detail::args_proxy const &args,
+                  detail::kwds_proxy const &kwds) const;
+
+
+

+
+
Effects
+

+ call object + with arguments + given by + the tuple + args, + and named + arguments given + by the + dictionary kwds +

+
+
+
operator bool_type() const;
+
+

+
+
Effects
+

+ Tests truth value of *this. +

+
Returns
+

+ call<object>(object(*static_cast<U*>(this)).ptr(), + a1, + a2,...aN) +

+
+
+
proxy<const_object_attribute> attr(char const* name) const;
+proxy<object_attribute> attr(char const* name);
+
+
+

+
+
Requires
+

+ name is an ntbs. +

+
Effects
+

+ accesses the named attribute of *this. +

+
Returns
+

+ a proxy object which binds object(*static_cast<U*>(this)) as its target, and name as its + key. +

+
+
+
proxy<const_object_objattribute> attr(const object& name) const;
+proxy<object_objattribute> attr(const object& name);
+
+
+

+
+
Requires
+

+ name is a object holding a string. +

+
Effects
+

+ accesses the named attribute of *this. +

+
Returns
+

+ a proxy object which binds object(*static_cast<U*>(this)) as its target, and name as its + key. +

+
+
+
template <class T>
+proxy<const_object_item> operator[](T const& key) const;
+template <class T>
+proxy<object_item> operator[](T const& key);
+
+
+

+
+
Effects
+

+ accesses the item of *this indicated by key. +

+
Returns
+

+ a proxy object which binds object(*static_cast<U*>(this)) as its target, and object(key) + as its key. +

+
+
+
template <class T, class V>
+proxy<const_object_slice> slice(T const& start; start, V const& finish) const
+template <class T, class V>
+proxy<object_slice> slice(T const& start; start, V const& finish);
+
+
+

+
+
Effects
+

+ accesses the slice of *this indicated by std::make_pair(object(start), object(finish)). +

+
Returns
+

+ a proxy object which binds object(*static_cast<U*>(this)) as its target, and std::make_pair(object(start), + object(finish)) + as its key. +

+
+
+
+
+ +

+ The intention is that object acts as much like a Python variable as possible. + Thus expressions you'd expect to work in Python should generally work in + the same way from C++. Most of object's interface is provided by its base + class object_operators<object>, and the free functions defined in + this header. +

+
namespace boost { namespace python { namespace api
+{
+  class object : public object_operators<object>
+  {
+   public:
+      object();
+      object(object const&);
+      template <class T>
+      explicit object(T const& x);
+
+      ~object();
+
+      object& operator=(object const&);
+      PyObject* ptr() const;
+      bool is_none() const;
+  };
+}}}
+
+
+
+ +
object();
+
+

+
+
Effects
+

+ Constructs an object managing a reference to the Python None object. +

+
Throws
+

+ nothing. +

+
+
+
template <class T>
+explicit object(T const& x);
+
+
+

+
+
Effects
+

+ converts x to python and manages a reference to it. +

+
Throws
+

+ error_already_set + and sets a Python TypeError exception if no such conversion is possible. +

+
+
+
~object();
+
+
+

+
+
Effects
+

+ decrements the reference count of the internally-held object. +

+
+
+
+
+ +
PyObject* ptr() const;
+
+

+
+
Returns
+

+ a pointer to the internally-held Python object. +

+
+
+
bool is_none() const;
+
+

+
+
Returns
+

+ result of (ptr() == Py_None) +

+
+
+
+
+ +

+ This template is instantiated with various Policies described in this document + in order to implement attribute, item, and slice access for object. It + stores an object of type Policies::key_type. +

+
namespace boost { namespace python { namespace api
+{
+  template <class Policies>
+  class proxy : public object_operators<proxy<Policies> >
+  {
+   public:
+      operator object() const;
+
+      proxy const& operator=(proxy const&) const;
+      template <class T>
+      inline proxy const& operator=(T const& rhs) const;
+
+      void del() const;
+
+      template <class R>
+      proxy operator+=(R const& rhs);
+      template <class R>
+      proxy operator-=(R const& rhs);
+      template <class R>
+      proxy operator*=(R const& rhs);
+      template <class R>
+      proxy operator/=(R const& rhs);
+      template <class R>
+      proxy operator%=(R const& rhs);
+      template <class R>
+      proxy operator<<=(R const& rhs);
+      template <class R>
+      proxy operator>>=(R const& rhs);
+      template <class R>
+      proxy operator&=(R const& rhs);
+      template <class R>
+      proxy operator|=(R const& rhs);
+  };
+}}}
+
+
+
+ +
operator object() const;
+
+

+
+
Effects
+

+ applies Policies::get(target, key) with the proxy's target and key + objects. +

+
+
+
+
+ +
proxy const& operator=(proxy const& rhs) const;
+template <class T>
+inline proxy const& operator=(T const& rhs) const;
+
+
+

+
+
Effects
+

+ Policies::set(target, + key , + object(rhs)) + with the proxy's target and key objects. +

+
+
+
template <class R>
+proxy operator+=(R const& rhs);
+template <class R>
+proxy operator-=(R const& rhs);
+template <class R>
+proxy operator*=(R const& rhs);
+template <class R>
+proxy operator/=(R const& rhs);
+template <class R>
+proxy operator%=(R const& rhs);
+template <class R>
+proxy operator<<=(R const& rhs);
+template <class R>
+proxy operator>>=(R const& rhs);
+template <class R>
+proxy operator&=(R const& rhs);
+template <class R>
+proxy operator|=(R const& rhs);
+
+
+

+
+
Effects
+

+ for a given operator@=, + object(*this) @= rhs; +

+
Returns
+

+ *this +

+
+
+
void del() const;
+
+

+
+
Effects
+

+ Policies::del(target, key ) with the proxy's target and key objects. +

+
+
+
+
+ +
template <class T>
+void del(proxy<T> const& x);
+
+
+

+
+
Effects
+

+ x.del() +

+
+
+
template<class L,class R> object operator>(L const&l,R const&r);
+template<class L,class R> object operator>=(L const&l,R const&r);
+template<class L,class R> object operator<(L const&l,R const&r);
+template<class L,class R> object operator<=(L const&l,R const&r);
+template<class L,class R> object operator==(L const&l,R const&r);
+template<class L,class R> object operator!=(L const&l,R const&r);
+
+
+

+
+
Effects
+

+ returns the result of applying the operator to object(l) and object(r), respectively, in Python. +

+
+
+
template<class L,class R> object operator+(L const&l,R const&r);
+template<class L,class R> object operator-(L const&l,R const&r);
+template<class L,class R> object operator*(L const&l,R const&r);
+template<class L,class R> object operator/(L const&l,R const&r);
+template<class L,class R> object operator%(L const&l,R const&r);
+template<class L,class R> object operator<<(L const&l,R const&r);
+template<class L,class R> object operator>>(L const&l,R const&r);
+template<class L,class R> object operator&(L const&l,R const&r);
+template<class L,class R> object operator^(L const&l,R const&r);
+template<class L,class R> object operator|(L const&l,R const&r);
+
+
+

+
+
Effects
+

+ returns the result of applying the operator to object(l) and object(r), respectively, in Python. +

+
+
+
template<class R> object& operator+=(object&l,R const&r);
+template<class R> object& operator-=(object&l,R const&r);
+template<class R> object& operator*=(object&l,R const&r);
+template<class R> object& operator/=(object&l,R const&r);
+template<class R> object& operator%=(object&l,R const&r);
+template<class R> object& operator<<=(object&l,R const&r)
+template<class R> object& operator>>=(object&l,R const&r);
+template<class R> object& operator&=(object&l,R const&r);
+template<class R> object& operator^=(object&l,R const&r);
+template<class R> object& operator|=(object&l,R const&r);
+
+
+

+
+
Effects
+

+ assigns to l the + result of applying the corresponding Python inplace operator to + l and object(r), + respectively. +

+
Returns
+

+ l +

+
+
+
long len(object const& obj);
+
+

+
+
Effects
+

+ PyObject_Length(obj.ptr()) +

+
Returns
+

+ len() + of object. +

+
+
+
+
+ +

+ Python code: +

+
def sum_items(seq):
+   result = 0
+   for x in seq:
+      result += x
+   return result
+
+

+ C++ version +

+
object sum_items(object seq)
+{
+   object result = object(0);
+   for (int i = 0; i < len(seq); ++i)
+      result += seq[i];
+   return result;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/object_wrappers/boost_python_slice_hpp.html b/doc/develop/html/reference/object_wrappers/boost_python_slice_hpp.html new file mode 100644 index 00000000..b979a93e --- /dev/null +++ b/doc/develop/html/reference/object_wrappers/boost_python_slice_hpp.html @@ -0,0 +1,297 @@ + + + +boost/python/slice.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Exposes a TypeWrapper + for the Python slice type. +

+
+
+ +

+ Exposes the extended slicing protocol by wrapping the built-in slice type. + The semantics of the constructors and member functions defined below can + be fully understood by reading the TypeWrapper + concept definition. Since slice + is publicly derived from object, the public object interface applies to slice instances as well. +

+
namespace boost { namespace python
+{
+  class slice : public object
+  {
+   public:
+      slice(); // create an empty slice, equivalent to [::]
+
+      template <typename Int1, typename Int2>
+      slice(Int1 start, Int2 stop);
+
+      template <typename Int1, typename Int2, typename Int3>
+      slice(Int1 start, Int2 stop, Int3 step);
+
+      // Access the parameters this slice was created with.
+      object start();
+      object stop();
+      object step();
+
+      // The return type of slice::get_indices()
+      template <typename RandomAccessIterator>
+      struct range
+      {
+          RandomAccessIterator start;
+          RandomAccessIterator stop;
+          int step;
+      };
+
+      template <typename RandomAccessIterator>
+      range<RandomAccessIterator>
+      get_indices(
+          RandomAccessIterator const& begin,
+          RandomAccessIterator const& end);
+  };
+}}
+
+
+
+ +
slice();
+
+

+
+
Effects
+

+ constructs a slice with default stop, start, and step values. Equivalent + to the slice object created as part of the Python expression base[::]. +

+
Throws
+

+ nothing +

+
+
+
template <typename Int1, typename Int2>
+slice(Int1 start, Int2 stop);
+
+
+

+
+
Requires
+

+ start, stop, and step + are of type slice_nil + or convertible to type object. +

+
Effects
+

+ constructs a new slice with default step value and the provided start + and stop values. Equivalent to the slice object created by the built-in + Python function slice(start,stop), or as part of the Python expression + base[start:stop]. +

+
Throws
+

+ error_already_set + and sets a Python TypeError exception if no conversion is possible + from the arguments to type object. +

+
+
+
template <typename Int1, typename Int2, typename Int3>
+slice(Int1 start, Int2 stop, Int3 step);
+
+
+

+
+
Requires
+

+ start, stop, and step + are slice_nil or + convertible to type object. +

+
Effects
+

+ constructs a new slice with start stop and step values. Equivalent + to the slice object created by the built-in Python function slice(start,stop,step), + or as part of the Python expression base[start:stop:step]. +

+
Throws
+

+ error_already_set + and sets a Python TypeError exception if no conversion is possible + from the arguments to type object. +

+
+
+
+
+ +
object slice::start() const;
+object slice::stop() const;
+object slice::step() const;
+
+
+

+
+
Effects
+

+ None +

+
Throws
+

+ nothing +

+
Returns
+

+ the parameter that the slice was created with. If the parameter was + omitted or slice_nil + was used when the slice was created, than that parameter will be + a reference to PyNone + and compare equal to a default-constructed object. In principal, + any object may be used when creating a slice object, but in practice + they are usually integers. +

+
+
+
template <typename RandomAccessIterator>
+slice::range<RandomAccessIterator>
+slice::get_indices(
+    RandomAccessIterator const& begin,
+    RandomAccessIterator const& end) const;
+
+
+

+
+
Arguments
+

+ A pair of STL-conforming Random Access Iterators that form a half-open + range. +

+
Effects
+

+ Create a RandomAccessIterator pair that defines a fully-closed range + within the [begin,end) range of its arguments. This function + translates this slice's indices while accounting for the effects + of any PyNone or negative indices, and non-singular step sizes. +

+
Returns
+

+ a slice::range that has been initialized + with a non-zero value of step and a pair of RandomAccessIterators + that point within the range of this functions arguments and define + a closed interval. +

+
Throws
+

+ Raises a Python TypeError exception if any of this slice's arguments + are neither references to PyNone nor convertible to int. Throws + std::invalid_argument if the resulting + range would be empty. You should always wrap calls to slice::get_indices() + within try { + ...; } + catch (std::invalid_argument) + {} to handle this case and + take appropriate action. +

+
Rationale
+

+ closed-interval: If an open interval were used, then for step size + other than 1, the required state for the end iterator would point + beyond the one-past-the-end position or before the beginning of the + specified range. exceptions on empty slice: It is impossible to define + a closed interval over an empty range, so some other form of error + checking would have to be used to prevent undefined behavior. In + the case where the exception is not caught, it will simply be translated + to Python by the default exception handling mechanisms. +

+
+
+
+
+ +
using namespace boost::python;
+
+// Perform an extended slice of a Python list.
+// Warning: extended slicing was not supported for built-in types prior 
+// to Python 2.3
+list odd_elements(list l)
+{
+    return l[slice(_,_,2)];
+}
+
+// Perform a summation over a slice of a std::vector.
+double partial_sum(std::vector<double> const& Foo, const slice index)
+{
+    slice::range<std::vector<double>::const_iterator> bounds;
+    try {
+        bounds = index.get_indices<>(Foo.begin(), Foo.end());
+    }
+    catch (std::invalid_argument) {
+        return 0.0;
+    }
+    double sum = 0.0;
+    while (bounds.start != bounds.stop) {
+        sum += *bounds.start;
+        std::advance( bounds.start, bounds.step);
+    }
+    sum += *bounds.start;
+    return sum;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/object_wrappers/boost_python_str_hpp.html b/doc/develop/html/reference/object_wrappers/boost_python_str_hpp.html new file mode 100644 index 00000000..5cd6b2ee --- /dev/null +++ b/doc/develop/html/reference/object_wrappers/boost_python_str_hpp.html @@ -0,0 +1,211 @@ + + + +boost/python/str.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Exposes a TypeWrapper + for the Python str type. +

+
+
+ +

+ Exposes the string + methods of Python's built-in str + type. The semantics of the constructors and member functions defined below, + except for the two-argument constructors which construct str objects from + a range of characters, can be fully understood by reading the TypeWrapper + concept definition. Since str is publicly derived from object, the public object interface applies to str instances as well. +

+
namespace boost { namespace python
+{
+  class str : public object
+  {
+   public:
+      str(); // new str
+
+      str(char const* s); // new str
+
+      str(char const* start, char const* finish); // new str
+      str(char const* start, std::size_t length); // new str
+
+      template <class T>
+      explicit str(T const& other);
+
+      str capitalize() const;
+
+      template <class T>
+      str center(T const& width) const;
+
+      template<class T>
+      long count(T const& sub) const;
+      template<class T1, class T2>
+      long count(T1 const& sub,T2 const& start) const;
+      template<class T1, class T2, class T3>
+      long count(T1 const& sub,T2 const& start, T3 const& end) const;
+
+      object decode() const;
+      template<class T>
+      object decode(T const& encoding) const;
+      template<class T1, class T2>
+      object decode(T1 const& encoding, T2 const& errors) const;
+
+      object encode() const;
+      template <class T>
+      object encode(T const& encoding) const;
+      template <class T1, class T2>
+      object encode(T1 const& encoding, T2 const& errors) const;
+
+      template <class T>
+      bool endswith(T const& suffix) const;
+      template <class T1, class T2>
+      bool endswith(T1 const& suffix, T2 const& start) const;
+      template <class T1, class T2, class T3>
+      bool endswith(T1 const& suffix, T2 const& start, T3 const& end) const;
+
+      str expandtabs() const;
+      template <class T>
+      str expandtabs(T const& tabsize) const;
+
+      template <class T>
+      long find(T const& sub) const;
+      template <class T1, class T2>
+      long find(T1 const& sub, T2 const& start) const;
+      template <class T1, class T2, class T3>
+      long find(T1 const& sub, T2 const& start, T3 const& end) const;
+
+      template <class T>
+      long index(T const& sub) const;
+      template <class T1, class T2>
+      long index(T1 const& sub, T2 const& start) const;
+      template <class T1, class T2, class T3>
+      long index(T1 const& sub, T2 const& start, T3 const& end) const;
+
+      bool isalnum() const;
+      bool isalpha() const;
+      bool isdigit() const;
+      bool islower() const;
+      bool isspace() const;
+      bool istitle() const;
+      bool isupper() const;
+
+      template <class T>
+      str join(T const& sequence) const;
+
+      template <class T>
+      str ljust(T const& width) const;
+
+      str lower() const;
+      str lstrip() const;
+
+      template <class T1, class T2>
+      str replace(T1 const& old, T2 const& new_) const;
+      template <class T1, class T2, class T3>
+      str replace(T1 const& old, T2 const& new_, T3 const& maxsplit) const;
+
+      template <class T>
+      long rfind(T const& sub) const;
+      template <class T1, class T2>
+      long rfind(T1 const& sub, T2 const& start) const;
+      template <class T1, class T2, class T3>
+      long rfind(T1 const& sub, T2 const& start, T3 const& end) const;
+
+      template <class T>
+      long rindex(T const& sub) const;
+      template <class T1, class T2>
+      long rindex(T1 const& sub, T2 const& start) const;
+      template <class T1, class T2, class T3>
+      long rindex(T1 const& sub, T2 const& start, T3 const& end) const;
+
+      template <class T>
+      str rjust(T const& width) const;
+
+      str rstrip() const;
+
+      list split() const;
+      template <class T>
+      list split(T const& sep) const;
+      template <class T1, class T2>
+      list split(T1 const& sep, T2 const& maxsplit) const;
+
+      list splitlines() const;
+      template <class T>
+      list splitlines(T const& keepends) const;
+
+      template <class T>
+      bool startswith(T const& prefix) const;
+      template <class T1, class T2>
+      bool startswidth(T1 const& prefix, T2 const& start) const;
+      template <class T1, class T2, class T3>
+      bool startswidth(T1 const& prefix, T2 const& start, T3 const& end) const;
+
+      str strip() const;
+      str swapcase() const;
+      str title() const;
+
+      template <class T>
+      str translate(T const& table) const;
+      template <class T1, class T2>
+      str translate(T1 const& table, T2 const& deletechars) const;
+
+      str upper() const;
+  };
+}}
+
+
+
+ +
using namespace boost::python;
+str remove_angle_brackets(str x)
+{
+  return x.strip('<').strip('>');
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/object_wrappers/boost_python_tuple_hpp.html b/doc/develop/html/reference/object_wrappers/boost_python_tuple_hpp.html new file mode 100644 index 00000000..9de2bed0 --- /dev/null +++ b/doc/develop/html/reference/object_wrappers/boost_python_tuple_hpp.html @@ -0,0 +1,119 @@ + + + +boost/python/tuple.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + + +
+ +

+ Exposes the interface of Python's built-in tuple type. The semantics of + the constructors and member functions defined below can be fully understood + by reading the TypeWrapper + concept definition. Since tuple is publicly derived from object, the public object interface applies to tuple instances as well. +

+
namespace boost { namespace python
+{
+   class tuple : public object
+   {
+      // tuple() -> an empty tuple
+      tuple();
+
+      // tuple(sequence) -> tuple initialized from sequence's items
+      template <class T>
+      explicit tuple(T const& sequence)
+  };
+}}
+
+
+
+ +
namespace boost { namespace python
+{
+  tuple make_tuple();
+
+  template <class A0>
+  tuple make_tuple(A0 const& a0);
+
+  template <class A0, class A1>
+  tuple make_tuple(A0 const& a0, A1 const& a1);
+  ...
+  template <class A0, class A1,...class An>
+  tuple make_tuple(A0 const& a0, A1 const& a1,...An const& an);
+}}
+
+
+

+
+
Effect
+

+ Constructs a new tuple object composed of object(a0), object(a0),...object(an). +

+
+
+
+
+ +
using namespace boost::python;
+tuple head_and_tail(object sequence)
+{
+    return make_tuple(sequence[0],sequence[-1]);
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/to_from_python_type_conversion.html b/doc/develop/html/reference/to_from_python_type_conversion.html new file mode 100644 index 00000000..ce85ab3e --- /dev/null +++ b/doc/develop/html/reference/to_from_python_type_conversion.html @@ -0,0 +1,287 @@ + + + +Chapter 5. To/From Python Type Conversion + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 5. To/From Python Type Conversion

+ +
+ + +
+ +

+ Exposes a mechanism for extracting C++ object values from generalized Python + objects. Note that extract<...> can also be used to "downcast" + an object to some specific ObjectWrapper. Because invoking + a mutable python type with an argument of the same type (e.g. list([1,2]) typically makes a copy of the argument + object, this may be the only way to access the ObjectWrapper's + interface on the original object. +

+
+
+ +

+ extract<T> + can be used to extract a value of an arbitrary C++ type from an instance + of object. + Two usages are supported: +

+
    +
  1. + extract<T>(o) + is a temporary object which is implicitly convertible to T (explicit conversion is also available + through the object's function-call operator). However, if no conversion + is available which can convert o to an object of type T, a Python TypeError exception will + be raised. +
  2. +
  3. + extract<T> x(o); + constructs an extractor whose check() member function can be used to ask + whether a conversion is available without causing an exception to be + thrown. +
  4. +
+
namespace boost { namespace python
+{
+  template <class T>
+  struct extract
+  {
+      typedef unspecified result_type;
+
+      extract(PyObject*);
+      extract(object const&);
+
+      result_type operator()() const;
+      operator result_type() const;
+
+      bool check() const;
+  };
+}}
+
+
+
+ +
extract(PyObject* p);
+extract(object const&);
+
+
+

+
+
Requires
+

+ The first form requires that p is non-null. +

+
Effects
+

+ Stores a pointer to the Python object managed by its constructor + argument. In particular, the reference count of the object is not + incremented. The onus is on the user to be sure it is not destroyed + before the extractor's conversion function is called. +

+
+
+
+
+ +
result_type operator()() const;
+operator result_type() const;
+
+
+

+
+
Effects
+

+ Converts the stored pointer to result_type, which is either T or + T const&. +

+
Returns
+

+ An object of result_type corresponding to the one referenced by the + stored pointer. +

+
Throws
+

+ error_already_set and sets + a TypeError if no + such conversion is available. May also emit other unspecified exceptions + thrown by the converter which is actually used. +

+
+
+
bool check() const;
+
+

+
+
Postconditions
+

+ None. In particular, note that a return value of true does not preclude + an exception being thrown from operator result_type() or operator()(). +

+
Returns
+

+ false only if no conversion from the stored pointer to T is available. +

+
+
+
+
+ +
#include <cstdio>
+using namespace boost::python;
+int Print(str s)
+{
+   // extract a C string from the Python string object
+   char const* c_str = extract<char const*>(s);
+
+   // Print it using printf
+   std::printf("%s\n", c_str);
+
+   // Get the Python string's length and convert it to an int
+   return extract<int>(s.attr("__len__")())
+}
+
+

+ The following example shows how extract can be used along with class_<...> + to create and access an instance of a wrapped C++ class. +

+
struct X
+{
+   X(int x) : v(x) {}
+   int value() { return v; }
+ private:
+   int v;
+};
+
+BOOST_PYTHON_MODULE(extract_ext)
+{
+    object x_class(
+       class_<X>("X", init<int>())
+          .def("value", &X::value))
+          ;
+
+    // Instantiate an X object through the Python interface. 
+    // Its lifetime is now managed by x_obj.
+    object x_obj = x_class(3);
+
+    // Get a reference to the C++ object out of the Python object
+    X& x = extract<X&>(x_obj);
+    assert(x.value() == 3);
+}
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/to_from_python_type_conversion/boost_python_implicit_hpp.html b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_implicit_hpp.html new file mode 100644 index 00000000..cd683300 --- /dev/null +++ b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_implicit_hpp.html @@ -0,0 +1,181 @@ + + + +boost/python/implicit.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ implicitly_convertible + allows Boost.Python to implicitly take advantage of a C++ implicit or explicit + conversion when matching Python objects to C++ argument types. +

+
+
+ +
template <class Source, class Target>
+void implicitly_convertible();
+
+
++++ + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Description +

+
+

+ Source +

+
+

+ The source type of the implicit conversion +

+
+

+ Target +

+
+

+ The target type of the implicit conversion +

+
+
+

+
+
Requires
+

+ The declaration Target + t(s);, + where s is of type Source, is valid. +

+
Effects
+

+ registers an rvalue from_python + converter to Target which can succeed for any PyObject* p + iff there exists any registered converter which can produce Source + rvalues +

+
Rationale
+

+ C++ users expect to be able to take advantage of the same sort of + interoperability in Python as they do in C++. +

+
+
+
+
+ +

+ In C++: +

+
#include <boost/python/class.hpp>
+#include <boost/python/implicit.hpp>
+#include <boost/python/module.hpp>
+
+using namespace boost::python;
+
+struct X
+{
+    X(int x) : v(x) {}
+    operator int() const { return v; }
+    int v;
+};
+
+int x_value(X const& x)
+{
+    return x.v;
+}
+
+X make_x(int n) { return X(n); }
+
+BOOST_PYTHON_MODULE(implicit_ext)
+{
+    def("x_value", x_value);
+    def("make_x", make_x);
+
+    class_<X>("X",
+        init<int>())
+        ;
+
+    implicitly_convertible<X,int>();
+    implicitly_convertible<int,X>();
+}
+
+

+ In Python: +

+
>>> from implicit_ext import *
+>>> x_value(X(42))
+42
+>>> x_value(42)
+42
+>>> x = make_x(X(42))
+>>> x_value(x)
+42
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/to_from_python_type_conversion/boost_python_lvalue_from_pytype_.html b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_lvalue_from_pytype_.html new file mode 100644 index 00000000..7626e6c2 --- /dev/null +++ b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_lvalue_from_pytype_.html @@ -0,0 +1,305 @@ + + + +boost/python/lvalue_from_pytype.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/lvalue_from_pytype.hpp> supplies a facility for extracting + C++ objects from within Python instances of a given type. This is typically + useful for dealing with "traditional" Python extension types. +

+
+
+ + +

+ Class template lvalue_from_pytype will register from_python converters + which, given an object of the given Python type, can extract references + and pointers to a particular C++ type. Its template arguments are: +

+
In the table below, x denotes an object of type PythonObject&
+
+
+++++ + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Extractor +

+
+

+ a model of Extractor + whose execute function returns a reference type. +

+
+

+ Extracts the lvalue from the Python object once its type has + been confirmed +

+
+

+ python_type +

+
+

+ A compile-time constant PyTypeObject* +

+
+

+ The Python type of instances convertible by this converter. Python + subtypes are also convertible. +

+
+
namespace boost { namespace python
+{
+   template <class Extractor, PyTypeObject const* python_type>
+   struct lvalue_from_pytype
+   {
+       lvalue_from_pytype();
+   };
+}}
+
+
+ +
lvalue_from_pytype();
+
+

+
+
Effects
+

+ Registers converters which can convert Python objects of the given + type to lvalues of the type returned by Extractor::execute. +

+
+
+
+
+
+ + +

+ extract_identity is a model of Extractor which can be used in + the common case where the C++ type to be extracted is the same as the Python + object type. +

+
namespace boost { namespace python
+{
+   template <class InstanceType>
+   struct extract_identity
+   {
+      static InstanceType& execute(InstanceType& c);
+   };
+}}
+
+
+ +
InstanceType& execute(InstanceType& c);
+
+

+
+
Returns
+

+ c +

+
+
+
+
+
+ + +

+ extract_member is a model + of Extractor + which can be used in the common case in the common case where the C++ type + to be extracted is a member of the Python object. +

+
namespace boost { namespace python
+{
+   template <class InstanceType, class MemberType, MemberType (InstanceType::*member)>
+   struct extract_member
+   {
+      static MemberType& execute(InstanceType& c);
+   };
+}}
+
+
+ +
static MemberType& execute(InstanceType& c);
+
+

+
+
Returns
+

+ c.*member +

+
+
+
+
+
+ +

+ This example presumes that someone has implemented the standard noddy example + module from the Python documentation, and we want to build a module which + manipulates Noddys. Since noddy_NoddyObject is so simple that it carries + no interesting information, the example is a bit contrived: it assumes + you want to keep track of one particular object for some reason. This module + would have to be dynamically linked to the module which defines noddy_NoddyType. +

+

+ In C++: +

+
#include <boost/python/module.hpp>
+#include <boost/python/handle.hpp>
+#include <boost/python/borrowed.hpp>
+#include <boost/python/lvalue_from_pytype.hpp>
+
+// definition lifted from the Python docs
+typedef struct {
+   PyObject_HEAD
+} noddy_NoddyObject;
+
+using namespace boost::python;
+static handle<noddy_NoddyObject> cache;
+
+bool is_cached(noddy_NoddyObject* x)
+{
+   return x == cache.get();
+}
+
+void set_cache(noddy_NoddyObject* x)
+{
+   cache = handle<noddy_NoddyObject>(borrowed(x));
+}
+
+BOOST_PYTHON_MODULE(noddy_cache)
+{
+   def("is_cached", is_cached);
+   def("set_cache", set_cache);
+
+   // register Noddy lvalue converter
+   lvalue_from_pytype<extract_identity<noddy_NoddyObject>,&noddy_NoddyType>();
+}
+
+

+ In Python: +

+
>>> import noddy
+>>> n = noddy.new_noddy()
+>>> import noddy_cache
+>>> noddy_cache.is_cached(n)
+0
+>>> noddy_cache.set_cache(n)
+>>> noddy_cache.is_cached(n)
+1
+>>> noddy_cache.is_cached(noddy.new_noddy())
+0
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/to_from_python_type_conversion/boost_python_opaque_pointer_conv.html b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_opaque_pointer_conv.html new file mode 100644 index 00000000..b982f341 --- /dev/null +++ b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_opaque_pointer_conv.html @@ -0,0 +1,118 @@ + + + +boost/python/opaque_pointer_converter.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ opaque<> + registers itself as a converter from Python objects to pointers to undefined + types and vice versa. +

+
namespace boost { namespace python
+{
+    template<class Pointee>
+    struct opaque
+    {
+        opaque();
+    };
+}}
+
+
+
+ +
opaque();
+
+

+
+
Effects
+
    +
  • + Registers the instance as a lvalue_from_pytype converter + from Python objects into opaque pointers. The Python Objects + created are named after the type pointed to by the opaque pointer + being wrapped. +
  • +
  • + Registers the instance as a to_python_converter + from opaque pointers to Python objects. +
  • +
+
+
+
+ + + + + +
[Note]Note

+ If there is already an instance registered by another module, this instance + doesn't try to register again in order to avoid warnings about multiple + registrations. +

+
+
+ +

+ This macro must be used to define specializations of the type_id function which can't be + instantiated for incomplete types. +

+
+ + + + + +
[Note]Note

+ The macro must be invoked in every translation unit which uses the opaque + converter. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/to_from_python_type_conversion/boost_python_register_ptr_to_pyt.html b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_register_ptr_to_pyt.html new file mode 100644 index 00000000..7a15754b --- /dev/null +++ b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_register_ptr_to_pyt.html @@ -0,0 +1,166 @@ + + + +boost/python/register_ptr_to_python.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/register_ptr_to_python.hpp> supplies register_ptr_to_python, a function template + which registers a conversion for smart pointers to Python. The resulting + Python object holds a copy of the converted smart pointer, but behaves + as though it were a wrapped copy of the pointee. If the pointee type has + virtual functions and the class representing its dynamic (most-derived) + type has been wrapped, the Python object will be an instance of the wrapper + for the most-derived type. More than one smart pointer type for a pointee's + class can be registered. +

+

+ Note that in order to convert a Python X + object to a smart_ptr<X>& + (non-const reference), the embedded C++ object must be held by smart_ptr<X>, + and that when wrapped objects are created by calling the constructor from + Python, how they are held is determined by the HeldType parameter to class_<...> + instances. +

+
+
+ +
template <class P>
+void register_ptr_to_python()
+
+
+

+
+
Requires
+

+ P is Dereferenceable. +

+
Effects
+

+ Allows conversions to-python of P instances. +

+
+
+
+
+ +

+ Here is an example of a module that contains a class A with virtual functions + and some functions that work with boost::shared_ptr<A>. +

+

+ In C++: +

+
struct A
+{
+    virtual int f() { return 0; }
+};
+
+shared_ptr<A> New() { return shared_ptr<A>( new A() ); }
+
+int Ok( const shared_ptr<A>& a ) { return a->f(); }
+
+int Fail( shared_ptr<A>& a ) { return a->f(); }
+
+struct A_Wrapper: A
+{
+    A_Wrapper(PyObject* self_): self(self_) {}
+    int f() { return call_method<int>(self, "f"); }
+    int default_f() { return A::f(); }
+    PyObject* self;
+};
+
+BOOST_PYTHON_MODULE(register_ptr)
+{
+    class_<A, A_Wrapper>("A")
+        .def("f", &A::f, &A_Wrapper::default_f)
+    ;
+
+    def("New", &New);
+    def("Ok", &Call);
+    def("Fail", &Fail);
+
+    register_ptr_to_python< shared_ptr<A> >();
+}
+
+

+ In Python: +

+
>>> from register_ptr import *
+>>> a = A()
+>>> Ok(a)     # ok, passed as shared_ptr<A>
+0
+>>> Fail(a)   # passed as shared_ptr<A>&, and was created in Python!
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+TypeError: bad argument type for built-in operation
+>>>
+>>> na = New()   # now "na" is actually a shared_ptr<A>
+>>> Ok(a)
+0
+>>> Fail(a)
+0
+>>>
+
+

+ If shared_ptr<A> is registered as follows: +

+
class_<A, A_Wrapper, shared_ptr<A> >("A")
+    .def("f", &A::f, &A_Wrapper::default_f)
+;
+
+

+ There will be an error when trying to convert shared_ptr<A> to shared_ptr<A_Wrapper>: +

+
>>> a = New()
+Traceback (most recent call last):
+File "<stdin>", line 1, in ?
+TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<struct A>
+>>>
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/to_from_python_type_conversion/boost_python_to_python_converter.html b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_to_python_converter.html new file mode 100644 index 00000000..f8cf289d --- /dev/null +++ b/doc/develop/html/reference/to_from_python_type_conversion/boost_python_to_python_converter.html @@ -0,0 +1,252 @@ + + + +boost/python/to_python_converter.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ to_python_converter registers + a conversion from objects of a given C++ type into a Python object. +

+
+
+ + +

+ to_python_converter adds + a wrapper around a static member function of its second template parameter, + handling low-level details such as insertion into the converter registry. +

+

+ In the table below, x denotes an object of type T +

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +
+

+ Parameter +

+
+

+ Requirements +

+
+

+ Description +

+
+

+ T +

+
+ +

+ The C++ type of the source object in the conversion +

+
+

+ Conversion +

+
+

+ PyObject* + p = + Conversion::convert(x), + if p + == 0, + PyErr_Occurred() != + 0. +

+
+

+ A class type whose static member function convert does the real + work of the conversion. +

+
+

+ bool has_get_pytype=false +

+
+

+ PyTypeObject const * + p = + Conversion::get_pytype() +

+
+

+ Optional member - if Conversion has get_pytype + member supply true + for this parameters. If present get_pytype + is used to document the return type of functions using this conversion. + The get_pytype + may be implemented using the classes and functions from pytype_function.hpp + NOTE : For backward compatibility this parameter may be passed + after checking if BOOST_PYTHON_SUPPORTS_PY_SIGNATURES is defined + (see here). +

+
+
namespace boost { namespace python
+{
+  template <class T, class Conversion, bool convertion_has_get_pytype_member=false>
+  struct to_python_converter
+  {
+      to_python_converter();
+  };
+}}
+
+
+ +
to_python_converter();
+
+

+
+
Effects
+

+ Registers a to_python + converter which uses Conversion::convert() to do its work. +

+
+
+
+
+
+ +

+ This example presumes that someone has implemented the standard noddy example + module from the Python documentation, and placed the corresponding declarations + in "noddy.h". Because noddy_NoddyObject is the ultimate trivial + extension type, the example is a bit contrived: it wraps a function for + which all information is contained in the type of its return value. +

+

+ In C++: +

+
#include <boost/python/reference.hpp>
+#include <boost/python/module.hpp>
+#include "noddy.h"
+
+struct tag {};
+tag make_tag() { return tag(); }
+
+using namespace boost::python;
+
+struct tag_to_noddy
+{
+    static PyObject* convert(tag const& x)
+    {
+        return PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
+    }
+    static PyTypeObject const* get_pytype()
+    {
+        return &noddy_NoddyType;
+    }
+};
+
+BOOST_PYTHON_MODULE(to_python_converter)
+{
+    def("make_tag", make_tag);
+    to_python_converter<tag, tag_to_noddy, true>(); //"true" because tag_to_noddy has member get_pytype
+}
+
+

+ In Python: +

+
>>> import to_python_converter
+>>> def always_none():
+...     return None
+...
+>>> def choose_function(x):
+...     if (x % 2 != 0):
+...         return to_python_converter.make_tag
+...     else:
+...         return always_none
+...
+>>> a = [ choose_function(x) for x in range(5) ]
+>>> b = [ f() for f in a ]
+>>> type(b[0])
+<type 'NoneType'>
+>>> type(b[1])
+<type 'Noddy'>
+>>> type(b[2])
+<type 'NoneType'>
+>>> type(b[3])
+<type 'Noddy'>
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/topics.html b/doc/develop/html/reference/topics.html new file mode 100644 index 00000000..17f6b922 --- /dev/null +++ b/doc/develop/html/reference/topics.html @@ -0,0 +1,332 @@ + + + +Chapter 8. Topics + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 8. Topics

+ +
+ + +
+ +

+ The simplest way to call a Python function from C++, given an object instance f holding the + function, is simply to invoke its function call operator. +

+
f("tea", 4, 2) // In Python: f('tea', 4, 2)
+

+ And of course, a method of an object instance x can be invoked by using the function-call + operator of the corresponding attribute: +

+
x.attr("tea")(4, 2); // In Python: x.tea(4, 2)
+

+ If you don't have an object instance, Boost.Python provides two families of function + templates, call and call_method, for invoking Python + functions and methods respectively on PyObject*s. The interface for calling a Python function + object (or any Python callable object) looks like: +

+
call<ResultType>(callable_object, a1, a2... aN);
+

+ Calling a method of a Python object is similarly easy: +

+
call_method<ResultType>(self_object, "method-name", a1, a2... aN);
+

+ This comparitively low-level interface is the one you'll use when implementing + C++ virtual functions that can be overridden in Python. +

+
+
+ +

+ Arguments are converted to Python according to their type. By default, + the arguments a1...aN are copied into new Python objects, + but this behavior can be overridden by the use of ptr() + and ref(): +

+
class X : boost::noncopyable
+{
+   ...
+};
+
+void apply(PyObject* callable, X& x)
+{
+   // Invoke callable, passing a Python object which holds a reference to x
+   boost::python::call<void>(callable, boost::ref(x));
+}
+
+

+ In the table below, x denotes the actual argument object and cv denotes + an optional cv-qualification: "const", "volatile", + or "const volatile". +

+
++++ + + + + + + + + + + + + + + + + + + + + + + +
+

+ Argument Type +

+
+

+ Behavior +

+
+

+ T cv + & T + cv +

+
+

+ The Python argument is created by the same means used for the + return value of a wrapped C++ function returning T. When T is + a class type, that normally means *x is copy-constructed into + the new Python object. +

+
+

+ T* +

+
+

+ If x == 0, the Python argument will be None. Otherwise, the Python + argument is created by the same means used for the return value + of a wrapped C++ function returning T. When T is a class type, + that normally means *x is copy-constructed into the new Python + object. +

+
+

+ boost::reference_wrapper<T> +

+
+

+ The Python argument contains a pointer to, rather than a copy + of, x.get(). Note: failure to ensure that no Python code holds + a reference to the resulting object beyond the lifetime of *x.get() + may result in a crash! +

+
+

+ pointer_wrapper<T> +

+
+

+ If x.get() == 0, the Python argument will be None. Otherwise, + the Python argument contains a pointer to, rather than a copy + of, *x.get(). Note: failure to ensure that no Python code holds + a reference to the resulting object beyond the lifetime of *x.get() + may result in a crash! +

+
+
+
+ +

+ In general, call<ResultType>() + and call_method<ResultType>() return ResultType by exploiting all + lvalue and rvalue from_python converters registered for ResultType and + returning a copy of the result. However, when ResultType is a pointer or + reference type, Boost.Python searches only for lvalue converters. To prevent + dangling pointers and references, an exception will be thrown if the Python + result object has only a single reference count. +

+
+
+ +

+ In general, to get Python arguments corresponding to a1...aN, a new Python + object must be created for each one; should the C++ object be copied into + that Python object, or should the Python object simply hold a reference/pointer + to the C++ object? In general, the latter approach is unsafe, since the + called function may store a reference to the Python object somewhere. If + the Python object is used after the C++ object is destroyed, we'll crash + Python. +

+

+ In keeping with the philosophy that users on the Python side shouldn't + have to worry about crashing the interpreter, the default behavior is to + copy the C++ object, and to allow a non-copying behavior only if the user + writes boost::ref(a1) instead of a1 directly. At least this way, the user + doesn't get dangerous behavior "by accident". It's also worth + noting that the non-copying ("by-reference") behavior is in general + only available for class types, and will fail at runtime with a Python + exception if used otherwise[1]. +

+

+ However, pointer types present a problem: one approach is to refuse to + compile if any aN has pointer type: after all, a user can always pass *aN + to pass "by-value" or ref(*aN) to indicate a pass-by-reference + behavior. However, this creates a problem for the expected null pointer + to None conversion: it's illegal to dereference a null pointer value. +

+

+ The compromise I've settled on is this: +

+
    +
  1. + The default behavior is pass-by-value. If you pass a non-null pointer, + the pointee is copied into a new Python object; otherwise the corresponding + Python argument will be None. +
  2. +
  3. + if you want by-reference behavior, use ptr(aN) if aN is a pointer and + ref(aN) otherwise. If a null pointer is passed to ptr(aN), the corresponding + Python argument will be None. +
  4. +
+

+ As for results, we have a similar problem: if ResultType is allowed to + be a pointer or reference type, the lifetime of the object it refers to + is probably being managed by a Python object. When that Python object is + destroyed, our pointer dangles. The problem is particularly bad when the + ResultType is char const* - the corresponding Python String object is typically + uniquely-referenced, meaning that the pointer dangles as soon as call<char + const*>(...) returns. +

+

+ The old Boost.Python v1 deals with this issue by refusing to compile any + uses of call<char const*>(), but this goes both too far and not far + enough. It goes too far because there are cases where the owning Python + string object survives beyond the call (just for instance, when it's the + name of a Python class), and it goes not far enough because we might just + as well have the same problem with a returned pointer or reference of any + other type. +

+

+ In Boost.Python this is dealt with by: +

+
    +
  1. + lifting the compile-time restriction on char + const * + callback returns +
  2. +
  3. + detecting the case when the reference count on the result Python object + is 1 and throwing an exception inside of call<U>(...) when U + is a pointer or reference type. +
  4. +
+

+ This should be acceptably safe because users have to explicitly specify + a pointer/reference for U + in call<U>, + and they will be protected against dangles at runtime, at least long enough + to get out of the call<U>(...) invocation. +

+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/topics/indexing_support.html b/doc/develop/html/reference/topics/indexing_support.html new file mode 100644 index 00000000..6a23fbc8 --- /dev/null +++ b/doc/develop/html/reference/topics/indexing_support.html @@ -0,0 +1,832 @@ + + + +Indexing support + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Indexing is a Boost Python + facility for easy exportation of indexable C++ containers to Python. Indexable + containers are containers that allow random access through the operator[] + (e.g. std::vector). +

+

+ While Boost Python + has all the facilities needed to expose indexable C++ containers such as + the ubiquitous std::vector to Python, the procedure is not as straightforward + as we'd like it to be. Python containers do not map easily to C++ containers. + Emulating Python containers in C++ (see Python Reference Manual, Emulating + container types) using Boost.Python + is non trivial. There are a lot of issues to consider before we can map + a C++ container to Python. These involve implementing wrapper functions + for the methods __len__, + __getitem__, __setitem__, __delitem__, + __iter__ and __contains__. +

+

+ The goals: +

+
    +
  • + Make indexable C++ containers behave exactly as one would expect a + Python container to behave. +
  • +
  • +

    + Provide default reference semantics for container element indexing + (__getitem__) such + that c[i] can be mutable. Require: +

    +
    val = c[i]
    +c[i].m()
    +val == c[i]
    +
    +

    + where m is a non-const (mutating) member function (method). +

    +
  • +
  • + Return safe references from __getitem__ + such that subsequent adds and deletes to and from the container will + not result in dangling references (will not crash Python). +
  • +
  • + Support slice indexes. +
  • +
  • + Accept Python container arguments (e.g. lists, + tuples) wherever appropriate. +
  • +
  • + Allow for extensibility through re-definable policy classes. +
  • +
  • + Provide predefined support for the most common STL and STL-like indexable + containers. +
  • +
+
+
+ +

+ The indexing_suite class + is the base class for the management of C++ containers intended to be integrated + to Python. The objective is make a C++ container look and feel and behave + exactly as we'd expect a Python container. The class automatically wraps + these special Python methods (taken from the Python reference: Emulating + container types): +

+
+

+
+
__len__(self)
+

+ Called to implement the built-in function len(). Should return the length of the + object, an integer >= 0. Also, an object that doesn't define + a __nonzero__() + method and whose __len__() method returns zero is considered + to be false in a Boolean context. +

+
__getitem__(self, key)
+

+ Called to implement evaluation of self[key]. For sequence types, the accepted + keys should be integers and slice objects. Note that the special + interpretation of negative indexes (if the class wishes to emulate + a sequence type) is up to the __getitem__() method. If key is of an inappropriate + type, TypeError may + be raised; if of a value outside the set of indexes for the sequence + (after any special interpretation of negative values), IndexError + should be raised. [Note: for loops expect that an IndexError will + be raised for illegal indexes to allow proper detection of the end + of the sequence.] +

+
__setitem__(self, key, value)
+

+ Called to implement assignment to self[key]. Same note as for __getitem__(). + This should only be implemented for mappings if the objects support + changes to the values for keys, or if new keys can be added, or for + sequences if elements can be replaced. The same exceptions should + be raised for improper key values as for the __getitem__() method. +

+
__delitem__(self, key)
+

+ Called to implement deletion of self[key]. Same note as for __getitem__(). + This should only be implemented for mappings if the objects support + removal of keys, or for sequences if elements can be removed from + the sequence. The same exceptions should be raised for improper key + values as for the __getitem__() method. +

+
__iter__(self)
+
+

+ This method is called when an iterator is required for a container. + This method should return a new iterator object that can iterate + over all the objects in the container. For mappings, it should iterate + over the keys of the container, and should also be made available + as the method iterkeys(). +

+

+ Iterator objects also need to implement this method; they are required + to return themselves. For more information on iterator objects, see + Iterator + Types in the Python + Library Reference. +

+
+
__contains__(self, item)
+

+ Called to implement membership test operators. Should return true + if item is in self, false otherwise. For mapping objects, this should + consider the keys of the mapping rather than the values or the key-item + pairs. +

+
+
+
+
+ + +

+ The indexing_suite is not + meant to be used as is. A couple of policy functions must be supplied by + subclasses of indexing_suite. + However, a set of indexing_suite subclasses for the standard indexable + STL containers will be provided, In most cases, we can simply use the available + predefined suites. In some cases, we can refine the predefined suites to + suit our needs. +

+
+ +

+ The vector_indexing_suite + class is a predefined indexing_suite + derived class designed to wrap std::vector + (and std::vector-like [i.e. a class with std::vector interface]) classes. It provides + all the policies required by the indexing_suite. +

+

+ Example usage: +

+
class X {...};
+...
+class_<std::vector<X> >("XVec")
+  .def(vector_indexing_suite<std::vector<X> >())
+;
+
+

+ XVec is now a full-fledged Python container (see the example in full, + along with its python test). +

+
+
+ +

+ The map_indexing_suite + class is a predefined indexing_suite + derived class designed to wrap std::map + (and std::map-like [i.e. a class with std::map interface]) classes. It provides + all the policies required by the indexing_suite. +

+

+ Example usage: +

+
class X {...};
+...
+
+class_<std::map<X> >("XMap")
+    .def(map_indexing_suite<std::map<X> >())
+;
+
+

+ By default indexed elements are returned by proxy. This can be disabled + by supplying true in the + NoProxy template parameter. + XMap is now a full-fledged Python container (see the example in full, + along with its python test). +

+
+
+
+ + +
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Template Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Default +

+
+

+ Container +

+
+

+ A class type +

+
+

+ The container type to be wrapped to Python. +

+
+
+

+ DerivedPolicies +

+
+

+ A subclass of indexing_suite +

+
+

+ Derived classes provide the policy hooks. See DerivedPolicies + below. +

+
+
+

+ NoProxy +

+
+

+ A boolean +

+
+

+ By default indexed elements have Python reference semantics and + are returned by proxy. This can be disabled by supplying true + in the NoProxy template parameter. +

+
+

+ false +

+
+

+ NoSlice +

+
+

+ A boolean +

+
+

+ Do not allow slicing. +

+
+

+ false +

+
+

+ Data +

+
+ +

+ The container's data type. +

+
+

+ Container::value_type +

+
+

+ Index +

+
+ +

+ The container's index type. +

+
+

+ Container::size_type +

+
+

+ Key +

+
+ +

+ The container's key type. +

+
+

+ Container::value_type +

+
+
template <class Container,
+	  class DerivedPolicies,
+	   bool NoProxy = false,
+	   bool NoSlice = false,
+	   class Data = typename Container::value_type,
+	   class Index = typename Container::size_type,
+	   class Key = typename Container::value_type>
+class indexing_suite : unspecified
+{
+public:
+  indexing_suite(); // default constructor
+}
+
+
+ +

+ Derived classes provide the hooks needed by the indexing_suite: +

+
data_type&
+get_item(Container& container, index_type i);
+
+static object
+get_slice(Container& container, index_type from, index_type to);
+
+static void
+set_item(Container& container, index_type i, data_type const& v);
+
+static void
+set_slice(
+    Container& container, index_type from,
+    index_type to, data_type const& v
+);
+
+template <class Iter>
+static void
+set_slice(Container& container, index_type from,
+    index_type to, Iter first, Iter last
+);
+
+static void
+delete_item(Container& container, index_type i);
+
+static void
+delete_slice(Container& container, index_type from, index_type to);
+
+static size_t
+size(Container& container);
+
+template <class T>
+static bool
+contains(Container& container, T const& val);
+
+static index_type
+convert_index(Container& container, PyObject* i);
+
+static index_type
+adjust_index(index_type current, index_type from,
+    index_type to, size_type len);
+
+

+ Most of these policies are self explanatory. However, convert_index and + adjust_index deserve some explanation. +

+

+ convert_index converts a Python index into a C++ index that the container + can handle. For instance, negative indexes in Python, by convention, + start counting from the right(e.g. C1 + indexes the rightmost element in C). convert_index should handle the + necessary conversion for the C++ container (e.g. convert -1 to C.size()-1). + convert_index should also be able to convert the type of the index (A + dynamic Python type) to the actual type that the C++ container expects. +

+

+ When a container expands or contracts, held indexes to its elements must + be adjusted to follow the movement of data. For instance, if we erase + 3 elements, starting from index 0 from a 5 element vector, what used + to be at index 4 will now be at index 1: +

+
[a][b][c][d][e] ---> [d][e]
+              ^           ^
+              4           1
+
+

+ adjust_index takes care of the adjustment. Given a current index, the + function should return the adjusted index when data in the container + at index from..to is replaced by len elements. +

+
+
+
+ +
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Template Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Default +

+
+

+ Container +

+
+

+ A class type +

+
+

+ The container type to be wrapped to Python. +

+
+
+

+ NoProxy +

+
+

+ A boolean +

+
+

+ By default indexed elements have Python reference semantics and + are returned by proxy. This can be disabled by supplying true + in the NoProxy template parameter. +

+
+

+ false +

+
+

+ DerivedPolicies +

+
+

+ A subclass of indexing_suite +

+
+

+ The vector_indexing_suite may still be derived to further tweak + any of the predefined policies. Static polymorphism through CRTP + (James Coplien. "Curiously Recurring Template Pattern". + C++ Report, Feb. 1995) enables the base indexing_suite class + to call policy function of the most derived class +

+
+
+
template <class Container,
+	  bool NoProxy = false,
+          class DerivedPolicies = unspecified_default>
+class vector_indexing_suite : unspecified_base
+{
+public:
+
+    typedef typename Container::value_type data_type;
+    typedef typename Container::value_type key_type;
+    typedef typename Container::size_type index_type;
+    typedef typename Container::size_type size_type;
+    typedef typename Container::difference_type difference_type;
+
+    data_type&
+    get_item(Container& container, index_type i);
+
+    static object
+    get_slice(Container& container, index_type from, index_type to);
+
+    static void
+    set_item(Container& container, index_type i, data_type const& v);
+
+    static void
+    set_slice(Container& container, index_type from,
+        index_type to, data_type const& v);
+
+    template <class Iter>
+    static void
+    set_slice(Container& container, index_type from,
+        index_type to, Iter first, Iter last);
+
+    static void
+    delete_item(Container& container, index_type i);
+
+    static void
+    delete_slice(Container& container, index_type from, index_type to);
+
+    static size_t
+    size(Container& container);
+
+    static bool
+    contains(Container& container, key_type const& key);
+
+    static index_type
+    convert_index(Container& container, PyObject* i);
+
+    static index_type
+    adjust_index(index_type current, index_type from,
+        index_type to, size_type len);
+};
+
+
+
+ +
++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Template Parameter +

+
+

+ Requirements +

+
+

+ Semantics +

+
+

+ Default +

+
+

+ Container +

+
+

+ A class type +

+
+

+ The container type to be wrapped to Python. +

+
+
+

+ NoProxy +

+
+

+ A boolean +

+
+

+ By default indexed elements have Python reference semantics and + are returned by proxy. This can be disabled by supplying true + in the NoProxy template parameter. +

+
+

+ false +

+
+

+ DerivedPolicies +

+
+

+ A subclass of indexing_suite +

+
+

+ The vector_indexing_suite may still be derived to further tweak + any of the predefined policies. Static polymorphism through CRTP + (James Coplien. "Curiously Recurring Template Pattern". + C++ Report, Feb. 1995) enables the base indexing_suite class + to call policy function of the most derived class +

+
+
+
template <class Container,
+          bool NoProxy = false,
+          class DerivedPolicies = unspecified_default>
+class map_indexing_suite : unspecified_base
+{
+public:
+
+    typedef typename Container::value_type value_type;
+    typedef typename Container::value_type::second_type data_type;
+    typedef typename Container::key_type key_type;
+    typedef typename Container::key_type index_type;
+    typedef typename Container::size_type size_type;
+    typedef typename Container::difference_type difference_type;
+
+    static data_type&
+    get_item(Container& container, index_type i);
+
+    static void
+    set_item(Container& container, index_type i, data_type const& v);
+
+    static void
+    delete_item(Container& container, index_type i);
+
+    static size_t
+    size(Container& container);
+
+    static bool
+    contains(Container& container, key_type const& key);
+
+    static bool
+    compare_index(Container& container, index_type a, index_type b);
+
+    static index_type
+    convert_index(Container& container, PyObject* i);
+};
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/topics/pickle_support.html b/doc/develop/html/reference/topics/pickle_support.html new file mode 100644 index 00000000..ca386396 --- /dev/null +++ b/doc/develop/html/reference/topics/pickle_support.html @@ -0,0 +1,356 @@ + + + +Pickle support + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Pickle is a Python module for object serialization, also known as persistence, + marshalling, or flattening. +

+

+ It is often necessary to save and restore the contents of an object to + a file. One approach to this problem is to write a pair of functions that + read and write data from a file in a special format. A powerful alternative + approach is to use Python's pickle module. Exploiting Python's ability + for introspection, the pickle module recursively converts nearly arbitrary + Python objects into a stream of bytes that can be written to a file. +

+

+ The Boost Python Library supports the pickle module through the interface + as described in detail in the Python + Library Reference for pickle. This interface involves the special + methods __getinitargs__, + __getstate__ and __setstate__ as described in the following. + Note that Boost.Python is also fully compatible with + Python's cPickle module. +

+
+
+ +

+ At the user level, the Boost.Python pickle interface involves three special + methods: +

+
+

+
+
__getinitargs__
+
+

+ When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a __getinitargs__ + method. This method must return a Python tuple + (it is most convenient to use a boost::python::tuple). When the instance + is restored by the unpickler, the contents of this tuple are used + as the arguments for the class constructor. +

+

+ If __getinitargs__ + is not defined, pickle.load + will call the constructor (__init__) + without arguments; i.e., the object must be default-constructible. +

+
+
__getstate__
+

+ When an instance of a Boost.Python + extension class is pickled, the pickler tests if the instance has + a __getstate__ method. + This method should return a Python object representing the state + of the instance. +

+
__setstate__
+

+ When an instance of a Boost.Python + extension class is restored by the unpickler (pickle.load), + it is first constructed using the result of __getinitargs__ + as arguments (see above). Subsequently the unpickler tests if the + new instance has a __setstate__ + method. If so, this method is called with the result of __getstate__ (a Python object) + as the argument. +

+
+
+

+ The three special methods described above may be .def()'ed + individually by the user. However, Boost.Python + provides an easy to use high-level interface via the boost::python::pickle_suite + class that also enforces consistency: __getstate__ + and __setstate__ must be + defined as pairs. Use of this interface is demonstrated by the following + examples. +

+
+
+ + +

+ There are three files in python/test + that show how to provide pickle support. +

+
+ +

+ The C++ class in this example can be fully restored by passing the appropriate + argument to the constructor. Therefore it is sufficient to define the + pickle interface method __getinitargs__. + This is done in the following way: Definition of the C++ pickle function: +

+
struct world_pickle_suite : boost::python::pickle_suite
+{
+  static
+  boost::python::tuple
+  getinitargs(world const& w)
+  {
+      return boost::python::make_tuple(w.get_country());
+  }
+};
+
+

+ Establishing the Python binding: +

+
class_<world>("world", args<const std::string&>())
+      // ...
+      .def_pickle(world_pickle_suite())
+      // ...
+
+
+
+ +

+ The C++ class in this example contains member data that cannot be restored + by any of the constructors. Therefore it is necessary to provide the + __getstate__/__setstate__ pair of pickle interface + methods: +

+

+ Definition of the C++ pickle functions: +

+
struct world_pickle_suite : boost::python::pickle_suite
+  {
+    static
+    boost::python::tuple
+    getinitargs(const world& w)
+    {
+      // ...
+    }
+
+    static
+    boost::python::tuple
+    getstate(const world& w)
+    {
+      // ...
+    }
+
+    static
+    void
+    setstate(world& w, boost::python::tuple state)
+    {
+      // ...
+    }
+  };
+
+

+ Establishing the Python bindings for the entire suite: +

+
class_<world>("world", args<const std::string&>())
+    // ...
+    .def_pickle(world_pickle_suite())
+    // ...
+
+

+ For simplicity, the __dict__ + is not included in the result of __getstate__. + This is not generally recommended, but a valid approach if it is anticipated + that the object's __dict__ + will always be empty. Note that the safety guard described below will + catch the cases where this assumption is violated. +

+
+
+ +

+ This example is similar to pickle2.cpp. However, the object's __dict__ is included in the result + of __getstate__. This + requires a little more code but is unavoidable if the object's __dict__ is not always empty. +

+
+
+
+ +

+ The pickle protocol described above has an important pitfall that the end + user of a Boost.Python extension module might not be aware of: +

+

+ __getstate__ + is defined and the instance's __dict__ + is not empty. +

+

+ The author of a Boost.Python extension class might provide + a __getstate__ method without + considering the possibilities that: * his class is used in Python as a + base class. Most likely the __dict__ + of instances of the derived class needs to be pickled in order to restore + the instances correctly. * the user adds items to the instance's __dict__ directly. Again, the __dict__ of the instance then needs to + be pickled. +

+

+ To alert the user to this highly unobvious problem, a safety guard is provided. + If __getstate__ is defined + and the instance's __dict__ + is not empty, Boost.Python tests if the class has an attribute + __getstate_manages_dict__. + An exception is raised if this attribute is not defined: +

+
RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
+
+

+ To resolve this problem, it should first be established that the __getstate__ and __setstate__ + methods manage the instances's __dict__ + correctly. Note that this can be done either at the C++ or the Python level. + Finally, the safety guard should intentionally be overridden. E.g. in C++ + (from pickle3.cpp): +

+
struct world_pickle_suite : boost::python::pickle_suite
+{
+  // ...
+
+  static bool getstate_manages_dict() { return true; }
+};
+
+

+ Alternatively in Python: +

+
import your_bpl_module
+class your_class(your_bpl_module.your_class):
+  __getstate_manages_dict__ = 1
+  def __getstate__(self):
+    # your code here
+  def __setstate__(self, state):
+    # your code here
+
+
+
+ +
    +
  • + In Boost.Python extension modules with many + extension classes, providing complete pickle support for all classes + would be a significant overhead. In general complete pickle support + should only be implemented for extension classes that will eventually + be pickled. +
  • +
  • + Avoid using __getstate__ + if the instance can also be reconstructed by way of __getinitargs__. + This automatically avoids the pitfall described above. +
  • +
  • + If __getstate__ is + required, include the instance's __dict__ + in the Python object that is returned. +
  • +
+
+
+ +

+ The pickle4.cpp example demonstrates an alternative technique for implementing + pickle support. First we direct Boost.Python via the class_::enable_pickling() + member function to define only the basic attributes required for pickling: +

+
class_<world>("world", args<const std::string&>())
+    // ...
+    .enable_pickling()
+    // ...
+
+

+ This enables the standard Python pickle interface as described in the Python + documentation. By "injecting" a __getinitargs__ + method into the definition of the wrapped class we make all instances pickleable: +

+
# import the wrapped world class
+from pickle4_ext import world
+
+# definition of __getinitargs__
+def world_getinitargs(self):
+  return (self.get_country(),)
+
+# now inject __getinitargs__ (Python is a dynamic language!)
+world.__getinitargs__ = world_getinitargs
+
+

+ See also the tutorial section on injecting additional methods from Python. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/utility_and_infrastructure.html b/doc/develop/html/reference/utility_and_infrastructure.html new file mode 100644 index 00000000..706f82af --- /dev/null +++ b/doc/develop/html/reference/utility_and_infrastructure.html @@ -0,0 +1,240 @@ + + + +Chapter 7. Utility and Infrastructure + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 7. Utility and Infrastructure

+ +
+ + +
+ +

+ <boost/python/has_back_reference.hpp> defines the predicate metafunction + has_back_reference<>, + which can be specialized by the user to indicate that a wrapped class instance + holds a PyObject* + corresponding to a Python object. +

+
+
+ +

+ A unary metafunction whose value is true iff its argument is a pointer_wrapper<>. +

+
namespace boost { namespace python
+{
+    template<class WrappedClass> class has_back_reference
+    {
+        typedef mpl::false_ type;
+    };
+}}
+
+

+ A metafunction that is inspected by Boost.Python to determine how wrapped + classes can be constructed. +

+

+ type::value is an integral constant convertible + to bool of unspecified type. Specializations may substitute a true-valued + integral constant wrapper for type iff for each invocation of class_<WrappedClass>::def(init< type-sequence...>()) + and the implicitly wrapped copy constructor (unless it is noncopyable), + there exists a corresponding constructor WrappedClass::WrappedClass(PyObject*, type-sequence...). If such a specialization exists, the + WrappedClass constructors will be called with a "back reference" + pointer to the corresponding Python object whenever they are invoked from + Python. The easiest way to provide this nested type is to derive the specialization + from mpl::true_. +

+
+
+ +

+ In C++: +

+
#include <boost/python/class.hpp>
+#include <boost/python/module.hpp>
+#include <boost/python/has_back_reference.hpp>
+#include <boost/python/handle.hpp>
+#include <boost/shared_ptr.hpp>
+
+using namespace boost::python;
+using boost::shared_ptr;
+
+struct X
+{
+    X(PyObject* self) : m_self(self), m_x(0) {}
+    X(PyObject* self, int x) : m_self(self), m_x(x) {}
+    X(PyObject* self, X const& other) : m_self(self), m_x(other.m_x) {}
+
+    handle<> self() { return handle<>(borrowed(m_self)); }
+    int get() { return m_x; }
+    void set(int x) { m_x = x; }
+
+    PyObject* m_self;
+    int m_x;
+};
+
+// specialize has_back_reference for X
+namespace boost { namespace python
+{
+  template <>
+  struct has_back_reference<X>
+    : mpl::true_
+  {};
+}}
+
+struct Y
+{
+    Y() : m_x(0) {}
+    Y(int x) : m_x(x) {}
+    int get() { return m_x; }
+    void set(int x) { m_x = x; }
+
+    int m_x;
+};
+
+shared_ptr<Y>
+Y_self(shared_ptr<Y> self) { return self; }
+
+BOOST_PYTHON_MODULE(back_references)
+{
+    class_<X>("X")
+       .def(init<int>())
+       .def("self", &X::self)
+       .def("get", &X::get)
+       .def("set", &X::set)
+       ;
+
+    class_<Y, shared_ptr<Y> >("Y")
+       .def(init<int>())
+       .def("get", &Y::get)
+       .def("set", &Y::set)
+       .def("self", Y_self)
+       ;
+}
+
+

+ The following Python session illustrates that x.self() returns the same + Python object on which it is invoked, while y.self() must create a new + Python object which refers to the same Y instance. +

+

+ In Python: +

+
>>> from back_references import *
+>>> x = X(1)
+>>> x2 = x.self()
+>>> x2 is x
+1
+>>> (x.get(), x2.get())
+(1, 1)
+>>> x.set(10)
+>>> (x.get(), x2.get())
+(10, 10)
+>>>
+>>>
+>>> y = Y(2)
+>>> y2 = y.self()
+>>> y2 is y
+0
+>>> (y.get(), y2.get())
+(2, 2)
+>>> y.set(20)
+>>> (y.get(), y2.get())
+(20, 20)
+
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/utility_and_infrastructure/boost_python_handle_hpp.html b/doc/develop/html/reference/utility_and_infrastructure/boost_python_handle_hpp.html new file mode 100644 index 00000000..6af91d68 --- /dev/null +++ b/doc/develop/html/reference/utility_and_infrastructure/boost_python_handle_hpp.html @@ -0,0 +1,363 @@ + + + +boost/python/handle.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/handle.hpp> provides class template handle, + a smart pointer for managing reference-counted Python objects. +

+
+
+ + +

+ handle is a smart pointer + to a Python object type; it holds a pointer of type T*, where T + is its template parameter. T must be either a type derived from PyObject or a POD + type whose initial sizeof(PyObject) bytes are layout-compatible with PyObject. Use handle<> at the boundary between the Python/'C' + API and high-level code; prefer object for a generalized interface to Python + objects. +

+

+ In this document, the term "upcast" refers to an operation which + converts a pointer Y* + to a base class pointer T* via + static_cast<T*> + if Y is derived from T, or via C-style cast (T*) if + it is not. However, in the latter case the "upcast" is ill-formed + if the initial sizeof(PyObject) + bytes of Y are not layout-compatible + with PyObject. +

+
namespace boost { namespace python
+{
+  template <class T>
+  class handle
+  {
+      typedef unspecified-member-function-pointer bool_type;
+
+   public: // types
+      typedef T element_type;
+
+   public: // member functions
+      ~handle();
+
+      template <class Y>
+      explicit handle(detail::borrowed<null_ok<Y> >* p);
+
+      template <class Y>
+      explicit handle(null_ok<detail::borrowed<Y> >* p);
+
+      template <class Y>
+      explicit handle(detail::borrowed<Y>* p);
+
+      template <class Y>
+      explicit handle(null_ok<Y>* p);
+
+      template <class Y>
+      explicit handle(Y* p);
+
+      handle();
+
+      handle& operator=(handle const& r);
+
+      template<typename Y>
+      handle& operator=(handle<Y> const & r); // never throws
+
+
+      template <typename Y>
+      handle(handle<Y> const& r);
+
+      handle(handle const& r);
+
+      T* operator-> () const;
+      T& operator* () const;
+      T* get() const;
+      void reset();
+      T* release();
+
+      operator bool_type() const; // never throws
+   private:
+      T* m_p;
+  };
+
+  template <class T> struct null_ok;
+  namespace detail { template <class T> struct borrowed; }
+}}
+
+
+ +
virtual ~handle();
+
+

+
+
Effects
+

+ Py_XDECREF(upcast<PyObject*>(m_p)) +

+
+
+
template <class Y>
+explicit handle(detail::borrowed<null_ok<Y> >* p);
+
+
+

+
+
Effects
+
Py_XINCREF(upcast<PyObject*>(p));
+m_p = upcast<T*>(p);
+
+
+
+
template <class Y>
+explicit handle(null_ok<detail::borrowed<Y> >* p);
+
+

+
+
Effects
+
Py_XINCREF(upcast<PyObject*>(p));
+      m_p = upcast<T*>(p);
+
+
+
+
template <class Y>
+explicit handle(detail::borrowed<Y>* p);
+
+

+
+
Effects
+
Py_XINCREF(upcast<PyObject*>(p));
+      m_p = upcast<T*>(expect_non_null(p));
+
+
+
+
template <class Y>
+explicit handle(null_ok<Y>* p);
+
+
+

+
+
Effects
+

+ m_p = + upcast<T*>(p); +

+
+
+
template <class Y>
+explicit handle(Y* p);
+
+
+

+
+
Effects
+

+ m_p = + upcast<T*>(expect_non_null(p)); +

+
+
+
handle();
+
+
+

+
+
Effects
+

+ m_p = + 0; +

+
+
+
template <typename Y>
+handle(handle<Y> const& r);
+handle(handle const& r);
+
+
+

+
+
Effects
+

+ m_p = r.m_p; Py_XINCREF(upcast<PyObject*>(m_p)); +

+
+
+
+
+ +
handle& operator=(handle const& r);
+template<typename Y>
+handle& operator=(handle<Y> const & r); // never throws
+
+
+

+
+
Effects
+

+ Py_XINCREF(upcast<PyObject*>(r.m_p)); + Py_XDECREF( + upcast<PyObject*>(m_p)); + m_p = + r.m_p; +

+
+
+
T* release();
+
+
+

+
+
Effects
+

+ T* + x = + m_p; + m_p = + 0; + return x; +

+
+
+
void reset();
+
+
+

+
+
Effects
+

+ *this + = handle<T>(); +

+
+
+
+
+ +
T* operator-> () const;
+T* get() const;
+
+
+

+
+
Returns
+

+ m_p; +

+
+
+
T& operator* () const;
+
+
+

+
+
Returns
+

+ *m_p; +

+
+
+
operator bool_type() const; // never throws
+
+
+

+
+
Returns
+

+ 0 if m_p == + 0, a pointer convertible + to true otherwise. +

+
+
+
+
+
+ +
template <class T>
+detail::borrowed<T>* borrowed(T* p)
+{
+    return (detail::borrowed<T>*)p;
+}
+
+
+
+ +
template <class T>
+null_ok<T>* allow_null(T* p)
+{
+    return (null_ok<T>*)p;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/utility_and_infrastructure/boost_python_instance_holder_hpp.html b/doc/develop/html/reference/utility_and_infrastructure/boost_python_instance_holder_hpp.html new file mode 100644 index 00000000..999f2bce --- /dev/null +++ b/doc/develop/html/reference/utility_and_infrastructure/boost_python_instance_holder_hpp.html @@ -0,0 +1,212 @@ + + + +boost/python/instance_holder.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/instance_holder.hpp> provides class instance_holder, + the base class for types which hold C++ instances of wrapped classes. +

+
+
+ + +

+ instance_holder is an abstract + base class whose concrete derived classes hold C++ class instances within + their Python object wrappers. To allow multiple inheritance in Python from + C++ class wrappers, each such Python object contains a chain of instance_holders. + When an __init__ function + for a wrapped C++ class is invoked, a new instance_holder + instance is created and installed in the Python object using its install() + function. Each concrete class derived from instance_holder + must provide a holds() + implementation which allows Boost.Python to query it for the type(s) it + is holding. In order to support the held type's wrapped constructor(s), + the class must also provide constructors that can accept an initial PyObject* + argument referring to the owning Python object, and which forward the rest + of their arguments to the constructor of the held type. The initial argument + is needed to enable virtual function overriding in Python, and may be ignored, + depending on the specific instance_holder + subclass. +

+
namespace boost { namespace python
+{
+  class instance_holder : noncopyable
+  {
+   public:
+      // destructor
+      virtual ~instance_holder();
+
+      // instance_holder modifiers
+      void install(PyObject* inst) throw();
+
+      // instance_holder observers
+      virtual void* holds(type_info) = 0;
+  };
+}}
+
+
+ +
virtual ~instance_holder();
+
+

+
+
Effects
+

+ destroys the object +

+
+
+
+
+ +
void install(PyObject* inst) throw();
+
+

+
+
Requires
+

+ inst is a Python + instance of a wrapped C++ class type, or is a type derived from + a wrapped C++ class type. +

+
Effects
+

+ installs the new instance at the head of the Python object's chain + of held instances. +

+
Throws
+

+ nothing +

+
+
+
+
+ +
virtual void *holds(type_info x) = 0;
+
+

+
+
Returns
+

+ A pointer to an object of the type described by x + if *this + contains such an object, 0 otherwise. +

+
+
+
+
+
+ +

+ The following is a simplified version of the instance holder template used + by Boost.Python to wrap classes held by smart pointers: +

+
template <class SmartPtr, class Value>
+struct pointer_holder : instance_holder
+{
+   // construct from the SmartPtr type
+   pointer_holder(SmartPtr p)
+       :m_p(p)
+
+   // Forwarding constructors for the held type
+   pointer_holder(PyObject*)
+       :m_p(new Value())
+   {
+   }
+
+   template<class A0>
+   pointer_holder(PyObject*,A0 a0)
+       :m_p(new Value(a0))
+   {
+   }
+
+   template<class A0,class A1>
+   pointer_holder(PyObject*,A0 a0,A1 a1)
+       :m_p(new Value(a0,a1))
+   {
+   }
+   ...
+
+ private: // required holder implementation
+   void* holds(type_info dst_t)
+   {
+       // holds an instance of the SmartPtr type...
+       if (dst_t == python::type_id<SmartPtr>())
+           return &this->m_p;
+
+       // ...and an instance of the SmartPtr's element_type, if the
+       // pointer is non-null
+       return python::type_id<Value>() == dst_t ? &*this->m_p : 0;
+   }
+
+ private: // data members
+   SmartPtr m_p;
+};
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/utility_and_infrastructure/boost_python_pointee_hpp.html b/doc/develop/html/reference/utility_and_infrastructure/boost_python_pointee_hpp.html new file mode 100644 index 00000000..544c7ffa --- /dev/null +++ b/doc/develop/html/reference/utility_and_infrastructure/boost_python_pointee_hpp.html @@ -0,0 +1,106 @@ + + + +boost/python/pointee.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/pointee.hpp> introduces a traits metafunction template pointee<T> that can be used to extract the "pointed-to" + type from the type of a pointer or smart pointer. +

+
+
+ +

+ pointee<T> + is used by the class_<...> + template to deduce the type being held when a pointer or smart pointer + type is used as its HeldType argument. +

+
namespace boost { namespace python
+{
+   template <class T> struct pointee
+   {
+      typedef T::element_type type;
+   };
+
+   // specialization for pointers
+   template <T> struct pointee<T*>
+   {
+      typedef T type;
+   };
+}
+
+
+
+ +

+ Given a 3rd-party smart pointer type smart_pointer<T>, one might partially specialize pointee<smart_pointer<T> > so that it can be used as the HeldType + for a class wrapper: +

+
#include <boost/python/pointee.hpp>
+#include <boost/python/class.hpp>
+#include <third_party_lib.hpp>
+
+namespace boost { namespace python
+{
+  template <class T> struct pointee<smart_pointer<T> >
+  {
+     typedef T type;
+  };
+}}
+
+BOOST_PYTHON_MODULE(pointee_demo)
+{
+   class_<third_party_class, smart_pointer<third_party_class> >("third_party_class")
+      .def(...)
+      ...
+      ;
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/utility_and_infrastructure/boost_python_ssize_t_hpp.html b/doc/develop/html/reference/utility_and_infrastructure/boost_python_ssize_t_hpp.html new file mode 100644 index 00000000..a22143d2 --- /dev/null +++ b/doc/develop/html/reference/utility_and_infrastructure/boost_python_ssize_t_hpp.html @@ -0,0 +1,90 @@ + + + +boost/python/ssize_t.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ Python 2.5 introduces a new Py_ssize_t + typedef and two related macros (PEP + 353). The <boost/python/ssize_t.hpp> header imports these + definitions into the boost::python + namespace as ssize_t, + ssize_t_max, and ssize_t_min. Appropriate definitions + are provided for backward compatibility with previous Python versions. +

+
+
+ +

+ Imports Py_ssize_t into + the boost::python namespace if available, or provides + an appropriate typedef for backward compatibility: +

+
#if PY_VERSION_HEX >= 0x02050000
+typedef Py_ssize_t ssize_t;
+#else
+typedef int ssize_t;
+#endif
+
+
+
+ +

+ Imports PY_SSIZE_T_MAX + and PY_SSIZE_T_MIN as constants + into the boost::python namespace if available, or provides + appropriate constants for backward compatibility: +

+
#if PY_VERSION_HEX >= 0x02050000
+ssize_t const ssize_t_max = PY_SSIZE_T_MAX;
+ssize_t const ssize_t_min = PY_SSIZE_T_MIN;
+#else
+ssize_t const ssize_t_max = INT_MAX;
+ssize_t const ssize_t_min = INT_MIN;
+#endif
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/reference/utility_and_infrastructure/boost_python_type_id_hpp.html b/doc/develop/html/reference/utility_and_infrastructure/boost_python_type_id_hpp.html new file mode 100644 index 00000000..5629b6bb --- /dev/null +++ b/doc/develop/html/reference/utility_and_infrastructure/boost_python_type_id_hpp.html @@ -0,0 +1,234 @@ + + + +boost/python/type_id.hpp + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ <boost/python/type_id.hpp> provides types and functions for runtime + type identification like those of of <typeinfo>. + It exists mostly to work around certain compiler bugs and platform-dependent + interactions with shared libraries. +

+
+
+ + +

+ type_info instances identify + a type. As std::type_info is specified to (but unlike + its implementation in some compilers), boost::python::type_info + never represents top-level references or cv-qualification (see section + 5.2.8 in the C++ standard). Unlike std::type_info, + boost::python::type_info instances are copyable, and + comparisons always work reliably across shared library boundaries. +

+
namespace boost { namespace python
+{
+  class type_info : totally_ordered<type_info>
+  {
+  public:
+    // constructor
+    type_info(std::type_info const& = typeid(void));
+
+    // comparisons
+    bool operator<(type_info const& rhs) const;
+    bool operator==(type_info const& rhs) const;
+
+    // observers
+    char const* name() const;
+  };
+}}
+
+
+ +
type_info(std::type_info const& = typeid(void));
+
+

+
+
Effects
+

+ constructs a type_info + object which identifies the same type as its argument. +

+
Rationale
+

+ Since it is occasionally necessary to make an array of type_info objects a benign default + argument is supplied. Note: this constructor does not correct for + non-conformance of compiler typeid() implementations. See type_id, below. +

+
+
+
+
+ +
bool operator<(type_info const &rhs) const;
+
+

+
+
Effects
+

+ yields a total order over type_info + objects. +

+
+
+
bool operator==(type_info const &rhs) const;
+
+

+
+
Returns
+

+ true iff the two values + describe the same type. +

+
Note
+

+ The use of totally_ordered<type_info> as a private base class supplies + operators <=, + >=, >, and != +

+
+
+
+
+ +
char const* name() const;
+
+
+

+
+
Returns
+

+ The result of calling name() on the argument used to construct + the object. +

+
+
+
+
+
+ +
std::ostream& operator<<(std::ostream&s, type_info const&x);
+
+
+

+
+
Effects
+

+ Writes a description of the type described by to x + into s. +

+
Rationale
+

+ Not every C++ implementation provides a truly human-readable type_info::name() + string, but for some we may be able to decode the string and produce + a reasonable representation. +

+
Note
+

+ On some non-conforming C++ implementations, the code is not actually + as simple as described above; the semantics are adjusted to work + as-if the C++ implementation were conforming. +

+
+
+
template <class T> type_info type_id()
+
+
+

+
+
Returns
+

+ type_info(typeid(T)) +

+
Note
+

+ On some non-conforming C++ implementations, the code is not actually + as simple as described above; the semantics are adjusted to work + as-if the C++ implementation were conforming. +

+
+
+
+
+ +

+ The following example, though silly, illustrates how the type_id facility + might be used +

+
#include <boost/python/type_id.hpp>
+
+// Returns true iff the user passes an int argument
+template <class T>
+bool is_int(T x)
+{
+   using boost::python::type_id;
+   return type_id<T>() == type_id<int>();
+}
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/rn.html b/doc/develop/html/rn.html new file mode 100644 index 00000000..695d5c63 --- /dev/null +++ b/doc/develop/html/rn.html @@ -0,0 +1,47 @@ + + + +Chapter 1. Release Notes + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 1. Release Notes

+
+ +
  • + The Boost.Python library names now contain the Python version suffix. + A variant compiled with Python 2.7 will thus produce library names boost_python27 and boost_numpy27, + etc., making it possible to host variants for multiple Python versions + next to each other. +
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/support.html b/doc/develop/html/support.html new file mode 100644 index 00000000..ef271592 --- /dev/null +++ b/doc/develop/html/support.html @@ -0,0 +1,85 @@ + + + +Chapter 4. Support Resources + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+

+Chapter 4. Support Resources

+

+ + Synopsis +

+

+ This is a list of available resources for support with Boost.Python problems + and feature requests. Please try to resist emailing the Boost.Python developers + directly for support. Use the following resources instead; the developers are + listening! +

+

+ + Support +

+
    +
  • + The Boost.Python + mailing list is a forum for discussing Python/C++ interoperability, + and Boost.Python in particular. Post your Boost.Python questions here. +
  • +
  • + The Boost.Build + mailing list is a forum for discussing Boost's Build System. +
  • +
  • +

    + The Boost.Python Issue + tracker +

    +
    + + + + + +
    [Note]Note

    + In the past we used Trac, which still hosts a considerable number of + open + issues. We hope to be able to either close them or migrate them + to the new issue tracker. +

    +
  • +
  • + The Boost.Python Wiki +
  • +
  • + Boost.Python Source repository +
  • +
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/HTML.manifest b/doc/develop/html/tutorial/HTML.manifest new file mode 100644 index 00000000..15d1dc13 --- /dev/null +++ b/doc/develop/html/tutorial/HTML.manifest @@ -0,0 +1,9 @@ +index.html +tutorial/hello.html +tutorial/exposing.html +tutorial/functions.html +tutorial/object.html +tutorial/embedding.html +tutorial/iterators.html +tutorial/exception.html +tutorial/techniques.html diff --git a/doc/develop/html/tutorial/index.html b/doc/develop/html/tutorial/index.html new file mode 100644 index 00000000..e42b11eb --- /dev/null +++ b/doc/develop/html/tutorial/index.html @@ -0,0 +1,149 @@ + + + +Boost.Python Tutorial + + + + + + +
+
+
Next
+
+
+
+

+Boost.Python Tutorial

+
+

+Joel de Guzman +

+

+David Abrahams +

+
+
+
+

+ Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt +

+
+
+
+
+ +
+ +

+ The Boost Python Library is a framework for interfacing Python and C++. It + allows you to quickly and seamlessly expose C++ classes functions and objects + to Python, and vice-versa, using no special tools -- just your C++ compiler. + It is designed to wrap C++ interfaces non-intrusively, so that you should not + have to change the C++ code at all in order to wrap it, making Boost.Python + ideal for exposing 3rd-party libraries to Python. The library's use of advanced + metaprogramming techniques simplifies its syntax for users, so that wrapping + code takes on the look of a kind of declarative interface definition language + (IDL). +

+

+ + Hello + World +

+

+ Following C/C++ tradition, let's start with the "hello, world". A + C++ Function: +

+
char const* greet()
+{
+   return "hello, world";
+}
+
+

+ can be exposed to Python by writing a Boost.Python wrapper: +

+
#include <boost/python.hpp>
+
+BOOST_PYTHON_MODULE(hello_ext)
+{
+    using namespace boost::python;
+    def("greet", greet);
+}
+
+

+ That's it. We're done. We can now build this as a shared library. The resulting + DLL is now visible to Python. Here's a sample Python session: +

+
>>> import hello_ext
+>>> print hello_ext.greet()
+hello, world
+
+

+ Next stop... Building your Hello World module + from start to finish... +

+
+
+ + + +

Last revised: December 25, 2020 at 18:34:31 GMT

+
+
Next
+ + diff --git a/doc/develop/html/tutorial/tutorial/embedding.html b/doc/develop/html/tutorial/tutorial/embedding.html new file mode 100644 index 00000000..8332a768 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/embedding.html @@ -0,0 +1,273 @@ + + + +Embedding + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ By now you should know how to use Boost.Python to call your C++ code from Python. + However, sometimes you may need to do the reverse: call Python code from the + C++-side. This requires you to embed the Python interpreter + into your C++ program. +

+

+ Currently, Boost.Python does not directly support everything you'll need when + embedding. Therefore you'll need to use the Python/C + API to fill in the gaps. However, Boost.Python already makes embedding + a lot easier and, in a future version, it may become unnecessary to touch the + Python/C API at all. So stay tuned... +

+

+ + Building + embedded programs +

+

+ To be able to embed python into your programs, you have to link to both Boost.Python's + as well as Python's own runtime library. +

+

+ Boost.Python's library comes in two variants. Both are located in Boost's + /libs/python/build/bin-stage subdirectory. On Windows, the + variants are called boost_python.lib (for release builds) + and boost_python_debug.lib (for debugging). If you can't + find the libraries, you probably haven't built Boost.Python yet. See Building and Testing on how to do this. +

+

+ Python's library can be found in the /libs subdirectory + of your Python directory. On Windows it is called pythonXY.lib where X.Y is + your major Python version number. +

+

+ Additionally, Python's /include subdirectory has to be added + to your include path. +

+

+ In a Jamfile, all the above boils down to: +

+
projectroot c:\projects\embedded_program ; # location of the program
+
+# bring in the rules for python
+SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
+include python.jam ;
+
+exe embedded_program # name of the executable
+  : #sources
+     embedded_program.cpp
+  : # requirements
+     <find-library>boost_python <library-path>c:\boost\libs\python
+  $(PYTHON_PROPERTIES)
+    <library-path>$(PYTHON_LIB_PATH)
+    <find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
+
+

+ + Getting + started +

+

+ Being able to build is nice, but there is nothing to build yet. Embedding the + Python interpreter into one of your C++ programs requires these 4 steps: +

+
    +
  1. + #include <boost/python.hpp> +
  2. +
  3. + Call Py_Initialize() + to start the interpreter and create the __main__ module. +
  4. +
  5. + Call other Python C API routines to use the interpreter. +
  6. +
+
+ + + + + +
[Note]Note

+ Note that at this time you must not call Py_Finalize() + to stop the interpreter. This may be fixed in a future version of boost.python. +

+

+ (Of course, there can be other C++ code between all of these steps.) +

+

+ Now that we can embed the interpreter in + our programs, lets see how to put it to use... +

+
+ +

+ As you probably already know, objects in Python are reference-counted. Naturally, + the PyObjects of the Python C API are also reference-counted. + There is a difference however. While the reference-counting is fully automatic + in Python, the Python C API requires you to do it by + hand. This is messy and especially hard to get right in the presence + of C++ exceptions. Fortunately Boost.Python provides the handle + and object + class templates to automate the process. +

+

+ + Running + Python code +

+

+ Boost.python provides three related functions to run Python code from C++. +

+
object eval(str expression, object globals = object(), object locals = object())
+object exec(str code, object globals = object(), object locals = object())
+object exec_file(str filename, object globals = object(), object locals = object())
+
+

+ eval evaluates the given expression and returns the resulting value. exec + executes the given code (typically a set of statements) returning the result, + and exec_file executes the code contained in the given file. +

+

+ There are also overloads taking char + const* + instead of str as the first argument. +

+

+ The globals and locals parameters are + Python dictionaries containing the globals and locals of the context in which + to run the code. For most intents and purposes you can use the namespace + dictionary of the __main__ module for both parameters. +

+

+ Boost.python provides a function to import a module: +

+
object import(str name)
+
+

+ import imports a python module (potentially loading it into the running process + first), and returns it. +

+

+ Let's import the __main__ module and run some Python code + in its namespace: +

+
object main_module = import("__main__");
+object main_namespace = main_module.attr("__dict__");
+
+object ignored = exec("hello = file('hello.txt', 'w')\n"
+                      "hello.write('Hello world!')\n"
+                      "hello.close()",
+                      main_namespace);
+
+

+ This should create a file called 'hello.txt' in the current directory containing + a phrase that is well-known in programming circles. +

+

+ + Manipulating + Python objects +

+

+ Often we'd like to have a class to manipulate Python objects. But we have + already seen such a class above, and in the previous + section: the aptly named object class and its derivatives. + We've already seen that they can be constructed from a handle. + The following examples should further illustrate this fact: +

+
object main_module = import("__main__");
+object main_namespace = main_module.attr("__dict__");
+object ignored = exec("result = 5 ** 2", main_namespace);
+int five_squared = extract<int>(main_namespace["result"]);
+
+

+ Here we create a dictionary object for the __main__ module's + namespace. Then we assign 5 squared to the result variable and read this + variable from the dictionary. Another way to achieve the same result is to + use eval instead, which returns the result directly: +

+
object result = eval("5 ** 2");
+int five_squared = extract<int>(result);
+
+

+ + Exception + handling +

+

+ If an exception occurs in the evaluation of the python expression, error_already_set + is thrown: +

+
try
+{
+    object result = eval("5/0");
+    // execution will never get here:
+    int five_divided_by_zero = extract<int>(result);
+}
+catch(error_already_set const &)
+{
+    // handle the exception in some way
+}
+
+

+ The error_already_set exception class doesn't carry any + information in itself. To find out more about the Python exception that occurred, + you need to use the exception + handling functions of the Python C API in your catch-statement. This + can be as simple as calling PyErr_Print() + to print the exception's traceback to the console, or comparing the type + of the exception with those of the standard + exceptions: +

+
catch(error_already_set const &)
+{
+    if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))
+    {
+        // handle ZeroDivisionError specially
+    }
+    else
+    {
+        // print all other errors to stderr
+        PyErr_Print();
+    }
+}
+
+

+ (To retrieve even more information from the exception you can use some of + the other exception handling functions listed here.) +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/exception.html b/doc/develop/html/tutorial/tutorial/exception.html new file mode 100644 index 00000000..1cd8cee8 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/exception.html @@ -0,0 +1,56 @@ + + + +Exception Translation + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ All C++ exceptions must be caught at the boundary with Python code. This boundary + is the point where C++ meets Python. Boost.Python provides a default exception + handler that translates selected standard exceptions, then gives up: +

+
raise RuntimeError, 'unidentifiable C++ Exception'
+
+

+ Users may provide custom translation. Here's an example: +

+
struct PodBayDoorException;
+void translator(PodBayDoorException const& x) {
+    PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave...");
+}
+BOOST_PYTHON_MODULE(kubrick) {
+     register_exception_translator<
+          PodBayDoorException>(translator);
+     ...
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/exposing.html b/doc/develop/html/tutorial/tutorial/exposing.html new file mode 100644 index 00000000..322b67a1 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/exposing.html @@ -0,0 +1,601 @@ + + + +Exposing Classes + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ Now let's expose a C++ class to Python. +

+

+ Consider a C++ class/struct that we want to expose to Python: +

+
struct World
+{
+    void set(std::string msg) { this->msg = msg; }
+    std::string greet() { return msg; }
+    std::string msg;
+};
+
+

+ We can expose this to Python by writing a corresponding Boost.Python C++ Wrapper: +

+
#include <boost/python.hpp>
+using namespace boost::python;
+
+BOOST_PYTHON_MODULE(hello)
+{
+    class_<World>("World")
+        .def("greet", &World::greet)
+        .def("set", &World::set)
+    ;
+}
+
+

+ Here, we wrote a C++ class wrapper that exposes the member functions greet + and set. Now, after building our module as a shared library, + we may use our class World in Python. Here's a sample Python + session: +

+
>>> import hello
+>>> planet = hello.World()
+>>> planet.set('howdy')
+>>> planet.greet()
+'howdy'
+
+
+ +

+ Our previous example didn't have any explicit constructors. Since World + is declared as a plain struct, it has an implicit default constructor. Boost.Python + exposes the default constructor by default, which is why we were able to + write +

+
>>> planet = hello.World()
+
+

+ We may wish to wrap a class with a non-default constructor. Let us build + on our previous example: +

+
struct World
+{
+    World(std::string msg): msg(msg) {} // added constructor
+    void set(std::string msg) { this->msg = msg; }
+    std::string greet() { return msg; }
+    std::string msg;
+};
+
+

+ This time World has no default constructor; our previous + wrapping code would fail to compile when the library tried to expose it. + We have to tell class_<World> about the constructor + we want to expose instead. +

+
#include <boost/python.hpp>
+using namespace boost::python;
+
+BOOST_PYTHON_MODULE(hello)
+{
+    class_<World>("World", init<std::string>())
+        .def("greet", &World::greet)
+        .def("set", &World::set)
+    ;
+}
+
+

+ init<std::string>() exposes the constructor taking + in a std::string (in Python, constructors are spelled + ""__init__""). +

+

+ We can expose additional constructors by passing more init<...>s + to the def() member function. Say for example we have + another World constructor taking in two doubles: +

+
class_<World>("World", init<std::string>())
+    .def(init<double, double>())
+    .def("greet", &World::greet)
+    .def("set", &World::set)
+;
+
+

+ On the other hand, if we do not wish to expose any constructors at all, we + may use no_init instead: +

+
class_<Abstract>("Abstract", no_init)
+
+

+ This actually adds an __init__ method which always raises + a Python RuntimeError exception. +

+
+
+ +

+ Data members may also be exposed to Python so that they can be accessed as + attributes of the corresponding Python class. Each data member that we wish + to be exposed may be regarded as read-only + or read-write. Consider this class Var: +

+
struct Var
+{
+    Var(std::string name) : name(name), value() {}
+    std::string const name;
+    float value;
+};
+
+

+ Our C++ Var class and its data members can be exposed + to Python: +

+
class_<Var>("Var", init<std::string>())
+    .def_readonly("name", &Var::name)
+    .def_readwrite("value", &Var::value);
+
+

+ Then, in Python, assuming we have placed our Var class inside the namespace + hello as we did before: +

+
>>> x = hello.Var('pi')
+>>> x.value = 3.14
+>>> print x.name, 'is around', x.value
+pi is around 3.14
+
+

+ Note that name is exposed as read-only + while value is exposed as read-write. +

+
>>> x.name = 'e' # can't change name
+Traceback (most recent call last):
+  File "<stdin>", line 1, in ?
+AttributeError: can't set attribute
+
+
+
+ +

+ In C++, classes with public data members are usually frowned upon. Well designed + classes that take advantage of encapsulation hide the class' data members. + The only way to access the class' data is through access (getter/setter) + functions. Access functions expose class properties. Here's an example: +

+
struct Num
+{
+    Num();
+    float get() const;
+    void set(float value);
+    ...
+};
+
+

+ However, in Python attribute access is fine; it doesn't neccessarily break + encapsulation to let users handle attributes directly, because the attributes + can just be a different syntax for a method call. Wrapping our Num + class using Boost.Python: +

+
class_<Num>("Num")
+    .add_property("rovalue", &Num::get)
+    .add_property("value", &Num::get, &Num::set);
+
+

+ And at last, in Python: +

+
>>> x = Num()
+>>> x.value = 3.14
+>>> x.value, x.rovalue
+(3.14, 3.14)
+>>> x.rovalue = 2.17 # error!
+
+

+ Take note that the class property rovalue is exposed as + read-only since the rovalue + setter member function is not passed in: +

+
.add_property("rovalue", &Num::get)
+
+
+
+ +

+ In the previous examples, we dealt with classes that are not polymorphic. + This is not often the case. Much of the time, we will be wrapping polymorphic + classes and class hierarchies related by inheritance. We will often have + to write Boost.Python wrappers for classes that are derived from abstract + base classes. +

+

+ Consider this trivial inheritance structure: +

+
struct Base { virtual ~Base(); };
+struct Derived : Base {};
+
+

+ And a set of C++ functions operating on Base and Derived + object instances: +

+
void b(Base*);
+void d(Derived*);
+Base* factory() { return new Derived; }
+
+

+ We've seen how we can wrap the base class Base: +

+
class_<Base>("Base")
+    /*...*/
+    ;
+
+

+ Now we can inform Boost.Python of the inheritance relationship between Derived + and its base class Base. Thus: +

+
class_<Derived, bases<Base> >("Derived")
+    /*...*/
+    ;
+
+

+ Doing so, we get some things for free: +

+
    +
  1. + Derived automatically inherits all of Base's Python methods (wrapped + C++ member functions) +
  2. +
  3. + If Base is polymorphic, Derived + objects which have been passed to Python via a pointer or reference to + Base can be passed where a pointer or reference to + Derived is expected. +
  4. +
+

+ Now, we will expose the C++ free functions b and d + and factory: +

+
def("b", b);
+def("d", d);
+def("factory", factory);
+
+

+ Note that free function factory is being used to generate + new instances of class Derived. In such cases, we use + return_value_policy<manage_new_object> to instruct + Python to adopt the pointer to Base and hold the instance + in a new Python Base object until the the Python object + is destroyed. We will see more of Boost.Python call + policies later. +

+
// Tell Python to take ownership of factory's result
+def("factory", factory,
+    return_value_policy<manage_new_object>());
+
+
+
+ +

+ In this section, we will learn how to make functions behave polymorphically + through virtual functions. Continuing our example, let us add a virtual function + to our Base class: +

+
struct Base
+{
+    virtual ~Base() {}
+    virtual int f() = 0;
+};
+
+

+ One of the goals of Boost.Python is to be minimally intrusive on an existing + C++ design. In principle, it should be possible to expose the interface for + a 3rd party library without changing it. It is not ideal to add anything + to our class Base. Yet, when + you have a virtual function that's going to be overridden in Python and called + polymorphically from C++, we'll need to + add some scaffoldings to make things work properly. What we'll do is write + a class wrapper that derives from Base + that will unintrusively hook into the virtual functions so that a Python + override may be called: +

+
struct BaseWrap : Base, wrapper<Base>
+{
+    int f()
+    {
+        return this->get_override("f")();
+    }
+};
+
+

+ Notice too that in addition to inheriting from Base, + we also multiply- inherited wrapper<Base> (See Wrapper). + The wrapper template makes + the job of wrapping classes that are meant to overridden in Python, easier. +

+
+

+

+ + MSVC6/7 Workaround +

+

+ If you are using Microsoft Visual C++ 6 or 7, you have to write f as: +

+

+ return call<int>(this->get_override("f").ptr());. +

+
+

+ BaseWrap's overridden virtual member function f + in effect calls the corresponding method of the Python object through get_override. +

+

+ Finally, exposing Base: +

+
class_<BaseWrap, boost::noncopyable>("Base")
+    .def("f", pure_virtual(&Base::f))
+    ;
+
+

+ pure_virtual signals Boost.Python + that the function f is a + pure virtual function. +

+
+ + + + + +
[Note]Note
+

+ member function and methods +

+

+ Python, like many object oriented languages uses the term methods. + Methods correspond roughly to C++'s member functions +

+
+
+
+ +

+ We've seen in the previous section how classes with pure virtual functions + are wrapped using Boost.Python's class + wrapper facilities. If we wish to wrap non-pure-virtual + functions instead, the mechanism is a bit different. +

+

+ Recall that in the previous + section, we wrapped a class with a pure virtual function that we then + implemented in C++, or Python classes derived from it. Our base class: +

+
struct Base
+{
+    virtual int f() = 0;
+};
+
+

+ had a pure virtual function f. If, however, its member + function f was not declared as pure virtual: +

+
struct Base
+{
+    virtual ~Base() {}
+    virtual int f() { return 0; }
+};
+
+

+ We wrap it this way: +

+
struct BaseWrap : Base, wrapper<Base>
+{
+    int f()
+    {
+        if (override f = this->get_override("f"))
+            return f(); // *note*
+        return Base::f();
+    }
+
+    int default_f() { return this->Base::f(); }
+};
+
+

+ Notice how we implemented BaseWrap::f. Now, + we have to check if there is an override for f. + If none, then we call Base::f(). +

+
+

+

+ + MSVC6/7 Workaround +

+

+ If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line + with the *note* as: +

+

+ return call<char const*>(f.ptr());. +

+
+

+ Finally, exposing: +

+
class_<BaseWrap, boost::noncopyable>("Base")
+    .def("f", &Base::f, &BaseWrap::default_f)
+    ;
+
+

+ Take note that we expose both &Base::f and &BaseWrap::default_f. Boost.Python needs to keep track + of 1) the dispatch function f and 2) the forwarding function + to its default implementation default_f. There's a special + def function for this purpose. +

+

+ In Python, the results would be as expected: +

+
>>> base = Base()
+>>> class Derived(Base):
+...     def f(self):
+...         return 42
+...
+>>> derived = Derived()
+
+

+ Calling base.f(): +

+
>>> base.f()
+0
+
+

+ Calling derived.f(): +

+
>>> derived.f()
+42
+
+
+
+ +

+ + Python + Operators +

+

+ C is well known for the abundance of operators. C++ extends this to the extremes + by allowing operator overloading. Boost.Python takes advantage of this and + makes it easy to wrap C++ operator-powered classes. +

+

+ Consider a file position class FilePos and a set of operators + that take on FilePos instances: +

+
class FilePos { /*...*/ };
+
+FilePos     operator+(FilePos, int);
+FilePos     operator+(int, FilePos);
+int         operator-(FilePos, FilePos);
+FilePos     operator-(FilePos, int);
+FilePos&    operator+=(FilePos&, int);
+FilePos&    operator-=(FilePos&, int);
+bool        operator<(FilePos, FilePos);
+
+

+ The class and the various operators can be mapped to Python rather easily + and intuitively: +

+
class_<FilePos>("FilePos")
+    .def(self + int())          // __add__
+    .def(int() + self)          // __radd__
+    .def(self - self)           // __sub__
+    .def(self - int())          // __sub__
+    .def(self += int())         // __iadd__
+    .def(self -= other<int>())
+    .def(self < self);          // __lt__
+
+

+ The code snippet above is very clear and needs almost no explanation at all. + It is virtually the same as the operators' signatures. Just take note that + self refers to FilePos object. Also, not every class + T that you might need to interact with in an operator + expression is (cheaply) default-constructible. You can use other<T>() + in place of an actual T instance when writing "self + expressions". +

+

+ + Special + Methods +

+

+ Python has a few more Special Methods. Boost.Python + supports all of the standard special method names supported by real Python + class instances. A similar set of intuitive interfaces can also be used to + wrap C++ functions that correspond to these Python special functions. + Example: +

+
class Rational
+{ public: operator double() const; };
+
+Rational pow(Rational, Rational);
+Rational abs(Rational);
+ostream& operator<<(ostream&,Rational);
+
+class_<Rational>("Rational")
+    .def(float_(self))                  // __float__
+    .def(pow(self, other<Rational>))    // __pow__
+    .def(abs(self))                     // __abs__
+    .def(str(self))                     // __str__
+    ;
+
+

+ Need we say more? +

+
+ + + + + +
[Note]Note

+ What is the business of operator<<? Well, the method str requires the operator<< to do its work (i.e. operator<< + is used by the method defined by def(str(self)). +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/functions.html b/doc/develop/html/tutorial/tutorial/functions.html new file mode 100644 index 00000000..480e5eb0 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/functions.html @@ -0,0 +1,587 @@ + + + +Functions + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ In this chapter, we'll look at Boost.Python powered functions in closer detail. + We will see some facilities to make exposing C++ functions to Python safe from + potential pifalls such as dangling pointers and references. We will also see + facilities that will make it even easier for us to expose C++ functions that + take advantage of C++ features such as overloading and default arguments. +

+

+ Read on... +

+

+ But before you do, you might want to fire up Python 2.2 or later and type + >>> import this. +

+
>>> import this
+The Zen of Python, by Tim Peters
+Beautiful is better than ugly.
+Explicit is better than implicit.
+Simple is better than complex.
+Complex is better than complicated.
+Flat is better than nested.
+Sparse is better than dense.
+Readability counts.
+Special cases aren't special enough to break the rules.
+Although practicality beats purity.
+Errors should never pass silently.
+Unless explicitly silenced.
+In the face of ambiguity, refuse the temptation to guess.
+There should be one-- and preferably only one --obvious way to do it
+Although that way may not be obvious at first unless you're Dutch.
+Now is better than never.
+Although never is often better than right now.
+If the implementation is hard to explain, it's a bad idea.
+If the implementation is easy to explain, it may be a good idea.
+Namespaces are one honking great idea -- let's do more of those!
+
+
+ +

+ In C++, we often deal with arguments and return types such as pointers and + references. Such primitive types are rather, ummmm, low level and they really + don't tell us much. At the very least, we don't know the owner of the pointer + or the referenced object. No wonder languages such as Java and Python never + deal with such low level entities. In C++, it's usually considered a good + practice to use smart pointers which exactly describe ownership semantics. + Still, even good C++ interfaces use raw references and pointers sometimes, + so Boost.Python must deal with them. To do this, it may need your help. Consider + the following C++ function: +

+
X& f(Y& y, Z* z);
+
+

+ How should the library wrap this function? A naive approach builds a Python + X object around result reference. This strategy might or might not work out. + Here's an example where it didn't +

+
>>> x = f(y, z) # x refers to some C++ X
+>>> del y
+>>> x.some_method() # CRASH!
+
+

+ What's the problem? +

+

+ Well, what if f() was implemented as shown below: +

+
X& f(Y& y, Z* z)
+{
+    y.z = z;
+    return y.x;
+}
+
+

+ The problem is that the lifetime of result X& is tied to the lifetime + of y, because the f() returns a reference to a member of the y object. This + idiom is is not uncommon and perfectly acceptable in the context of C++. + However, Python users should not be able to crash the system just by using + our C++ interface. In this case deleting y will invalidate the reference + to X. We have a dangling reference. +

+

+ Here's what's happening: +

+
    +
  1. + f is called passing in a reference to y + and a pointer to z +
  2. +
  3. + A reference to y.x is returned +
  4. +
  5. + y is deleted. x is a dangling reference +
  6. +
  7. + x.some_method() is called +
  8. +
  9. + BOOM! +
  10. +
+

+ We could copy result into a new object: +

+
>>> f(y, z).set(42) # Result disappears
+>>> y.x.get()       # No crash, but still bad
+3.14
+
+

+ This is not really our intent of our C++ interface. We've broken our promise + that the Python interface should reflect the C++ interface as closely as + possible. +

+

+ Our problems do not end there. Suppose Y is implemented as follows: +

+
struct Y
+{
+    X x; Z* z;
+    int z_value() { return z->value(); }
+};
+
+

+ Notice that the data member z is held by class Y using + a raw pointer. Now we have a potential dangling pointer problem inside Y: +

+
>>> x = f(y, z) # y refers to z
+>>> del z       # Kill the z object
+>>> y.z_value() # CRASH!
+
+

+ For reference, here's the implementation of f again: +

+
X& f(Y& y, Z* z)
+{
+    y.z = z;
+    return y.x;
+}
+
+

+ Here's what's happening: +

+
    +
  1. + f is called passing in a reference to y + and a pointer to z +
  2. +
  3. + A pointer to z is held by y +
  4. +
  5. + A reference to y.x is returned +
  6. +
  7. + z is deleted. y.z is a dangling + pointer +
  8. +
  9. + y.z_value() is called +
  10. +
  11. + z->value() is called +
  12. +
  13. + BOOM! +
  14. +
+

+ + Call + Policies +

+

+ Call Policies may be used in situations such as the example detailed above. + In our example, return_internal_reference and with_custodian_and_ward + are our friends: +

+
def("f", f,
+    return_internal_reference<1,
+        with_custodian_and_ward<1, 2> >());
+
+

+ What are the 1 and 2 parameters, you + ask? +

+
return_internal_reference<1
+
+

+ Informs Boost.Python that the first argument, in our case Y& + y, is the owner of the returned reference: X&. + The "1" simply specifies the first argument. + In short: "return an internal reference X& owned + by the 1st argument Y& y". +

+
with_custodian_and_ward<1, 2>
+
+

+ Informs Boost.Python that the lifetime of the argument indicated by ward + (i.e. the 2nd argument: Z* z) is dependent on the lifetime + of the argument indicated by custodian (i.e. the 1st argument: Y& + y). +

+

+ It is also important to note that we have defined two policies above. Two + or more policies can be composed by chaining. Here's the general syntax: +

+
policy1<args...,
+    policy2<args...,
+        policy3<args...> > >
+
+

+ Here is the list of predefined call policies. A complete reference detailing + these can be found here. +

+
    +
  • + with_custodian_and_ward: Ties lifetimes + of the arguments +
  • +
  • + with_custodian_and_ward_postcall: Ties + lifetimes of the arguments and results +
  • +
  • + return_internal_reference: Ties lifetime + of one argument to that of result +
  • +
  • + return_value_policy<T> with T one of: +
      +
    • + reference_existing_object: naive + (dangerous) approach +
    • +
    • + copy_const_reference: Boost.Python + v1 approach +
    • +
    • + copy_non_const_reference: +
    • +
    • + manage_new_object: Adopt a pointer + and hold the instance +
    • +
    +
  • +
+
+

+

+ + Remember the Zen, Luke: +

+

+ "Explicit is better than implicit" +

+

+ "In the face of ambiguity, refuse the temptation to guess" +

+
+
+
+ +

+ The following illustrates a scheme for manually wrapping an overloaded member + functions. Of course, the same technique can be applied to wrapping overloaded + non-member functions. +

+

+ We have here our C++ class: +

+
struct X
+{
+    bool f(int a)
+    {
+        return true;
+    }
+
+    bool f(int a, double b)
+    {
+        return true;
+    }
+
+    bool f(int a, double b, char c)
+    {
+        return true;
+    }
+
+    int f(int a, int b, int c)
+    {
+        return a + b + c;
+    };
+};
+
+

+ Class X has 4 overloaded functions. We will start by introducing some member + function pointer variables: +

+
bool    (X::*fx1)(int)              = &X::f;
+bool    (X::*fx2)(int, double)      = &X::f;
+bool    (X::*fx3)(int, double, char)= &X::f;
+int     (X::*fx4)(int, int, int)    = &X::f;
+
+

+ With these in hand, we can proceed to define and wrap this for Python: +

+
.def("f", fx1)
+.def("f", fx2)
+.def("f", fx3)
+.def("f", fx4)
+
+
+
+ +

+ Boost.Python wraps (member) function pointers. Unfortunately, C++ function + pointers carry no default argument info. Take a function f + with default arguments: +

+
int f(int, double = 3.14, char const* = "hello");
+
+

+ But the type of a pointer to the function f has no information + about its default arguments: +

+
int(*g)(int,double,char const*) = f;    // defaults lost!
+
+

+ When we pass this function pointer to the def function, + there is no way to retrieve the default arguments: +

+
def("f", f);                            // defaults lost!
+
+

+ Because of this, when wrapping C++ code, we had to resort to manual wrapping + as outlined in the previous + section, or writing thin wrappers: +

+
// write "thin wrappers"
+int f1(int x) { return f(x); }
+int f2(int x, double y) { return f(x,y); }
+
+/*...*/
+
+    // in module init
+    def("f", f);  // all arguments
+    def("f", f2); // two arguments
+    def("f", f1); // one argument
+
+

+ When you want to wrap functions (or member functions) that either: +

+
    +
  • + have default arguments, or +
  • +
  • + are overloaded with a common sequence of initial arguments +
  • +
+

+ + BOOST_PYTHON_FUNCTION_OVERLOADS +

+

+ Boost.Python now has a way to make it easier. For instance, given a function: +

+
int foo(int a, char b = 1, unsigned c = 2, double d = 3)
+{
+    /*...*/
+}
+
+

+ The macro invocation: +

+
BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4)
+
+

+ will automatically create the thin wrappers for us. This macro will create + a class foo_overloads that can be passed on to def(...). + The third and fourth macro argument are the minimum arguments and maximum + arguments, respectively. In our foo function the minimum + number of arguments is 1 and the maximum number of arguments is 4. The def(...) + function will automatically add all the foo variants for us: +

+
def("foo", foo, foo_overloads());
+
+

+ + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS +

+

+ Objects here, objects there, objects here there everywhere. More frequently + than anything else, we need to expose member functions of our classes to + Python. Then again, we have the same inconveniences as before when default + arguments or overloads with a common sequence of initial arguments come into + play. Another macro is provided to make this a breeze. +

+

+ Like BOOST_PYTHON_FUNCTION_OVERLOADS, BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS + may be used to automatically create the thin wrappers for wrapping member + functions. Let's have an example: +

+
struct george
+{
+    void
+    wack_em(int a, int b = 0, char c = 'x')
+    {
+        /*...*/
+    }
+};
+
+

+ The macro invocation: +

+
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3)
+
+

+ will generate a set of thin wrappers for george's wack_em + member function accepting a minimum of 1 and a maximum of 3 arguments (i.e. + the third and fourth macro argument). The thin wrappers are all enclosed + in a class named george_overloads that can then be used + as an argument to def(...): +

+
.def("wack_em", &george::wack_em, george_overloads());
+
+

+ See the overloads + reference for details. +

+

+ + init and + optional +

+

+ A similar facility is provided for class constructors, again, with default + arguments or a sequence of overloads. Remember init<...>? + For example, given a class X with a constructor: +

+
struct X
+{
+    X(int a, char b = 'D', std::string c = "constructor", double d = 0.0);
+    /*...*/
+}
+
+

+ You can easily add this constructor to Boost.Python in one shot: +

+
.def(init<int, optional<char, std::string, double> >())
+
+

+ Notice the use of init<...> and optional<...> + to signify the default (optional arguments). +

+
+
+ +

+ It was mentioned in passing in the previous section that BOOST_PYTHON_FUNCTION_OVERLOADS + and BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS can also be + used for overloaded functions and member functions with a common sequence + of initial arguments. Here is an example: +

+
void foo()
+{
+   /*...*/
+}
+
+void foo(bool a)
+{
+   /*...*/
+}
+
+void foo(bool a, int b)
+{
+   /*...*/
+}
+
+void foo(bool a, int b, char c)
+{
+   /*...*/
+}
+
+

+ Like in the previous section, we can generate thin wrappers for these overloaded + functions in one-shot: +

+
BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3)
+
+

+ Then... +

+
.def("foo", (void(*)(bool, int, char))0, foo_overloads());
+
+

+ Notice though that we have a situation now where we have a minimum of zero + (0) arguments and a maximum of 3 arguments. +

+

+ + Manual + Wrapping +

+

+ It is important to emphasize however that the overloaded + functions must have a common sequence of initial arguments. Otherwise, + our scheme above will not work. If this is not the case, we have to wrap + our functions manually. +

+

+ Actually, we can mix and match manual wrapping of overloaded functions and + automatic wrapping through BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS + and its sister, BOOST_PYTHON_FUNCTION_OVERLOADS. Following + up on our example presented in the section on + overloading, since the first 4 overload functins have a common sequence + of initial arguments, we can use BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS + to automatically wrap the first three of the defs and + manually wrap just the last. Here's how we'll do this: +

+
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4)
+
+

+ Create a member function pointers as above for both X::f overloads: +

+
bool    (X::*fx1)(int, double, char)    = &X::f;
+int     (X::*fx2)(int, int, int)        = &X::f;
+
+

+ Then... +

+
.def("f", fx1, xf_overloads());
+.def("f", fx2)
+
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/hello.html b/doc/develop/html/tutorial/tutorial/hello.html new file mode 100644 index 00000000..bb282017 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/hello.html @@ -0,0 +1,191 @@ + + + +Building Hello World + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ + From + Start To Finish +

+

+ Now the first thing you'd want to do is to build the Hello World module and + try it for yourself in Python. In this section, we will outline the steps necessary + to achieve that. We will use the build tool that comes bundled with every boost + distribution: bjam. +

+
+ + + + + +
[Note]Note
+

+ Building without bjam +

+

+ Besides bjam, there are of course other ways to get your module built. What's + written here should not be taken as "the one and only way". There + are of course other build tools apart from bjam. +

+

+ Take note however that the preferred build tool for Boost.Python is bjam. + There are so many ways to set up the build incorrectly. Experience shows + that 90% of the "I can't build Boost.Python" problems come from + people who had to use a different tool. +

+
+

+ We will skip over the details. Our objective will be to simply create the hello + world module and run it in Python. For a complete reference to building Boost.Python, + check out: building.html. After this + brief bjam tutorial, we should have built the DLLs and + run a python program using the extension. +

+

+ The tutorial example can be found in the directory: libs/python/example/tutorial. + There, you can find: +

+
    +
  • + hello.cpp +
  • +
  • + hello.py +
  • +
  • + Jamroot +
  • +
+

+ The hello.cpp file is our C++ hello world example. The + Jamroot is a minimalist bjam script + that builds the DLLs for us. Finally, hello.py is our Python + program that uses the extension in hello.cpp. +

+

+ Before anything else, you should have the bjam executable in your boost directory + or somewhere in your path such that bjam can be executed + in the command line. Pre-built Boost.Jam executables are available for most + platforms. The complete list of Bjam executables can be found here. +

+

+ + Let's + Jam! +

+

+ +

+

+ Here is our minimalist + Jamroot file. Simply copy the file and tweak use-project boost + to where your boost root directory is and you're OK. +

+

+ The comments contained in the Jamroot file above should be sufficient to get + you going. +

+

+ + Running + bjam +

+

+ bjam is run using your operating system's command line + interpreter. +

+

+ Start it up. +

+

+ A file called user-config.jam in your home directory is used to configure your + tools. In Windows, your home directory can be found by typing: +

+
ECHO %HOMEDRIVE%%HOMEPATH%
+
+

+ into a command prompt window. Your file should at least have the rules for + your compiler and your python installation. A specific example of this on Windows + would be: +

+
#  MSVC configuration
+using msvc : 8.0 ;
+
+#  Python configuration
+using python : 2.4 : C:dev/tools/Python ;
+
+

+ The first rule tells Bjam to use the MSVC 8.0 compiler and associated tools. + The second rule provides information on Python, its version and where it is + located. The above assumes that the Python installation is in C:dev/tools\/Python. + If you have one fairly "standard" python installation for your platform, + you might not need to do this. +

+

+ Now we are ready... Be sure to cd to libs/python/example/tutorial + where the tutorial "hello.cpp" and the "Jamroot" + is situated. +

+

+ Finally: +

+
bjam
+
+

+ It should be building now: +

+
cd C:\dev\boost\libs\python\example\tutorial
+bjam
+...patience...
+...found 1101 targets...
+...updating 35 targets...
+
+

+ And so on... Finally: +

+
   Creating library path-to-boost_python.dll
+   Creating library /path-to-hello_ext.exp/
+**passed** ... hello.test
+...updated 35 targets...
+
+

+ Or something similar. If all is well, you should now have built the DLLs and + run the Python program. +

+

+ There you go... Have fun! +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/iterators.html b/doc/develop/html/tutorial/tutorial/iterators.html new file mode 100644 index 00000000..c4d9e4b0 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/iterators.html @@ -0,0 +1,180 @@ + + + +Iterators + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ +

+ In C++, and STL in particular, we see iterators everywhere. Python also has + iterators, but these are two very different beasts. +

+

+ C++ iterators: +

+
    +
  • + C++ has 5 type categories (random-access, bidirectional, forward, input, + output) +
  • +
  • + There are 2 Operation categories: reposition, access +
  • +
  • + A pair of iterators is needed to represent a (first/last) range. +
  • +
+

+ Python Iterators: +

+
    +
  • + 1 category (forward) +
  • +
  • + 1 operation category (next()) +
  • +
  • + Raises StopIteration exception at end +
  • +
+

+ The typical Python iteration protocol: for y + in x... is as follows: +

+
iter = x.__iter__()         # get iterator
+try:
+    while 1:
+    y = iter.next()         # get each item
+    ...                     # process y
+except StopIteration: pass  # iterator exhausted
+
+

+ Boost.Python provides some mechanisms to make C++ iterators play along nicely + as Python iterators. What we need to do is to produce appropriate __iter__ function from C++ iterators that + is compatible with the Python iteration protocol. For example: +

+
object get_iterator = iterator<vector<int> >();
+object iter = get_iterator(v);
+object first = iter.next();
+
+

+ Or for use in class_<>: +

+
.def("__iter__", iterator<vector<int> >())
+
+

+ range +

+

+ We can create a Python savvy iterator using the range function: +

+
    +
  • + range(start, finish) +
  • +
  • + range<Policies,Target>(start, finish) +
  • +
+

+ Here, start/finish may be one of: +

+
    +
  • + member data pointers +
  • +
  • + member function pointers +
  • +
  • + adaptable function object (use Target parameter) +
  • +
+

+ iterator +

+
  • + iterator<T, Policies>() +
+

+ Given a container T, iterator is a shortcut that simply + calls range with &T::begin, &T::end. +

+

+ Let's put this into action... Here's an example from some hypothetical bogon + Particle accelerator code: +

+
f = Field()
+for x in f.pions:
+    smash(x)
+for y in f.bogons:
+    count(y)
+
+

+ Now, our C++ Wrapper: +

+
class_<F>("Field")
+    .property("pions", range(&F::p_begin, &F::p_end))
+    .property("bogons", range(&F::b_begin, &F::b_end));
+
+

+ stl_input_iterator +

+

+ So far, we have seen how to expose C++ iterators and ranges to Python. Sometimes + we wish to go the other way, though: we'd like to pass a Python sequence to + an STL algorithm or use it to initialize an STL container. We need to make + a Python iterator look like an STL iterator. For that, we use stl_input_iterator<>. + Consider how we might implement a function that exposes std::list<int>::assign() to Python: +

+
template<typename T>
+void list_assign(std::list<T>& l, object o) {
+    // Turn a Python sequence into an STL input range
+    stl_input_iterator<T> begin(o), end;
+    l.assign(begin, end);
+}
+
+// Part of the wrapper for list<int>
+class_<std::list<int> >("list_int")
+    .def("assign", &list_assign<int>)
+    // ...
+    ;
+
+

+ Now in Python, we can assign any integer sequence to list_int + objects: +

+
x = list_int();
+x.assign([1,2,3,4,5])
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/object.html b/doc/develop/html/tutorial/tutorial/object.html new file mode 100644 index 00000000..65b34b40 --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/object.html @@ -0,0 +1,366 @@ + + + +Object Interface + + + + + + + + +
+
+
+PrevUpHomeNext +
+
+ + +

+ Python is dynamically typed, unlike C++ which is statically typed. Python variables + may hold an integer, a float, list, dict, tuple, str, long etc., among other + things. In the viewpoint of Boost.Python and C++, these Pythonic variables + are just instances of class object. We will see in this + chapter how to deal with Python objects. +

+

+ As mentioned, one of the goals of Boost.Python is to provide a bidirectional + mapping between C++ and Python while maintaining the Python feel. Boost.Python + C++ objects are as close as possible to Python. This should + minimize the learning curve significantly. +

+

+ +

+
+ +

+ Class object wraps PyObject*. All the + intricacies of dealing with PyObjects such as managing + reference counting are handled by the object class. C++ + object interoperability is seamless. Boost.Python C++ objects + can in fact be explicitly constructed from any C++ object. +

+

+ To illustrate, this Python code snippet: +

+
def f(x, y):
+     if (y == 'foo'):
+         x[3:7] = 'bar'
+     else:
+         x.items += y(3, x)
+     return x
+
+def getfunc():
+   return f;
+
+

+ Can be rewritten in C++ using Boost.Python facilities this way: +

+
object f(object x, object y) {
+     if (y == "foo")
+         x.slice(3,7) = "bar";
+     else
+         x.attr("items") += y(3, x);
+     return x;
+}
+object getfunc() {
+    return object(f);
+}
+
+

+ Apart from cosmetic differences due to the fact that we are writing the code + in C++, the look and feel should be immediately apparent to the Python coder. +

+
+
+ +

+ Boost.Python comes with a set of derived object types + corresponding to that of Python's: +

+
    +
  • + list +
  • +
  • + dict +
  • +
  • + tuple +
  • +
  • + str +
  • +
  • + long_ +
  • +
  • + enum +
  • +
+

+ These derived object types act like real Python types. + For instance: +

+
str(1) ==> "1"
+
+

+ Wherever appropriate, a particular derived object has + corresponding Python type's methods. For instance, dict + has a keys() method: +

+
d.keys()
+
+

+ make_tuple is provided for declaring tuple literals. + Example: +

+
make_tuple(123, 'D', "Hello, World", 0.0);
+
+

+ In C++, when Boost.Python objects are used as arguments + to functions, subtype matching is required. For example, when a function + f, as declared below, is wrapped, it will only accept + instances of Python's str type and subtypes. +

+
void f(str name)
+{
+    object n2 = name.attr("upper")();   // NAME = name.upper()
+    str NAME = name.upper();            // better
+    object msg = "%s is bigger than %s" % make_tuple(NAME,name);
+}
+
+

+ In finer detail: +

+
str NAME = name.upper();
+
+

+ Illustrates that we provide versions of the str type's methods as C++ member + functions. +

+
object msg = "%s is bigger than %s" % make_tuple(NAME,name);
+
+

+ Demonstrates that you can write the C++ equivalent of "format" + % x,y,z in Python, which is useful since there's no easy way to + do that in std C++. +

+
+

+

+ + Beware the common pitfall of forgetting + that the constructors of most of Python's mutable types make copies, just + as in Python. +

+
+

+ Python: +

+
>>> d = dict(x.__dict__)     # copies x.__dict__
+>>> d['whatever'] = 3        # modifies the copy
+
+

+ C++: +

+
dict d(x.attr("__dict__"));  // copies x.__dict__
+d['whatever'] = 3;           // modifies the copy
+
+

+ + class_<T> + as objects +

+

+ Due to the dynamic nature of Boost.Python objects, any class_<T> + may also be one of these types! The following code snippet wraps the class + (type) object. +

+

+ We can use this to create wrapped instances. Example: +

+
object vec345 = (
+    class_<Vec2>("Vec2", init<double, double>())
+        .def_readonly("length", &Point::length)
+        .def_readonly("angle", &Point::angle)
+    )(3.0, 4.0);
+
+assert(vec345.attr("length") == 5.0);
+
+
+
+ +

+ At some point, we will need to get C++ values out of object instances. This + can be achieved with the extract<T> function. Consider + the following: +

+
double x = o.attr("length"); // compile error
+
+

+ In the code above, we got a compiler error because Boost.Python object + can't be implicitly converted to doubles. Instead, what + we wanted to do above can be achieved by writing: +

+
double l = extract<double>(o.attr("length"));
+Vec2& v = extract<Vec2&>(o);
+assert(l == v.length());
+
+

+ The first line attempts to extract the "length" attribute of the + Boost.Python object. The second line attempts to extract + the Vec2 object from held by the Boost.Python object. +

+

+ Take note that we said "attempt to" above. What if the Boost.Python + object does not really hold a Vec2 + type? This is certainly a possibility considering the dynamic nature of Python + objects. To be on the safe side, if the C++ type can't + be extracted, an appropriate exception is thrown. To avoid an exception, + we need to test for extractibility: +

+
extract<Vec2&> x(o);
+if (x.check()) {
+    Vec2& v = x(); ...
+
+

+ + The astute reader might have noticed that the extract<T> + facility in fact solves the mutable copying problem: +

+
dict d = extract<dict>(x.attr("__dict__"));
+d["whatever"] = 3;          // modifies x.__dict__ !
+
+
+
+

+Enums +

+

+ Boost.Python has a nifty facility to capture and wrap C++ enums. While Python + has no enum type, we'll often want to expose our C++ enums + to Python as an int. Boost.Python's enum facility makes + this easy while taking care of the proper conversions from Python's dynamic + typing to C++'s strong static typing (in C++, ints cannot be implicitly converted + to enums). To illustrate, given a C++ enum: +

+
enum choice { red, blue };
+
+

+ the construct: +

+
enum_<choice>("choice")
+    .value("red", red)
+    .value("blue", blue)
+    ;
+
+

+ can be used to expose to Python. The new enum type is created in the current + scope(), which is usually the current module. The snippet + above creates a Python class derived from Python's int + type which is associated with the C++ type passed as its first parameter. +

+
+ + + + + +
[Note]Note
+

+ what is a scope? +

+

+ The scope is a class that has an associated global Python object which + controls the Python namespace in which new extension classes and wrapped + functions will be defined as attributes. Details can be found here. +

+
+

+ You can access those values in Python as +

+
>>> my_module.choice.red
+my_module.choice.red
+
+

+ where my_module is the module where the enum is declared. You can also create + a new scope around a class: +

+
scope in_X = class_<X>("X")
+                .def( ... )
+                .def( ... )
+            ;
+
+// Expose X::nested as X.nested
+enum_<X::nested>("nested")
+    .value("red", red)
+    .value("blue", blue)
+    ;
+
+
+
+ +

+ When you want a boost::python::object to manage a pointer to PyObject* + pyobj one does: +

+
boost::python::object o(boost::python::handle<>(pyobj));
+
+

+ In this case, the o object, + manages the pyobj, it won’t + increase the reference count on construction. +

+

+ Otherwise, to use a borrowed reference: +

+
boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj)));
+
+

+ In this case, Py_INCREF is + called, so pyobj is not destructed + when object o goes out of scope. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/develop/html/tutorial/tutorial/techniques.html b/doc/develop/html/tutorial/tutorial/techniques.html new file mode 100644 index 00000000..9c3ece6c --- /dev/null +++ b/doc/develop/html/tutorial/tutorial/techniques.html @@ -0,0 +1,397 @@ + + + +General Techniques + + + + + + + +
+
+
+PrevUpHome +
+
+ + +

+ Here are presented some useful techniques that you can use while wrapping code + with Boost.Python. +

+
+ +

+ A Python package is a collection of modules that provide to the user a certain + functionality. If you're not familiar on how to create packages, a good introduction + to them is provided in the Python + Tutorial. +

+

+ But we are wrapping C++ code, using Boost.Python. How can we provide a nice + package interface to our users? To better explain some concepts, let's work + with an example. +

+

+ We have a C++ library that works with sounds: reading and writing various + formats, applying filters to the sound data, etc. It is named (conveniently) + sounds. Our library already has a neat C++ namespace hierarchy, + like so: +

+
sounds::core
+sounds::io
+sounds::filters
+
+

+ We would like to present this same hierarchy to the Python user, allowing + him to write code like this: +

+
import sounds.filters
+sounds.filters.echo(...) # echo is a C++ function
+
+

+ The first step is to write the wrapping code. We have to export each module + separately with Boost.Python, like this: +

+
/* file core.cpp */
+BOOST_PYTHON_MODULE(core)
+{
+    /* export everything in the sounds::core namespace */
+    ...
+}
+
+/* file io.cpp */
+BOOST_PYTHON_MODULE(io)
+{
+    /* export everything in the sounds::io namespace */
+    ...
+}
+
+/* file filters.cpp */
+BOOST_PYTHON_MODULE(filters)
+{
+    /* export everything in the sounds::filters namespace */
+    ...
+}
+
+

+ Compiling these files will generate the following Python extensions: core.pyd, + io.pyd and filters.pyd. +

+
+ + + + + +
[Note]Note

+ The extension .pyd is used for python extension modules, + which are just shared libraries. Using the default for your system, like + .so for Unix and .dll for Windows, + works just as well. +

+

+ Now, we create this directory structure for our Python package: +

+
sounds/
+    __init__.py
+    core.pyd
+    filters.pyd
+    io.pyd
+
+

+ The file __init__.py is what tells Python that the directory + sounds/ is actually a Python package. It can be a empty + file, but can also perform some magic, that will be shown later. +

+

+ Now our package is ready. All the user has to do is put sounds + into his PYTHONPATH + and fire up the interpreter: +

+
>>> import sounds.io
+>>> import sounds.filters
+>>> sound = sounds.io.open('file.mp3')
+>>> new_sound = sounds.filters.echo(sound, 1.0)
+
+

+ Nice heh? +

+

+ This is the simplest way to create hierarchies of packages, but it is not + very flexible. What if we want to add a pure Python + function to the filters package, for instance, one that applies 3 filters + in a sound object at once? Sure, you can do this in C++ and export it, but + why not do so in Python? You don't have to recompile the extension modules, + plus it will be easier to write it. +

+

+ If we want this flexibility, we will have to complicate our package hierarchy + a little. First, we will have to change the name of the extension modules: +

+
/* file core.cpp */
+BOOST_PYTHON_MODULE(_core)
+{
+    ...
+    /* export everything in the sounds::core namespace */
+}
+
+

+ Note that we added an underscore to the module name. The filename will have + to be changed to _core.pyd as well, and we do the same + to the other extension modules. Now, we change our package hierarchy like + so: +

+
sounds/
+    __init__.py
+    core/
+        __init__.py
+        _core.pyd
+    filters/
+        __init__.py
+        _filters.pyd
+    io/
+        __init__.py
+        _io.pyd
+
+

+ Note that we created a directory for each extension module, and added a __init__.py + to each one. But if we leave it that way, the user will have to access the + functions in the core module with this syntax: +

+
>>> import sounds.core._core
+>>> sounds.core._core.foo(...)
+
+

+ which is not what we want. But here enters the __init__.py + magic: everything that is brought to the __init__.py namespace + can be accessed directly by the user. So, all we have to do is bring the + entire namespace from _core.pyd to core/__init__.py. + So add this line of code to sounds/core/__init__.py: +

+
from _core import *
+
+

+ We do the same for the other packages. Now the user accesses the functions + and classes in the extension modules like before: +

+
>>> import sounds.filters
+>>> sounds.filters.echo(...)
+
+

+ with the additional benefit that we can easily add pure Python functions + to any module, in a way that the user can't tell the difference between a + C++ function and a Python function. Let's add a pure + Python function, echo_noise, to the filters + package. This function applies both the echo and noise + filters in sequence in the given sound object. We create + a file named sounds/filters/echo_noise.py and code our + function: +

+
import _filters
+def echo_noise(sound):
+    s = _filters.echo(sound)
+    s = _filters.noise(sound)
+    return s
+
+

+ Next, we add this line to sounds/filters/__init__.py: +

+
from echo_noise import echo_noise
+
+

+ And that's it. The user now accesses this function like any other function + from the filters package: +

+
>>> import sounds.filters
+>>> sounds.filters.echo_noise(...)
+
+
+
+ +

+ Thanks to Python's flexibility, you can easily add new methods to a class, + even after it was already created: +

+
>>> class C(object): pass
+>>>
+>>> # a regular function
+>>> def C_str(self): return 'A C instance!'
+>>>
+>>> # now we turn it in a member function
+>>> C.__str__ = C_str
+>>>
+>>> c = C()
+>>> print c
+A C instance!
+>>> C_str(c)
+A C instance!
+
+

+ Yes, Python rox. +

+

+ We can do the same with classes that were wrapped with Boost.Python. Suppose + we have a class point in C++: +

+
class point {...};
+
+BOOST_PYTHON_MODULE(_geom)
+{
+    class_<point>("point")...;
+}
+
+

+ If we are using the technique from the previous session, Creating + Packages, we can code directly into geom/__init__.py: +

+
from _geom import *
+
+# a regular function
+def point_str(self):
+    return str((self.x, self.y))
+
+# now we turn it into a member function
+point.__str__ = point_str
+
+

+ All point instances created from C++ will + also have this member function! This technique has several advantages: +

+
    +
  • + Cut down compile times to zero for these additional functions +
  • +
  • + Reduce the memory footprint to virtually zero +
  • +
  • + Minimize the need to recompile +
  • +
  • + Rapid prototyping (you can move the code to C++ if required without changing + the interface) +
  • +
+

+ Another useful idea is to replace constructors with factory functions: +

+
_point = point
+
+def point(x=0, y=0):
+    return _point(x, y)
+
+

+ In this simple case there is not much gained, but for constructurs with many + overloads and/or arguments this is often a great simplification, again with + virtually zero memory footprint and zero compile-time overhead for the keyword + support. +

+
+
+ +

+ If you have ever exported a lot of classes, you know that it takes quite + a good time to compile the Boost.Python wrappers. Plus the memory consumption + can easily become too high. If this is causing you problems, you can split + the class_ definitions in multiple files: +

+
/* file point.cpp */
+#include <point.h>
+#include <boost/python.hpp>
+
+void export_point()
+{
+    class_<point>("point")...;
+}
+
+/* file triangle.cpp */
+#include <triangle.h>
+#include <boost/python.hpp>
+
+void export_triangle()
+{
+    class_<triangle>("triangle")...;
+}
+
+

+ Now you create a file main.cpp, which contains the BOOST_PYTHON_MODULE + macro, and call the various export functions inside it. +

+
void export_point();
+void export_triangle();
+
+BOOST_PYTHON_MODULE(_geom)
+{
+    export_point();
+    export_triangle();
+}
+
+

+ Compiling and linking together all this files produces the same result as + the usual approach: +

+
#include <boost/python.hpp>
+#include <point.h>
+#include <triangle.h>
+
+BOOST_PYTHON_MODULE(_geom)
+{
+    class_<point>("point")...;
+    class_<triangle>("triangle")...;
+}
+
+

+ but the memory is kept under control. +

+

+ This method is recommended too if you are developing the C++ library and + exporting it to Python at the same time: changes in a class will only demand + the compilation of a single cpp, instead of the entire wrapper code. +

+
+ + + + + +
[Note]Note

+ This method is useful too if you are getting the error message "fatal + error C1204:Compiler limit:internal structure overflow" + when compiling a large source file, as explained in the FAQ. +

+
+
+ + + +
+
+
+PrevUpHome +
+ +