/
chainable_object.hpp
122 lines (111 loc) · 3.71 KB
/
chainable_object.hpp
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
#ifndef STAN_MATH_REV_CORE_CHAINABLE_OBJECT_HPP
#define STAN_MATH_REV_CORE_CHAINABLE_OBJECT_HPP
#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core/chainable_alloc.hpp>
#include <stan/math/rev/core/typedefs.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/typedefs.hpp>
#include <vector>
namespace stan {
namespace math {
/**
* `chainable_object` hold another object is useful for connecting
* the lifetime of a specific object to the chainable stack
*
* `chainable_object` objects should only be allocated with `new`.
* `chainable_object` objects allocated on the stack will result
* in a double free (`obj_` will get destructed once when the
* chainable_object leaves scope and once when the chainable
* stack memory is recovered).
*
* @tparam T type of object to hold
*/
template <typename T>
class chainable_object : public chainable_alloc {
private:
plain_type_t<T> obj_;
public:
/**
* Construct chainable object from another object
*
* @tparam S type of object to hold (must have the same plain type as `T`)
*/
template <typename S,
require_same_t<plain_type_t<T>, plain_type_t<S>>* = nullptr>
explicit chainable_object(S&& obj) : obj_(std::forward<S>(obj)) {}
/**
* Return a reference to the underlying object
*
* @return reference to underlying object
*/
inline auto& get() noexcept { return obj_; }
inline const auto& get() const noexcept { return obj_; }
};
/**
* Store the given object in a `chainable_object` so it is destructed
* only when the chainable stack memory is recovered and return
* a pointer to the underlying object
*
* @tparam T type of object to hold
* @param obj object to hold
* @return pointer to object held in `chainable_object`
*/
template <typename T>
auto make_chainable_ptr(T&& obj) {
auto ptr = new chainable_object<T>(std::forward<T>(obj));
return &ptr->get();
}
/**
* `unsafe_chainable_object` hold another object and is useful for connecting
* the lifetime of a specific object to the chainable stack. This class
* differs from `chainable_object` in that this class does not evaluate
* expressions.
*
* `unsafe_chainable_object` objects should only be allocated with `new`.
* `unsafe_chainable_object` objects allocated on the stack will result
* in a double free (`obj_` will get destructed once when the
* `unsafe_chainable_object` leaves scope and once when the chainable
* stack memory is recovered).
*
* @tparam T type of object to hold
*/
template <typename T>
class unsafe_chainable_object : public chainable_alloc {
private:
std::decay_t<T> obj_;
public:
/**
* Construct chainable object from another object
*
* @tparam S type of object to hold (must have the same plain type as `T`)
*/
template <typename S,
require_same_t<plain_type_t<T>, plain_type_t<S>>* = nullptr>
explicit unsafe_chainable_object(S&& obj) : obj_(std::forward<S>(obj)) {}
/**
* Return a reference to the underlying object
*
* @return reference to underlying object
*/
inline auto& get() noexcept { return obj_; }
inline const auto& get() const noexcept { return obj_; }
};
/**
* Store the given object in a `chainable_object` so it is destructed
* only when the chainable stack memory is recovered and return
* a pointer to the underlying object This function
* differs from `make_chainable_object` in that this class does not evaluate
* expressions.
*
* @tparam T type of object to hold
* @param obj object to hold
* @return pointer to object held in `chainable_object`
*/
template <typename T>
auto make_unsafe_chainable_ptr(T&& obj) {
auto ptr = new unsafe_chainable_object<T>(std::forward<T>(obj));
return &ptr->get();
}
} // namespace math
} // namespace stan
#endif