File: listview.h

package info (click to toggle)
regina-normal 7.4.1-1.1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 154,244 kB
  • sloc: cpp: 295,026; xml: 9,992; sh: 1,344; python: 1,225; perl: 616; ansic: 138; makefile: 26
file content (150 lines) | stat: -rw-r--r-- 7,432 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

/**************************************************************************
 *                                                                        *
 *  Regina - A Normal Surface Theory Calculator                           *
 *  Python Interface                                                      *
 *                                                                        *
 *  Copyright (c) 1999-2025, Ben Burton                                   *
 *  For further details contact Ben Burton (bab@debian.org).              *
 *                                                                        *
 *  This program is free software; you can redistribute it and/or         *
 *  modify it under the terms of the GNU General Public License as        *
 *  published by the Free Software Foundation; either version 2 of the    *
 *  License, or (at your option) any later version.                       *
 *                                                                        *
 *  As an exception, when this program is distributed through (i) the     *
 *  App Store by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or     *
 *  (iii) Google Play by Google Inc., then that store may impose any      *
 *  digital rights management, device limits and/or redistribution        *
 *  restrictions that are required by its terms of service.               *
 *                                                                        *
 *  This program is distributed in the hope that it will be useful, but   *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *  General Public License for more details.                              *
 *                                                                        *
 *  You should have received a copy of the GNU General Public License     *
 *  along with this program. If not, see <https://www.gnu.org/licenses/>. *
 *                                                                        *
 **************************************************************************/

/*! \file python/helpers/listview.h
 *  \brief Assists with wrapping instances of Regina's lightweight ListView
 *  template class.
 */

#include "utilities/listview.h"
#include "../docstrings/utilities/listview.h"

namespace regina::python {

/**
 * Adds Python bindings for one of Regina's ListView classes, given the
 * class type.
 *
 * The type \a T must be of the form regina::ListView<...>, and must be
 * explicitly specified in the template arguments for addListView().
 *
 * Typically you would not write out the full ListView type explicitly (since
 * this is an implementation detail that may change in future versions of
 * Regina); instead you would access the type using an appropriate decltype()
 * statement.
 *
 * The Python class corresponding to \a T will be named `ListView_suffix`.
 * The \a suffix argument should not be overly long, and does not need to
 * accurately reflect the specific internal data types used by Regina's
 * calculation engine; however, it is important that these suffixes be unique
 * across all ListView types.
 *
 * Note that the Python module that is passed to addListView() should be
 * the submodule `regina.internal`, not the main module `regina`.
 *
 * It is assumed that the ListView type \a T has not yet been wrapped in
 * Python.  If it has, then this routine will throw an exception.
 * Note that this behaviour is different from addTableView, which detects
 * and gracefully avoids attempts to bind the same type multiple times.
 *
 * Return value policies work as follows:
 *
 * - When accessing a list element (e.g., through front() or back(), or
 *   via iteration or indexing), the relationship between the list element
 *   and the ListView will be defined by the template argument \a Policy.
 *   By default, list elements that are pointers (e.g., when calling
 *   Triangulation::vertices()) will use a \c reference_internal policy,
 *   and thus keep the ListView alive; list elements that are values
 *   (e.g., when calling Vertex::embeddings()) will use a \c copy policy,
 *   and thus will have independent lifespans.
 *
 * - If you need the list elements to keep the underlying container alive,
 *   you will need to indicate this when wrapping whatever function returns a
 *   ListView.  Since ListView objects are passed by value, you cannot
 *   use \c reference_internal; instead you should pass an appropriate
 *   \c keep_alive argument.  For example, Triangulation::vertices()
 *   would use pybind11::keep_alive<0,1>().  Note that this assumes that the
 *   list elements are pointers (or if not, the \a Policy argument has been set
 *   appropriately): thus the list elements keep the ListView alive, and
 *   in turn the ListView keeps the container alive.
 */
template <class T, pybind11::return_value_policy Policy =
    (std::is_pointer<typename T::value_type>::value ?
        pybind11::return_value_policy::reference_internal :
        pybind11::return_value_policy::copy)>
void addListView(pybind11::module_& internal, const char* suffix) {
    auto c = pybind11::class_<T>(internal,
            (std::string("ListView_") + suffix).c_str(), doc::ListView)
        .def(pybind11::init<const T&>(), doc::ListView_::__copy)
        .def("__iter__", [](const T& view) {
            return pybind11::make_iterator<Policy>(view.begin(), view.end());
        }, pybind11::keep_alive<0, 1>(), // iterator keeps ListView alive
            doc::ListView_::__iter__)
        .def("__getitem__", [](const T& view, size_t index) {
            if (index >= view.size())
                throw pybind11::index_error("ListView index out of range");
            return view[index];
        }, Policy, doc::ListView_::__array)
        .def("empty", &T::empty, doc::ListView_::empty)
        .def("size", &T::size, doc::ListView_::size)
        .def("__len__", &T::size, doc::ListView_::size)
        .def("front", [](const T& view) {
            if (view.empty())
                throw pybind11::index_error("List is empty");
            return view.front();
        }, Policy, doc::ListView_::front)
        .def("back", [](const T& view) {
            if (view.empty())
                throw pybind11::index_error("List is empty");
            return view.back();
        }, Policy, doc::ListView_::back)
        ;
    regina::python::add_output_custom(c, [](const T& view, std::ostream& out) {
        out << "[ ";
        // For very small lists, output the entire list.
        // For larger lists, do not output everything.
        if (view.empty()) {
            out << "[ ]";
        } else if (view.size() <= 5) {
            bool started = false;
            for (const auto& i : view) {
                if (started)
                    out << ", ";
                else
                    started = true;
                regina::python::writeRepr(out, i);
            }
            out << ' ';
        } else {
            for (int i = 0; i < 3; ++i) {
                regina::python::writeRepr(out, view[i]);
                out << ", ";
            }
            out << "..., ";
            regina::python::writeRepr(out, view.back());
            out << ' ';
        }
        out << ']';
    }, "<internal>.ListView");
    regina::python::add_eq_operators(c, doc::ListView_::__eq);
}

} // namespace regina::python