summaryrefslogtreecommitdiff
path: root/Cython/Utility/CppSupport.cpp
blob: ba0002c94fc76a416c15fe872c84b3b03bc09e44 (plain)
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
/////////////// CppExceptionConversion.proto ///////////////

#ifndef __Pyx_CppExn2PyErr
#include <new>
#include <typeinfo>
#include <stdexcept>
#include <ios>

static void __Pyx_CppExn2PyErr() {
  // Catch a handful of different errors here and turn them into the
  // equivalent Python errors.
  try {
    if (PyErr_Occurred())
      ; // let the latest Python exn pass through and ignore the current one
    else
      throw;
  } catch (const std::bad_alloc& exn) {
    PyErr_SetString(PyExc_MemoryError, exn.what());
  } catch (const std::bad_cast& exn) {
    PyErr_SetString(PyExc_TypeError, exn.what());
  } catch (const std::bad_typeid& exn) {
    PyErr_SetString(PyExc_TypeError, exn.what());
  } catch (const std::domain_error& exn) {
    PyErr_SetString(PyExc_ValueError, exn.what());
  } catch (const std::invalid_argument& exn) {
    PyErr_SetString(PyExc_ValueError, exn.what());
  } catch (const std::ios_base::failure& exn) {
    // Unfortunately, in standard C++ we have no way of distinguishing EOF
    // from other errors here; be careful with the exception mask
    PyErr_SetString(PyExc_IOError, exn.what());
  } catch (const std::out_of_range& exn) {
    // Change out_of_range to IndexError
    PyErr_SetString(PyExc_IndexError, exn.what());
  } catch (const std::overflow_error& exn) {
    PyErr_SetString(PyExc_OverflowError, exn.what());
  } catch (const std::range_error& exn) {
    PyErr_SetString(PyExc_ArithmeticError, exn.what());
  } catch (const std::underflow_error& exn) {
    PyErr_SetString(PyExc_ArithmeticError, exn.what());
  } catch (const std::exception& exn) {
    PyErr_SetString(PyExc_RuntimeError, exn.what());
  }
  catch (...)
  {
    PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
  }
}
#endif

/////////////// PythranConversion.proto ///////////////

template <class T>
auto __Pyx_pythran_to_python(T &&value) -> decltype(to_python(
      typename pythonic::returnable<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::type{std::forward<T>(value)}))
{
  using returnable_type = typename pythonic::returnable<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::type;
  return to_python(returnable_type{std::forward<T>(value)});
}

#define __Pyx_PythranShapeAccessor(x) (pythonic::builtins::getattr(pythonic::types::attr::SHAPE{}, x))

////////////// MoveIfSupported.proto //////////////////

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)
  // move should be defined for these versions of MSVC, but __cplusplus isn't set usefully
  #include <utility>
  #define __PYX_STD_MOVE_IF_SUPPORTED(x) std::move(x)
#else
  #define __PYX_STD_MOVE_IF_SUPPORTED(x) x
#endif

////////////// EnumClassDecl.proto //////////////////

#if defined (_MSC_VER)
  #if _MSC_VER >= 1910
    #define __PYX_ENUM_CLASS_DECL enum
  #else
    #define __PYX_ENUM_CLASS_DECL
  #endif
#else
  #define __PYX_ENUM_CLASS_DECL enum
#endif

////////////// OptionalLocals.proto ////////////////
//@proto_block: utility_code_proto_before_types

#include <utility>
#if defined(CYTHON_USE_BOOST_OPTIONAL)
    // fallback mode - std::optional is preferred but this gives
    // people with a less up-to-date compiler a chance
    #include <boost/optional.hpp>
    #define __Pyx_Optional_BaseType boost::optional
#else
    #include <optional>
    // since std::optional is a C++17 features, a templated using declaration should be safe
    // (although it could be replaced with a define)
    template <typename T>
    using __Pyx_Optional_BaseType = std::optional<T>;
#endif

// This class reuses as much of the implementation of std::optional as possible.
// The only place it differs significantly is the assignment operators, which use
// "emplace" (thus requiring move/copy constructors, but not move/copy
// assignment operators). This is preferred because it lets us work with assignable
// types (for example those with const members)
template <typename T>
class __Pyx_Optional_Type : private __Pyx_Optional_BaseType<T> {
public:
    using __Pyx_Optional_BaseType<T>::__Pyx_Optional_BaseType;
    using __Pyx_Optional_BaseType<T>::has_value;
    using __Pyx_Optional_BaseType<T>::operator*;
    using __Pyx_Optional_BaseType<T>::operator->;
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)
    __Pyx_Optional_Type& operator=(const __Pyx_Optional_Type& rhs) {
        this->emplace(*rhs);
        return *this;
    }
    __Pyx_Optional_Type& operator=(__Pyx_Optional_Type&& rhs) {
        this->emplace(std::move(*rhs));
        return *this;
    }
    template <typename U=T>
    __Pyx_Optional_Type& operator=(U&& rhs) {
        this->emplace(std::forward<U>(rhs));
        return *this;
    }
#else
    // Note - the "cpp_locals" feature is designed to require C++14.
    // This pre-c++11 fallback is largely untested, and definitely won't work
    // in all the cases that the more modern version does
    using __Pyx_Optional_BaseType<T>::operator=; // the chances are emplace can't work...
#endif
};