From 4240e3d668be01a8497747b542279041a64a11cd Mon Sep 17 00:00:00 2001 From: Hein-Pieter van Braam Date: Thu, 3 Jan 2019 05:56:41 +0100 Subject: Optimizations for trivial types Relying on various compiler primitives we can reduce the work done in our memory allocators and CowData. For types with trivial ctors or dtors we can skip looping over all elements when creating, resizing, and destroying lists of objects. These primitives are supported by clang, msvc, and GCC. However, once we've moved to C++11 we can rely on several std:: primitives that do the same thing and are standardized. In my testing the extra conditionals introduced here get removed from the generated program entirely as the results for these primitives is known at compile time. --- core/cowdata.h | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'core/cowdata.h') diff --git a/core/cowdata.h b/core/cowdata.h index d5d49215c2..319e61d261 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -31,6 +31,8 @@ #ifndef COWDATA_H_ #define COWDATA_H_ +#include + #include "core/os/memory.h" #include "core/safe_refcount.h" @@ -194,12 +196,14 @@ void CowData::_unref(void *p_data) { return; // still in use // clean up - uint32_t *count = _get_size(); - T *data = (T *)(count + 1); + if (!__has_trivial_destructor(T)) { + uint32_t *count = _get_size(); + T *data = (T *)(count + 1); - for (uint32_t i = 0; i < *count; ++i) { - // call destructors - data[i].~T(); + for (uint32_t i = 0; i < *count; ++i) { + // call destructors + data[i].~T(); + } } // free mem @@ -226,9 +230,13 @@ void CowData::_copy_on_write() { T *_data = (T *)(mem_new); // initialize new elements - for (uint32_t i = 0; i < current_size; i++) { + if (__has_trivial_copy(T)) { + memcpy(mem_new, _ptr, current_size * sizeof(T)); - memnew_placement(&_data[i], T(_get_data()[i])); + } else { + for (uint32_t i = 0; i < current_size; i++) { + memnew_placement(&_data[i], T(_get_data()[i])); + } } _unref(_ptr); @@ -275,22 +283,25 @@ Error CowData::resize(int p_size) { } // construct the newly created elements - T *elems = _get_data(); - for (int i = *_get_size(); i < p_size; i++) { + if (!__has_trivial_constructor(T)) { + T *elems = _get_data(); - memnew_placement(&elems[i], T); + for (int i = *_get_size(); i < p_size; i++) { + memnew_placement(&elems[i], T); + } } *_get_size() = p_size; } else if (p_size < size()) { - // deinitialize no longer needed elements - for (uint32_t i = p_size; i < *_get_size(); i++) { - - T *t = &_get_data()[i]; - t->~T(); + if (!__has_trivial_destructor(T)) { + // deinitialize no longer needed elements + for (uint32_t i = p_size; i < *_get_size(); i++) { + T *t = &_get_data()[i]; + t->~T(); + } } void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true); -- cgit v1.2.3