68 #include <unordered_map> 73 class ConstructorStats {
96 default_constructions++;
104 if (--_instances[inst] < 0)
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(
118 Py_file_input, globals, globals);
119 if (result ==
nullptr)
123 py::module::import(
"gc").attr(
"collect")();
130 for (
const auto &p : _instances)
138 template <
typename T,
typename... Tmore>
void value(
const T &v, Tmore &&...args) {
139 std::ostringstream oss;
141 _values.push_back(oss.str());
142 value(std::forward<Tmore>(args)...);
148 for (
const auto &v : _values) l.append(
py::cast(v));
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));
169 auto &internals = py::detail::get_internals();
170 const std::type_index *t1 =
nullptr, *t2 =
nullptr;
172 auto *type_info = internals.registered_types_py.at((PyTypeObject *)
class_.ptr()).
at(0);
173 for (
auto &p : internals.registered_types_cpp) {
174 if (p.second == type_info) {
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;
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)...);
219 auto &cst = ConstructorStats::get<T>();
221 cst.value(std::forward<Values>(
values)...);
224 ConstructorStats::get<T>().
destroyed(inst);
227 ConstructorStats::get<T>().
value(std::forward<Values>(
values)...);
232 template <
typename T>
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>
int default_constructions
void track_copy_assigned(T *, Values &&...values)
void print_destroyed(T *inst, Values &&...values)
void print_copy_assigned(T *inst, Values &&...values)
const char * format_ptrs(const char *p)
Don't cast pointers to Python, print them as strings.
void print_copy_created(T *inst, Values &&...values)
test_initializer class_("class_", test_submodule_class_)
std::unordered_map< void *, int > _instances
void track_move_created(T *inst)
void print_default_created(T *inst, Values &&...values)
void print_values(T *inst, Values &&...values)
void print_move_assigned(T *inst, Values &&...values)
void copy_created(void *inst)
void default_created(void *inst)
void track_copy_created(T *inst)
void track_destroyed(T *inst)
const x_value & at(const std::map< x_key, x_value > &a_map, const x_key &a_key, const x_value &a_default)
std::list< std::string > _values
void track_move_assigned(T *, Values &&...values)
const detail::type_info * type
void print_created(T *inst, Values &&...values)
void print_constr_details(T *inst, const std::string &action, Output &&...output)
T cast(const handle &handle)
void print(Args &&...args)
void print_move_created(T *inst, Values &&...values)
void move_created(void *inst)
void track_created(T *inst, Values &&...values)
void track_default_created(T *inst, Values &&...values)
void value(const T &v, Tmore &&...args)
void destroyed(void *inst)
void track_values(T *, Values &&...values)