68 #include <unordered_map>
73 class ConstructorStats {
105 throw std::runtime_error(
"cstats.destroyed() called with unknown "
106 "instance; potential double-destruction "
107 "or a missing cstats.created()");
112 #if defined(PYPY_VERSION)
113 PyObject *
globals = PyEval_GetGlobals();
114 PyObject *result = PyRun_String(
119 if (result ==
nullptr)
120 throw py::error_already_set();
123 py::module_::import(
"gc").attr(
"collect")();
138 template <
typename T,
typename... Tmore>
void value(
const T &v, Tmore &&...
args) {
139 std::ostringstream oss;
154 static ConstructorStats&
get(std::type_index
type) {
155 static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
156 return all_cstats[
type];
160 template <
typename T>
static ConstructorStats&
get() {
161 #if defined(PYPY_VERSION)
164 return get(
typeid(T));
168 static ConstructorStats&
get(py::object class_) {
170 const std::type_index *t1 =
nullptr, *t2 =
nullptr;
183 catch (
const std::out_of_range&) {}
184 if (!t1)
throw std::runtime_error(
"Unknown class passed to ConstructorStats::get()");
185 auto &cs1 =
get(*t1);
189 auto &cs2 =
get(*t2);
190 int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
191 int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
192 if (cs2_total > cs1_total)
return cs2;
201 template <
class T>
void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
202 template <
class T>
void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
204 auto &cst = ConstructorStats::get<T>();
205 cst.copy_assignments++;
206 cst.value(std::forward<Values>(values)...);
209 auto &cst = ConstructorStats::get<T>();
210 cst.move_assignments++;
211 cst.value(std::forward<Values>(values)...);
214 auto &cst = ConstructorStats::get<T>();
215 cst.default_created(inst);
216 cst.value(std::forward<Values>(values)...);
218 template <
class T,
typename... Values>
void track_created(T *inst, Values &&...values) {
219 auto &cst = ConstructorStats::get<T>();
221 cst.value(std::forward<Values>(values)...);
224 ConstructorStats::get<T>().destroyed(inst);
226 template <
class T,
typename... Values>
void track_values(T *, Values &&...values) {
227 ConstructorStats::get<T>().value(std::forward<Values>(values)...);
232 template <
typename T>
233 py::str
format_ptrs(T *p) {
return "{:#x}"_s.format(
reinterpret_cast<std::uintptr_t
>(p)); }
234 template <
typename T>
235 auto format_ptrs(T &&
x) -> decltype(std::forward<T>(
x)) {
return std::forward<T>(
x); }
237 template <
class T,
typename... Output>
264 template <
class T,
typename... Values>
void print_created(T *inst, Values &&...values) {
268 template <
class T,
typename... Values>
void print_destroyed(T *inst, Values &&...values) {
272 template <
class T,
typename... Values>
void print_values(T *inst, Values &&...values) {