├── .gitignore ├── CMakeLists.txt ├── License.rst ├── Readme.rst ├── example └── python.hpp ├── include └── sg14 │ └── memory.hpp ├── proposal ├── Makefile ├── docutils.conf ├── p0468.bs ├── pygments.css └── style.css └── tests ├── doctest.cxx ├── doctest.hpp ├── python.cxx └── usage_example.cxx /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.html 3 | 4 | build/ 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(retain-ptr 3 | VERSION 0.1.0) 4 | 5 | include(CMakeDependentOption) 6 | include(CheckCXXCompilerFlag) 7 | include(CTest) 8 | 9 | find_package(PythonInterp 3.6) 10 | find_package(PythonLibs 3.6) 11 | 12 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 13 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 14 | 15 | set(TEST_SOURCE_DIR ${PROJECT_SOURCE_DIR}/tests) 16 | set(TEST_BINARY_DIR ${PROJECT_BINARY_DIR}/tests) 17 | 18 | set(USE_COVERAGE "--coverage") 19 | set(WARN_MAYBE_UNINIT "-Wmaybe-unintialized") 20 | set(WARN_EVERYTHING "-Weverything") 21 | set(WARN_PEDANTIC "-Wpedantic") 22 | set(WARN_ONE_LINE "-WL") 23 | set(WARN_ERROR "-Werror") 24 | set(WARN_EXTRA "-Wextra") 25 | set(WARN_ODR "-Wodr") 26 | set(WARN_ALL "-Wall") 27 | 28 | set(WARN_NO_DOUBLE_PROMO "-Wno-double-promotion") 29 | set(WARN_NO_UNUSED_FUNC "-Wno-unused-function") 30 | set(WARN_NO_FLOAT_EQUAL "-Wno-float-equal") 31 | set(WARN_NO_DEPRECATED "-Wno-deprecated-declarations") 32 | set(WARN_NO_ATTRIBUTES "-Wno-attributes") 33 | set(WARN_NO_SHADOW "-Wno-shadow") 34 | set(WARN_NO_PADDED "-Wno-padded") 35 | 36 | check_cxx_compiler_flag(${USE_COVERAGE} CAN_USE_COVERAGE) 37 | 38 | check_cxx_compiler_flag(${WARN_MAYBE_UNINIT} CAN_WARN_MAYBE_UNINIT) 39 | check_cxx_compiler_flag(${WARN_EVERYTHING} CAN_WARN_EVERYTHING) 40 | check_cxx_compiler_flag(${WARN_PEDANTIC} CAN_WARN_PEDANTIC) 41 | check_cxx_compiler_flag(${WARN_ONE_LINE} CAN_WARN_ONE_LINE) 42 | check_cxx_compiler_flag(${WARN_ERROR} CAN_WARN_ERROR) 43 | check_cxx_compiler_flag(${WARN_EXTRA} CAN_WARN_EXTRA) 44 | check_cxx_compiler_flag(${WARN_ODR} CAN_WARN_ODR) 45 | check_cxx_compiler_flag(${WARN_ALL} CAN_WARN_ALL) 46 | 47 | check_cxx_compiler_flag(${WARN_NO_DOUBLE_PROMO} CAN_WARN_NO_DOUBLE_PROMO) 48 | check_cxx_compiler_flag(${WARN_NO_UNUSED_FUNC} CAN_WARN_NO_UNUSED_FUNC) 49 | check_cxx_compiler_flag(${WARN_NO_FLOAT_EQUAL} CAN_WARN_NO_FLOAT_EQUAL) 50 | check_cxx_compiler_flag(${WARN_NO_DEPRECATED} CAN_WARN_NO_DEPRECATED) 51 | check_cxx_compiler_flag(${WARN_NO_ATTRIBUTES} CAN_WARN_NO_ATTRIBUTES) 52 | check_cxx_compiler_flag(${WARN_NO_SHADOW} CAN_WARN_NO_SHADOW) 53 | check_cxx_compiler_flag(${WARN_NO_PADDED} CAN_WARN_NO_PADDED) 54 | 55 | add_library(retain-ptr INTERFACE) 56 | target_compile_features(retain-ptr INTERFACE cxx_std_17) 57 | target_include_directories(retain-ptr INTERFACE 58 | ${PROJECT_SOURCE_DIR}/include) 59 | 60 | if (PYTHONLIBS_FOUND) 61 | add_library(pywrap INTERFACE) 62 | target_include_directories(pywrap INTERFACE 63 | ${PROJECT_SOURCE_DIR}/example) 64 | target_include_directories(pywrap SYSTEM INTERFACE 65 | ${PYTHON_INCLUDE_DIR}) 66 | target_link_libraries(pywrap INTERFACE ${PYTHON_LIBRARIES}) 67 | if (MINGW) 68 | target_compile_definitions(pywrap INTERFACE "-D_hypot=hypot") 69 | endif() 70 | endif () 71 | 72 | add_library(doctest-main STATIC ${TEST_SOURCE_DIR}/doctest.cxx) 73 | target_compile_options(doctest-main 74 | PUBLIC 75 | $<$:${USE_COVERAGE}> 76 | $<$:${WARN_MAYBE_UNINIT}> 77 | $<$:${WARN_EVERYTHING}> 78 | $<$:${WARN_PEDANTIC}> 79 | $<$:${WARN_EXTRA}> 80 | $<$:${WARN_ODR}> 81 | $<$:${WARN_ALL}> 82 | 83 | $<$:${WARN_NO_DOUBLE_PROMO}> 84 | $<$:${WARN_NO_UNUSED_FUNC}> 85 | $<$:${WARN_NO_FLOAT_EQUAL}> 86 | $<$:${WARN_NO_DEPRECATED}> 87 | $<$:${WARN_NO_ATTRIBUTES}> 88 | $<$:${WARN_NO_SHADOW}> 89 | $<$:${WARN_NO_PADDED}> 90 | 91 | $<$:-Wno-potentially-evaluated-expression> 92 | $<$:-Wno-unneeded-internal-declaration> 93 | $<$:-Wno-disabled-macro-expansion> 94 | $<$:-Wno-unused-member-function> 95 | $<$:-Wno-c++98-compat-pedantic> 96 | $<$:-Wno-exit-time-destructors> 97 | $<$:-Wno-c++98-compat> 98 | $<$:-Wno-weak-vtables>) 99 | 100 | if (TARGET pywrap) 101 | add_executable(test-python ${TEST_SOURCE_DIR}/python.cxx) 102 | add_test(python test-python) 103 | target_include_directories(test-python SYSTEM PRIVATE ${TEST_SOURCE_DIR}) 104 | target_link_libraries(test-python PUBLIC retain-ptr pywrap doctest-main) 105 | target_link_libraries(test-python PRIVATE 106 | $<$:${USE_COVERAGE}>) 107 | endif () 108 | 109 | add_executable(test-usage_example ${TEST_SOURCE_DIR}/usage_example.cxx) 110 | add_test(usage_example test-usage_example) 111 | target_link_libraries(test-usage_example PUBLIC retain-ptr doctest-main) 112 | target_link_libraries(test-usage_example PRIVATE 113 | $<$:${USE_COVERAGE}>) 114 | -------------------------------------------------------------------------------- /License.rst: -------------------------------------------------------------------------------- 1 | .. |copy| unicode:: U+000A9 2 | 3 | Copyright |copy| 2016, Isabella Muerte 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Readme.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | This is a proposal (P0468_) and reference implementation for an intrusive smart 5 | pointer for the C++ standard library. The example provided is fragile, as it is 6 | only being written against Python 3.5. More examples will eventually follow. 7 | 8 | The implementation provided works with C++14, but could be backported to C++11. 9 | Due to the feature lockin of C++17, this will most likely not make it into the 10 | standard until C++20. 11 | 12 | Creating the HTML file for the proposal requires ``rst2html.py``, which is a 13 | part of the python ``docutils`` package. 14 | 15 | The reference implementation (everything under the include directory) is under 16 | the BSD 2-clause. 17 | 18 | .. _P0468: https://wg21.link/p0468 19 | -------------------------------------------------------------------------------- /example/python.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PYTHON_WRAPPER_EXAMPLE_HPP 2 | #define PYTHON_WRAPPER_EXAMPLE_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace py { 10 | 11 | struct snake_traits final { 12 | static void increment (PyObject* obj) noexcept { Py_INCREF(obj); } 13 | static void decrement (PyObject* obj) noexcept { Py_DECREF(obj); } 14 | }; 15 | 16 | using object = sg14::retain_ptr; 17 | 18 | struct tuple { 19 | using index_type = Py_ssize_t; 20 | 21 | tuple (object obj) noexcept(false) : obj { obj } { 22 | if (not PyTuple_Check(obj.get())) { 23 | throw std::logic_error("Was not passed a tuple"); 24 | } 25 | } 26 | 27 | tuple (object::pointer obj) : tuple(object(obj)) { } 28 | tuple (index_type n) : 29 | tuple(PyTuple_New(n)) 30 | { } 31 | 32 | object operator [] (index_type idx) const noexcept { 33 | return { PyTuple_GetItem(this->obj.get(), idx), sg14::retain_object }; 34 | } 35 | 36 | index_type size () const noexcept { return PyTuple_Size(this->obj.get()); } 37 | 38 | tuple slice (index_type low, index_type high) const noexcept { 39 | return PyTuple_GetSlice(this->obj.get(), low, high); 40 | } 41 | 42 | auto get () const noexcept { return this->obj.get(); } 43 | 44 | private: 45 | object obj; 46 | }; 47 | 48 | struct list { 49 | using index_type = Py_ssize_t; 50 | 51 | list (object obj) noexcept(false) : obj { obj } { 52 | if (not PyList_Check(obj.get())) { 53 | throw std::logic_error("Was not passed a list"); 54 | } 55 | } 56 | list (object::pointer obj) : list(object(obj)) { } 57 | list (index_type n) : 58 | list(PyList_New(n)) 59 | { } 60 | 61 | object operator [] (index_type idx) const noexcept { 62 | return { PyList_GetItem(this->obj.get(), idx), sg14::retain_object }; 63 | } 64 | 65 | void insert (index_type idx, object item) noexcept { 66 | PyList_Insert(this->obj.get(), idx, item.get()); 67 | } 68 | 69 | void append (object item) noexcept { 70 | PyList_Append(this->obj.get(), item.get()); 71 | } 72 | 73 | index_type size () const noexcept { 74 | return PyList_Size(this->obj.get()); 75 | } 76 | 77 | void slice (index_type low, index_type high, list items) noexcept { 78 | PyList_SetSlice(this->obj.get(), low, high, items.obj.get()); 79 | } 80 | 81 | list slice (index_type low, index_type high) const noexcept { 82 | return PyList_GetSlice(this->obj.get(), low, high); 83 | } 84 | 85 | void reverse () noexcept { PyList_Reverse(this->obj.get()); } 86 | void sort () noexcept { PyList_Sort(this->obj.get()); } 87 | 88 | auto get () const noexcept { return this->obj.get(); } 89 | 90 | private: 91 | object obj; 92 | }; 93 | 94 | inline tuple as_tuple (list const& in) { return PySequence_Tuple(in.get()); } 95 | inline list as_list (tuple const& in) { return PyList_AsTuple(in.get()); } 96 | 97 | } /* namespace py */ 98 | 99 | #endif /* PYTHON_WRAPPER_EXAMPLE_HPP */ 100 | -------------------------------------------------------------------------------- /include/sg14/memory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SG14_MEMORY_HPP 2 | #define SG14_MEMORY_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sg14 { 11 | 12 | using std::is_convertible; 13 | using std::is_same; 14 | 15 | using std::conditional_t; 16 | using std::add_pointer_t; 17 | using std::nullptr_t; 18 | 19 | using std::declval; 20 | 21 | } /* namespace sg14 */ 22 | 23 | namespace sg14 { 24 | namespace impl { 25 | 26 | template struct identity { using type = T; }; 27 | 28 | template class, class...> 29 | struct detector : identity { using value_t = std::false_type; }; 30 | 31 | template class U, class... Args> 32 | struct detector>, U, Args...> : 33 | identity> 34 | { using value_t = std::true_type; }; 35 | 36 | struct nonesuch final { 37 | nonesuch (nonesuch const&) = delete; 38 | nonesuch () = delete; 39 | ~nonesuch () = delete; 40 | 41 | void operator = (nonesuch const&) = delete; 42 | }; 43 | 44 | template class U, class... Args> 45 | using detected_or = detector; 46 | 47 | template