Change the check for when copyRange/destroyRange can be trivially done

* Even if a struct isn't trivial (e.g. it contains a constructor) it can still
  be trivially copyable (just POD with memcpy), or trivially destructable (with
  no destructor). Make sure we don't fall back to slower copies/destroys for
  this case as it's relatively common.
This commit is contained in:
baldurk
2019-01-22 18:48:07 +00:00
parent 9443423389
commit 3f8e2e7f99
+45 -23
View File
@@ -170,18 +170,6 @@ struct ItemHelper
new(first + i) T();
}
static void copyRange(T *dest, const T *src, int32_t count)
{
for(int32_t i = 0; i < count; i++)
new(dest + i) T(src[i]);
}
static void destroyRange(T *first, int32_t count)
{
for(int32_t i = 0; i < count; i++)
(first + i)->~T();
}
static bool equalRange(T *a, T *b, int32_t count)
{
for(int32_t i = 0; i < count; i++)
@@ -205,11 +193,6 @@ template <typename T>
struct ItemHelper<T, true>
{
static void initRange(T *first, int32_t itemCount) { memset(first, 0, itemCount * sizeof(T)); }
static void copyRange(T *dest, const T *src, int32_t count)
{
memcpy(dest, src, count * sizeof(T));
}
static void destroyRange(T *first, int32_t itemCount) {}
static bool equalRange(T *a, T *b, int32_t count) { return !memcmp(a, b, count * sizeof(T)); }
static bool lessthanRange(T *a, T *b, int32_t count)
{
@@ -217,6 +200,45 @@ struct ItemHelper<T, true>
}
};
// ItemCopyHelper checks if memcpy can be used over placement new
template <typename T, bool isStd = std::is_trivially_copyable<T>::value>
struct ItemCopyHelper
{
static void copyRange(T *dest, const T *src, int32_t count)
{
for(int32_t i = 0; i < count; i++)
new(dest + i) T(src[i]);
}
};
template <typename T>
struct ItemCopyHelper<T, true>
{
static void copyRange(T *dest, const T *src, int32_t count)
{
memcpy(dest, src, count * sizeof(T));
}
};
// ItemDestroyHelper checks if the destructor is trivial/do-nothing and can be skipped
template <typename T, bool isStd = std::is_trivially_destructible<T>::value>
struct ItemDestroyHelper
{
static void destroyRange(T *first, int32_t count)
{
for(int32_t i = 0; i < count; i++)
(first + i)->~T();
}
};
template <typename T>
struct ItemDestroyHelper<T, true>
{
static void destroyRange(T *first, int32_t itemCount) {}
};
template <typename T>
struct rdcarray
{
@@ -326,10 +348,10 @@ public:
if(elems)
{
// copy the elements to new storage
ItemHelper<T>::copyRange(newElems, elems, usedCount);
ItemCopyHelper<T>::copyRange(newElems, elems, usedCount);
// delete the old elements
ItemHelper<T>::destroyRange(elems, usedCount);
ItemDestroyHelper<T>::destroyRange(elems, usedCount);
}
// deallocate tee old storage
@@ -366,7 +388,7 @@ public:
// resizing down, we just need to update the count and destruct removed elements
setUsedCount((int32_t)s);
ItemHelper<T>::destroyRange(elems + usedCount, oldCount - usedCount);
ItemDestroyHelper<T>::destroyRange(elems + usedCount, oldCount - usedCount);
}
}
@@ -626,7 +648,7 @@ public:
setUsedCount((int32_t)in.size());
// copy construct the new elems
ItemHelper<T>::copyRange(elems, in.data(), usedCount);
ItemCopyHelper<T>::copyRange(elems, in.data(), usedCount);
null_terminator<T>::fixup(elems, usedCount);
@@ -671,7 +693,7 @@ public:
setUsedCount((int32_t)in.size());
// copy construct the new elems
ItemHelper<T>::copyRange(elems, in.data(), usedCount);
ItemCopyHelper<T>::copyRange(elems, in.data(), usedCount);
null_terminator<T>::fixup(elems, usedCount);
@@ -690,7 +712,7 @@ public:
setUsedCount((int32_t)count);
// copy construct the new elems
ItemHelper<T>::copyRange(elems, in, usedCount);
ItemCopyHelper<T>::copyRange(elems, in, usedCount);
}
#if defined(RENDERDOC_QT_COMPAT)