mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
Refactor and improve rdcarray/rdcstr interface
* We are going to replace all std::string/std::vector use with these.
This commit is contained in:
@@ -1138,7 +1138,7 @@ PyObject *PythonContext::outstream_write(PyObject *self, PyObject *args)
|
||||
_frame *frame = PyEval_GetFrame();
|
||||
|
||||
while(message.back() == '\n' || message.back() == '\r')
|
||||
message.erase(message.size() - 1);
|
||||
message.pop_back();
|
||||
|
||||
QString filename = lit("unknown");
|
||||
int line = 0;
|
||||
|
||||
@@ -1018,19 +1018,9 @@ QString PipelineStateViewer::GetVBufferFormatString(uint32_t slot)
|
||||
uint32_t stride = vbs[slot].byteStride;
|
||||
|
||||
// filter attributes to only the ones enabled and using this slot
|
||||
for(size_t i = 0; i < attrs.size();)
|
||||
{
|
||||
if(!attrs[i].used || attrs[i].vertexBuffer != (int)slot)
|
||||
{
|
||||
attrs.erase(i);
|
||||
// continue with same i
|
||||
}
|
||||
else
|
||||
{
|
||||
// move to next i
|
||||
i++;
|
||||
}
|
||||
}
|
||||
attrs.removeIf([slot](const VertexInputAttribute &attr) {
|
||||
return (!attr.used || attr.vertexBuffer != (int)slot);
|
||||
});
|
||||
|
||||
// we now have all attributes in this buffer. Sort by offset
|
||||
std::sort(attrs.begin(), attrs.end(),
|
||||
|
||||
@@ -594,7 +594,7 @@ struct AndroidRemoteServer : public RemoteServer
|
||||
rdcstr package = path;
|
||||
|
||||
if(!package.empty() && package[0] == '/')
|
||||
package.erase(0);
|
||||
package.erase(0, 1);
|
||||
|
||||
std::vector<PathEntry> activities;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <stdint.h> // for standard types
|
||||
#include <string.h> // for memcpy, etc
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
@@ -150,6 +151,12 @@ public:
|
||||
typedef T value_type;
|
||||
|
||||
rdcarray() : elems(NULL), allocatedCount(0), usedCount(0) {}
|
||||
rdcarray(size_t count)
|
||||
{
|
||||
elems = NULL;
|
||||
allocatedCount = usedCount = 0;
|
||||
resize(count);
|
||||
}
|
||||
~rdcarray()
|
||||
{
|
||||
// clear will destruct the actual elements still existing
|
||||
@@ -192,7 +199,22 @@ public:
|
||||
size_t capacity() const { return allocatedCount; }
|
||||
bool empty() const { return usedCount == 0; }
|
||||
bool isEmpty() const { return usedCount == 0; }
|
||||
void clear() { resize(0); }
|
||||
void clear()
|
||||
{
|
||||
// we specialise clear() so that it doesn't implicitly require a default constructor of T()
|
||||
// resize(0);
|
||||
|
||||
size_t sz = size();
|
||||
|
||||
if(sz == 0)
|
||||
return;
|
||||
|
||||
setUsedCount(0);
|
||||
|
||||
// destroy the old items
|
||||
ItemDestroyHelper<T>::destroyRange(elems, sz);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// managing elements and memory
|
||||
|
||||
@@ -267,8 +289,24 @@ public:
|
||||
setUsedCount(usedCount + 1);
|
||||
}
|
||||
|
||||
// fill the string with 'count' copies of 'el'
|
||||
void fill(size_t count, const T &el)
|
||||
{
|
||||
// destruct any old elements
|
||||
clear();
|
||||
// ensure we have enough space for the count
|
||||
reserve(count);
|
||||
// copy-construct all elements in place and update space
|
||||
for(size_t i = 0; i < count; i++)
|
||||
new(elems + i) T(el);
|
||||
setUsedCount(count);
|
||||
}
|
||||
|
||||
void insert(size_t offs, const T *el, size_t count)
|
||||
{
|
||||
if(count == 0)
|
||||
return;
|
||||
|
||||
if(elems < el + count && el < elems + allocatedCount)
|
||||
{
|
||||
// we're inserting from ourselves, so if we did this blindly we'd potentially change the
|
||||
@@ -403,12 +441,21 @@ public:
|
||||
}
|
||||
// helpful shortcut for 'append at end', basically a multi-element push_back
|
||||
inline void append(const T *el, size_t count) { insert(size(), el, count); }
|
||||
inline void append(const rdcarray<T> &in) { insert(size(), in.data(), in.size()); }
|
||||
void erase(size_t offs, size_t count = 1)
|
||||
{
|
||||
// invalid count
|
||||
if(offs + count > size())
|
||||
if(count == 0)
|
||||
return;
|
||||
|
||||
const size_t sz = size();
|
||||
|
||||
// invalid offset
|
||||
if(offs >= sz)
|
||||
return;
|
||||
|
||||
if(count > sz - offs)
|
||||
count = sz - offs;
|
||||
|
||||
// this is simpler to implement than insert(). We do two simpler passes:
|
||||
//
|
||||
// Pass 1: Iterate over the secified range, destruct it.
|
||||
@@ -420,7 +467,7 @@ public:
|
||||
elems[offs + i].~T();
|
||||
|
||||
// move remaining elements into place
|
||||
for(size_t i = offs + count; i < size(); i++)
|
||||
for(size_t i = offs + count; i < sz; i++)
|
||||
{
|
||||
new(elems + i - count) T(elems[i]);
|
||||
elems[i].~T();
|
||||
@@ -430,6 +477,12 @@ public:
|
||||
setUsedCount(usedCount - count);
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if(!empty())
|
||||
erase(size() - 1);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Qt style helper functions
|
||||
|
||||
@@ -463,6 +516,35 @@ public:
|
||||
erase((size_t)idx);
|
||||
}
|
||||
|
||||
void removeIf(std::function<bool(const T &)> predicate)
|
||||
{
|
||||
for(size_t i = 0; i < size();)
|
||||
{
|
||||
if(predicate(at(i)))
|
||||
{
|
||||
erase(i);
|
||||
// continue with same i
|
||||
}
|
||||
else
|
||||
{
|
||||
// move to next i
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeOneIf(std::function<bool(const T &)> predicate)
|
||||
{
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
if(predicate(at(i)))
|
||||
{
|
||||
erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// constructors that just forward to assign
|
||||
rdcarray(const T *in, size_t count)
|
||||
@@ -497,6 +579,39 @@ public:
|
||||
std::swap(usedCount, other.usedCount);
|
||||
}
|
||||
|
||||
// move operator/constructor using swap
|
||||
|
||||
rdcarray &operator=(rdcarray &&in)
|
||||
{
|
||||
// if we have old elems, clear (to destruct) and deallocate
|
||||
if(elems)
|
||||
{
|
||||
clear();
|
||||
deallocate(elems);
|
||||
}
|
||||
|
||||
// set ourselves to a pristine state
|
||||
elems = NULL;
|
||||
allocatedCount = 0;
|
||||
usedCount = 0;
|
||||
|
||||
// now swap with the incoming array, so it becomes empty
|
||||
swap(in);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
rdcarray(rdcarray &&in)
|
||||
{
|
||||
// set ourselves to a pristine state
|
||||
elems = NULL;
|
||||
allocatedCount = 0;
|
||||
usedCount = 0;
|
||||
|
||||
// now swap with the incoming array, so it becomes empty
|
||||
swap(in);
|
||||
}
|
||||
|
||||
// assign forwards to operator =
|
||||
inline void assign(const std::vector<T> &in) { *this = in; }
|
||||
inline void assign(const std::initializer_list<T> &in) { *this = in; }
|
||||
@@ -632,6 +747,8 @@ struct bytebuf : public rdcarray<byte>
|
||||
{
|
||||
bytebuf() : rdcarray<byte>() {}
|
||||
bytebuf(const std::vector<byte> &in) : rdcarray<byte>(in) {}
|
||||
bytebuf(const std::initializer_list<byte> &in) : rdcarray<byte>(in) {}
|
||||
bytebuf(const byte *in, size_t size) : rdcarray<byte>(in, size) {}
|
||||
#if defined(RENDERDOC_QT_COMPAT)
|
||||
bytebuf(const QByteArray &in)
|
||||
{
|
||||
|
||||
+226
-17
@@ -270,9 +270,19 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void swap(rdcstr &other)
|
||||
{
|
||||
// just need to swap the d element
|
||||
std::swap(d, other.d);
|
||||
}
|
||||
|
||||
// assign from an rdcstr, copy the d element and allocate if needed
|
||||
void assign(const rdcstr &in)
|
||||
{
|
||||
// do nothing if we're self-assigning
|
||||
if(this == &in)
|
||||
return;
|
||||
|
||||
// if the input d is allocated, we need to make our own allocation. Go through the standard
|
||||
// string assignment function which will allocate & copy
|
||||
if(in.is_alloc())
|
||||
@@ -314,7 +324,7 @@ public:
|
||||
void append(const std::string &str) { append(str.c_str(), str.size()); }
|
||||
void append(const rdcstr &str) { append(str.c_str(), str.size()); }
|
||||
void append(const char *const str, size_t length) { insert(size(), str, length); }
|
||||
void erase(size_t offs, size_t count = 1)
|
||||
void erase(size_t offs, size_t count)
|
||||
{
|
||||
const size_t sz = size();
|
||||
|
||||
@@ -335,8 +345,24 @@ public:
|
||||
void insert(size_t offset, const char *const str) { insert(offset, str, strlen(str)); }
|
||||
void insert(size_t offset, const std::string &str) { insert(offset, str.c_str(), str.size()); }
|
||||
void insert(size_t offset, const rdcstr &str) { insert(offset, str.c_str(), str.size()); }
|
||||
void insert(size_t offset, char c) { insert(offset, &c, 1); }
|
||||
void insert(size_t offset, const char *const instr, size_t length)
|
||||
{
|
||||
if(!is_fixed() && instr + length >= begin() && end() >= instr)
|
||||
{
|
||||
// we're inserting from ourselves and we're not allocated, so if we did this blindly
|
||||
// we'd potentially change the contents of the inserted range while doing the insertion.
|
||||
// To fix that, we store our original data in a temp and copy into ourselves again. Then we
|
||||
// insert from the temp copy and let it be destroyed.
|
||||
// This could be more efficient as an append and then a rotate, but this is simpler for now.
|
||||
rdcstr copy;
|
||||
copy.swap(*this);
|
||||
this->reserve(copy.capacity() + length);
|
||||
*this = copy;
|
||||
insert(offset, copy.c_str(), copy.size());
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t sz = size();
|
||||
|
||||
// invalid offset
|
||||
@@ -361,6 +387,19 @@ public:
|
||||
d.arr.set_size(sz + length);
|
||||
}
|
||||
|
||||
void replace(size_t offset, size_t length, const rdcstr &str)
|
||||
{
|
||||
erase(offset, length);
|
||||
insert(offset, str);
|
||||
}
|
||||
|
||||
// fill the string with 'count' copies of 'c'
|
||||
void fill(size_t count, char c)
|
||||
{
|
||||
resize(count);
|
||||
memset(data(), c, count);
|
||||
}
|
||||
|
||||
// cast operators
|
||||
operator std::string() const
|
||||
{
|
||||
@@ -369,7 +408,7 @@ public:
|
||||
}
|
||||
|
||||
// read-only by-value accessor can look up directly in c_str() since it can't be modified
|
||||
char operator[](size_t i) const { return c_str()[i]; }
|
||||
const char &operator[](size_t i) const { return c_str()[i]; }
|
||||
// assignment operator must make the string mutable first
|
||||
char &operator[](size_t i)
|
||||
{
|
||||
@@ -540,6 +579,8 @@ public:
|
||||
}
|
||||
const char *begin() const { return c_str(); }
|
||||
const char *end() const { return c_str() + size(); }
|
||||
char *begin() { return data(); }
|
||||
char *end() { return data() + size(); }
|
||||
char front() const { return *c_str(); }
|
||||
char &front()
|
||||
{
|
||||
@@ -553,7 +594,7 @@ public:
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
rdcstr substr(size_t offs, size_t length = ~0U)
|
||||
rdcstr substr(size_t offs, size_t length = ~0U) const
|
||||
{
|
||||
const size_t sz = size();
|
||||
if(offs >= sz)
|
||||
@@ -580,6 +621,11 @@ public:
|
||||
append(str.c_str(), str.size());
|
||||
return *this;
|
||||
}
|
||||
rdcstr &operator+=(char c)
|
||||
{
|
||||
push_back(c);
|
||||
return *this;
|
||||
}
|
||||
rdcstr operator+(const char *const str) const
|
||||
{
|
||||
rdcstr ret = *this;
|
||||
@@ -598,24 +644,36 @@ public:
|
||||
ret += str;
|
||||
return ret;
|
||||
}
|
||||
rdcstr operator+(const char c) const
|
||||
{
|
||||
rdcstr ret = *this;
|
||||
ret += c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Qt-type interface
|
||||
bool isEmpty() const { return size() == 0; }
|
||||
int32_t count() const { return (int32_t)size(); }
|
||||
char takeAt(size_t offs)
|
||||
char takeAt(int32_t offs)
|
||||
{
|
||||
char ret = c_str()[offs];
|
||||
erase(offs);
|
||||
erase(offs, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Python interface
|
||||
int32_t indexOf(char el, size_t first = 0, size_t last = ~0U) const
|
||||
int32_t indexOf(char el, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
const char *str = c_str();
|
||||
const size_t sz = size();
|
||||
if(first < 0)
|
||||
return -1;
|
||||
|
||||
for(size_t i = first; i < sz && i < last; i++)
|
||||
const char *str = c_str();
|
||||
size_t sz = size();
|
||||
|
||||
if(last >= 0 && (size_t)last < sz)
|
||||
sz = last;
|
||||
|
||||
for(size_t i = first; i < sz; i++)
|
||||
{
|
||||
if(str[i] == el)
|
||||
return (int32_t)i;
|
||||
@@ -624,18 +682,32 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t find(const char *needle_str, size_t needle_len, size_t first = 0, size_t last = ~0U) const
|
||||
// find a substring. Optionally starting at a given 'first' character and not including an
|
||||
// optional 'last' character. If last is -1 (the default), the whole string is searched
|
||||
int32_t find(const char *needle_str, size_t needle_len, int32_t first, int32_t last) const
|
||||
{
|
||||
// no default parameters for first/last here because otherwise it'd be dangerous with casting
|
||||
// and
|
||||
// misusing this instead of just specifying a 'first' below.
|
||||
const char *haystack = c_str();
|
||||
const size_t haystack_len = size();
|
||||
size_t haystack_len = size();
|
||||
|
||||
if(needle_len > haystack_len)
|
||||
if(first < 0)
|
||||
return -1;
|
||||
|
||||
if(needle_len == 0)
|
||||
return 0;
|
||||
|
||||
for(size_t i = first; i <= haystack_len - needle_len && i < last; i++)
|
||||
if(last >= 0 && (size_t)last < haystack_len)
|
||||
haystack_len = last;
|
||||
|
||||
if((size_t)first >= haystack_len)
|
||||
return -1;
|
||||
|
||||
if(needle_len > haystack_len - first)
|
||||
return -1;
|
||||
|
||||
for(size_t i = first; i <= haystack_len - needle_len; i++)
|
||||
{
|
||||
if(strncmp(haystack + i, needle_str, needle_len) == 0)
|
||||
return (int32_t)i;
|
||||
@@ -644,28 +716,165 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t find(const rdcstr &needle, size_t first = 0, size_t last = ~0U) const
|
||||
int32_t find(const char needle, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
if(first < 0)
|
||||
return -1;
|
||||
|
||||
const char *haystack = c_str();
|
||||
size_t haystack_len = size();
|
||||
|
||||
if(last >= 0 && (size_t)last < haystack_len)
|
||||
haystack_len = last;
|
||||
|
||||
for(size_t i = first; i < haystack_len; i++)
|
||||
{
|
||||
if(haystack[i] == needle)
|
||||
return (int32_t)i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t find(const rdcstr &needle, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find(needle.c_str(), needle.size(), first, last);
|
||||
}
|
||||
int32_t find(const std::string &needle, size_t first = 0, size_t last = ~0U) const
|
||||
int32_t find(const std::string &needle, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find(needle.c_str(), needle.size(), first, last);
|
||||
}
|
||||
int32_t find(const char *needle, size_t first = 0, size_t last = ~0U) const
|
||||
int32_t find(const char *needle, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find(needle, strlen(needle), first, last);
|
||||
}
|
||||
|
||||
// find the first character that is in a given set of characters, from the start of the string
|
||||
// Optionally starting at a given 'first' character and not including an optional 'last'
|
||||
// character. If last is -1 (the default), the whole string is searched
|
||||
int32_t find_first_of(const rdcstr &needle_set, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find_first_last(needle_set, true, true, first, last);
|
||||
}
|
||||
// find the first character that is not in a given set of characters, from the start of the string
|
||||
int32_t find_first_not_of(const rdcstr &needle_set, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find_first_last(needle_set, true, false, first, last);
|
||||
}
|
||||
// find the first character that is in a given set of characters, from the end of the string
|
||||
int32_t find_last_of(const rdcstr &needle_set, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find_first_last(needle_set, false, true, first, last);
|
||||
}
|
||||
// find the first character that is not in a given set of characters, from the end of the string
|
||||
int32_t find_last_not_of(const rdcstr &needle_set, int32_t first = 0, int32_t last = -1) const
|
||||
{
|
||||
return find_first_last(needle_set, false, false, first, last);
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t find_first_last(const rdcstr &needle_set, bool forward_search, bool search_in_set,
|
||||
int32_t first, int32_t last) const
|
||||
{
|
||||
if(first < 0)
|
||||
return -1;
|
||||
|
||||
const char *haystack = c_str();
|
||||
size_t haystack_len = size();
|
||||
|
||||
if(last >= 0 && (size_t)last < haystack_len)
|
||||
haystack_len = last;
|
||||
|
||||
if(forward_search)
|
||||
{
|
||||
for(size_t i = first; i < haystack_len; i++)
|
||||
{
|
||||
bool in_set = needle_set.contains(haystack[i]);
|
||||
if(in_set == search_in_set)
|
||||
return (int32_t)i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t i = 0; i < haystack_len; i++)
|
||||
{
|
||||
size_t idx = haystack_len - 1 - i;
|
||||
|
||||
if(idx < (size_t)first)
|
||||
break;
|
||||
|
||||
bool in_set = needle_set.contains(haystack[idx]);
|
||||
if(in_set == search_in_set)
|
||||
return (int32_t)idx;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
bool contains(char needle) const { return indexOf(needle) != -1; }
|
||||
bool contains(const rdcstr &needle) const { return find(needle) != -1; }
|
||||
bool contains(const std::string &needle) const { return find(needle) != -1; }
|
||||
bool contains(const char *needle) const { return find(needle) != -1; }
|
||||
bool beginsWith(const rdcstr &beginning) const
|
||||
{
|
||||
if(beginning.length() > length())
|
||||
return false;
|
||||
|
||||
return !strncmp(c_str(), beginning.c_str(), beginning.length());
|
||||
}
|
||||
bool endsWith(const rdcstr &ending) const
|
||||
{
|
||||
if(ending.length() > length())
|
||||
return false;
|
||||
|
||||
return !strcmp(c_str() + length() - ending.length(), ending.c_str());
|
||||
}
|
||||
|
||||
void removeOne(char el)
|
||||
{
|
||||
int idx = indexOf(el);
|
||||
if(idx >= 0)
|
||||
erase((size_t)idx);
|
||||
erase((size_t)idx, 1);
|
||||
}
|
||||
|
||||
// remove any preceeding or trailing whitespace from the string, in-place
|
||||
void trim()
|
||||
{
|
||||
if(empty())
|
||||
return;
|
||||
|
||||
#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
|
||||
|
||||
const char *str = c_str();
|
||||
size_t sz = size();
|
||||
|
||||
size_t start = 0;
|
||||
while(start < sz && IS_WHITESPACE(str[start]))
|
||||
start++;
|
||||
|
||||
size_t end = sz - 1;
|
||||
while(end > start && IS_WHITESPACE(str[end]))
|
||||
end--;
|
||||
|
||||
// no non-whitespace characters, become the empty string
|
||||
if(start >= end)
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
erase(end + 1, ~0U);
|
||||
erase(0, start);
|
||||
}
|
||||
|
||||
// return a copy of the string with preceeding and trailing whitespace removed
|
||||
rdcstr trimmed() const
|
||||
{
|
||||
rdcstr ret = *this;
|
||||
ret.trim();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// for equality check with rdcstr, check quickly for empty string comparisons
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "3rdparty/catch/catch.hpp"
|
||||
|
||||
static volatile int32_t constructor = 0;
|
||||
static volatile int32_t moveConstructor = 0;
|
||||
static volatile int32_t valueConstructor = 0;
|
||||
static volatile int32_t copyConstructor = 0;
|
||||
static volatile int32_t destructor = 0;
|
||||
@@ -55,11 +56,27 @@ struct ConstructorCounter
|
||||
value = other.value;
|
||||
Atomic::Inc32(©Constructor);
|
||||
}
|
||||
ConstructorCounter(ConstructorCounter &&other)
|
||||
{
|
||||
value = other.value;
|
||||
other.value = -9999;
|
||||
Atomic::Inc32(&moveConstructor);
|
||||
}
|
||||
ConstructorCounter &operator=(const ConstructorCounter &other) = delete;
|
||||
ConstructorCounter &operator=(ConstructorCounter &&other) = delete;
|
||||
~ConstructorCounter() { Atomic::Inc32(&destructor); }
|
||||
bool operator==(const ConstructorCounter &other) { return value == other.value; }
|
||||
};
|
||||
|
||||
TEST_CASE("Test array type", "[basictypes]")
|
||||
{
|
||||
// reset globals
|
||||
constructor = 0;
|
||||
moveConstructor = 0;
|
||||
valueConstructor = 0;
|
||||
copyConstructor = 0;
|
||||
destructor = 0;
|
||||
|
||||
SECTION("Basic test")
|
||||
{
|
||||
rdcarray<int> test;
|
||||
@@ -240,7 +257,7 @@ TEST_CASE("Test array type", "[basictypes]")
|
||||
};
|
||||
};
|
||||
|
||||
SECTION("Verify insert()")
|
||||
SECTION("insert")
|
||||
{
|
||||
rdcarray<int> vec;
|
||||
vec.insert(0, {});
|
||||
@@ -304,7 +321,7 @@ TEST_CASE("Test array type", "[basictypes]")
|
||||
CHECK(vec[8] == 4);
|
||||
|
||||
// insert a large amount of data to ensure this doesn't read off start/end of vector
|
||||
std::vector<int> largedata;
|
||||
rdcarray<int> largedata;
|
||||
largedata.resize(100000);
|
||||
|
||||
vec.insert(4, largedata);
|
||||
@@ -353,7 +370,7 @@ TEST_CASE("Test array type", "[basictypes]")
|
||||
CHECK(vec[14] == 16);
|
||||
};
|
||||
|
||||
SECTION("Verify erase()")
|
||||
SECTION("erase")
|
||||
{
|
||||
rdcarray<int> vec = {6, 3, 13, 5};
|
||||
|
||||
@@ -408,6 +425,69 @@ TEST_CASE("Test array type", "[basictypes]")
|
||||
CHECK(vec[0] == 5);
|
||||
CHECK(vec[1] == 6);
|
||||
CHECK(vec[2] == 3);
|
||||
|
||||
vec = {5, 6, 3, 9, 1, 0};
|
||||
|
||||
vec.erase(3, 100);
|
||||
REQUIRE(vec.size() == 3);
|
||||
CHECK(vec[0] == 5);
|
||||
CHECK(vec[1] == 6);
|
||||
CHECK(vec[2] == 3);
|
||||
};
|
||||
|
||||
SECTION("removeOne / removeOneIf / removeIf")
|
||||
{
|
||||
rdcarray<int> vec = {6, 3, 9, 6, 6, 3, 5, 15, 5};
|
||||
|
||||
vec.removeOne(3);
|
||||
|
||||
REQUIRE(vec.size() == 8);
|
||||
CHECK(vec[0] == 6);
|
||||
CHECK(vec[1] == 9);
|
||||
CHECK(vec[2] == 6);
|
||||
CHECK(vec[3] == 6);
|
||||
CHECK(vec[4] == 3);
|
||||
CHECK(vec[5] == 5);
|
||||
CHECK(vec[6] == 15);
|
||||
CHECK(vec[7] == 5);
|
||||
|
||||
vec.removeOne(3);
|
||||
|
||||
REQUIRE(vec.size() == 7);
|
||||
CHECK(vec[0] == 6);
|
||||
CHECK(vec[1] == 9);
|
||||
CHECK(vec[2] == 6);
|
||||
CHECK(vec[3] == 6);
|
||||
CHECK(vec[4] == 5);
|
||||
CHECK(vec[5] == 15);
|
||||
CHECK(vec[6] == 5);
|
||||
|
||||
vec.removeOne(3);
|
||||
|
||||
REQUIRE(vec.size() == 7);
|
||||
CHECK(vec[0] == 6);
|
||||
CHECK(vec[1] == 9);
|
||||
CHECK(vec[2] == 6);
|
||||
CHECK(vec[3] == 6);
|
||||
CHECK(vec[4] == 5);
|
||||
CHECK(vec[5] == 15);
|
||||
CHECK(vec[6] == 5);
|
||||
|
||||
vec.removeOneIf([](const int &el) { return (el % 3) == 0; });
|
||||
|
||||
REQUIRE(vec.size() == 6);
|
||||
CHECK(vec[0] == 9);
|
||||
CHECK(vec[1] == 6);
|
||||
CHECK(vec[2] == 6);
|
||||
CHECK(vec[3] == 5);
|
||||
CHECK(vec[4] == 15);
|
||||
CHECK(vec[5] == 5);
|
||||
|
||||
vec.removeIf([](const int &el) { return (el % 3) == 0; });
|
||||
|
||||
REQUIRE(vec.size() == 2);
|
||||
CHECK(vec[0] == 5);
|
||||
CHECK(vec[1] == 5);
|
||||
};
|
||||
|
||||
SECTION("Check construction")
|
||||
@@ -415,6 +495,7 @@ TEST_CASE("Test array type", "[basictypes]")
|
||||
rdcarray<ConstructorCounter> test;
|
||||
|
||||
CHECK(constructor == 0);
|
||||
CHECK(moveConstructor == 0);
|
||||
CHECK(valueConstructor == 0);
|
||||
CHECK(copyConstructor == 0);
|
||||
CHECK(destructor == 0);
|
||||
@@ -489,6 +570,89 @@ TEST_CASE("Test array type", "[basictypes]")
|
||||
CHECK(constructor == 50);
|
||||
CHECK(valueConstructor == 1);
|
||||
CHECK(copyConstructor == 3);
|
||||
|
||||
// still should have had no moves
|
||||
CHECK(moveConstructor == 0);
|
||||
|
||||
// reset counters
|
||||
constructor = 0;
|
||||
valueConstructor = 0;
|
||||
copyConstructor = 0;
|
||||
destructor = 0;
|
||||
|
||||
CHECK(constructor == 0);
|
||||
CHECK(moveConstructor == 0);
|
||||
CHECK(valueConstructor == 0);
|
||||
CHECK(copyConstructor == 0);
|
||||
CHECK(destructor == 0);
|
||||
|
||||
auto lambda = []() -> rdcarray<ConstructorCounter> {
|
||||
rdcarray<ConstructorCounter> ret;
|
||||
ConstructorCounter tmp(9);
|
||||
ret.push_back(tmp);
|
||||
return ret;
|
||||
};
|
||||
|
||||
test = lambda();
|
||||
|
||||
// ensure that the value constructor was called only once within the lambda
|
||||
CHECK(valueConstructor == 1);
|
||||
|
||||
// the copy constructor was called in push_back
|
||||
CHECK(copyConstructor == 1);
|
||||
|
||||
// the destructor was called once for tmp
|
||||
CHECK(destructor == 1);
|
||||
|
||||
// and no default construction or moves
|
||||
CHECK(constructor == 0);
|
||||
CHECK(moveConstructor == 0);
|
||||
|
||||
// check that the new value arrived
|
||||
CHECK(test.back().value == 9);
|
||||
};
|
||||
|
||||
SECTION("operations with empty array")
|
||||
{
|
||||
rdcarray<ConstructorCounter> test;
|
||||
|
||||
ConstructorCounter val;
|
||||
|
||||
test.append(test);
|
||||
|
||||
CHECK(test.empty());
|
||||
|
||||
test.insert(0, test);
|
||||
|
||||
CHECK(test.empty());
|
||||
|
||||
test.removeOne(val);
|
||||
|
||||
CHECK(test.empty());
|
||||
|
||||
test.assign(test.data(), test.size());
|
||||
|
||||
CHECK(test.empty());
|
||||
|
||||
CHECK(test.indexOf(val) == -1);
|
||||
|
||||
rdcarray<ConstructorCounter> test2(test);
|
||||
|
||||
CHECK(test.empty());
|
||||
CHECK(test2.empty());
|
||||
|
||||
rdcarray<ConstructorCounter> test3;
|
||||
|
||||
test3 = test;
|
||||
|
||||
CHECK(test.empty());
|
||||
CHECK(test3.empty());
|
||||
|
||||
CHECK(constructor == 1);
|
||||
CHECK(moveConstructor == 0);
|
||||
CHECK(valueConstructor == 0);
|
||||
CHECK(copyConstructor == 0);
|
||||
CHECK(destructor == 0);
|
||||
};
|
||||
|
||||
SECTION("Inserting from array into itself")
|
||||
@@ -775,6 +939,36 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
lambda(STRING_LITERAL(LARGE_STRING), LARGE_STRING);
|
||||
};
|
||||
|
||||
SECTION("Inserting from string into itself")
|
||||
{
|
||||
auto lambda = [](rdcstr test) {
|
||||
|
||||
// create a version without doing self-insertion
|
||||
rdcstr test2 = test;
|
||||
|
||||
test2.insert(4, test);
|
||||
|
||||
test.insert(4, test);
|
||||
|
||||
CHECK(test.size() == test2.size());
|
||||
CHECK(test.empty() == test2.empty());
|
||||
|
||||
for(size_t i = 0; i < test.size(); i++)
|
||||
{
|
||||
CHECK(test[i] == test2[i]);
|
||||
}
|
||||
|
||||
CHECK(test.c_str() != test2.c_str());
|
||||
};
|
||||
|
||||
// need a small string small enough that even doubling it is still small
|
||||
lambda("foo");
|
||||
lambda(SMALL_STRING);
|
||||
lambda(LARGE_STRING);
|
||||
lambda(VERY_LARGE_STRING);
|
||||
lambda(STRING_LITERAL(LARGE_STRING));
|
||||
};
|
||||
|
||||
SECTION("Shrinking and expanding strings")
|
||||
{
|
||||
rdcstr test = "A longer string that would have been heap allocated";
|
||||
@@ -851,7 +1045,11 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
{
|
||||
rdcstr test = "Hello, World! This is a test string";
|
||||
|
||||
test.erase(0);
|
||||
test.erase(0, 0);
|
||||
|
||||
CHECK(test == "Hello, World! This is a test string");
|
||||
|
||||
test.erase(0, 1);
|
||||
|
||||
CHECK(test == "ello, World! This is a test string");
|
||||
|
||||
@@ -867,7 +1065,7 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
|
||||
CHECK(test == ", World! is a ");
|
||||
|
||||
test.erase(100);
|
||||
test.erase(100, 1);
|
||||
|
||||
CHECK(test == ", World! is a ");
|
||||
|
||||
@@ -899,6 +1097,13 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
test2 += ", " + test + "?";
|
||||
|
||||
CHECK(test2 == "Hello World! And enough characters to force an allocation, Hello World?");
|
||||
|
||||
test += '?';
|
||||
CHECK(test == "Hello World?");
|
||||
|
||||
test2 = test + '!';
|
||||
|
||||
CHECK(test2 == "Hello World?!");
|
||||
};
|
||||
|
||||
SECTION("insert")
|
||||
@@ -918,6 +1123,77 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
test2.insert(100, "foo");
|
||||
|
||||
CHECK(test2 == "Hello, World!Hello, World!");
|
||||
|
||||
test2.insert(4, '_');
|
||||
|
||||
CHECK(test2 == "Hell_o, World!Hello, World!");
|
||||
};
|
||||
|
||||
SECTION("replace")
|
||||
{
|
||||
rdcstr test = "Hello, World!";
|
||||
|
||||
test.replace(5, 1, ".");
|
||||
|
||||
CHECK(test == "Hello. World!");
|
||||
|
||||
test.replace(7, 3, "Fau");
|
||||
|
||||
CHECK(test == "Hello. Fauld!");
|
||||
|
||||
test.replace(0, 0, "Hi! ");
|
||||
|
||||
CHECK(test == "Hi! Hello. Fauld!");
|
||||
|
||||
test.replace(0, 99, "Test");
|
||||
|
||||
CHECK(test == "Test");
|
||||
|
||||
test.replace(2, 99, "sting!");
|
||||
|
||||
CHECK(test == "Testing!");
|
||||
|
||||
test.replace(20, 99, "Invalid?");
|
||||
|
||||
CHECK(test == "Testing!");
|
||||
};
|
||||
|
||||
SECTION("beginsWith / endsWith")
|
||||
{
|
||||
rdcstr test = "foobar";
|
||||
|
||||
CHECK_FALSE(test.beginsWith("bar"));
|
||||
CHECK(test.beginsWith("foo"));
|
||||
CHECK(test.beginsWith(""));
|
||||
|
||||
CHECK(test.endsWith("bar"));
|
||||
CHECK_FALSE(test.endsWith("foo"));
|
||||
CHECK(test.endsWith(""));
|
||||
|
||||
test = "";
|
||||
|
||||
CHECK(test.endsWith(""));
|
||||
CHECK_FALSE(test.endsWith("foo"));
|
||||
|
||||
CHECK(test.beginsWith(""));
|
||||
CHECK_FALSE(test.beginsWith("foo"));
|
||||
|
||||
test = "bar";
|
||||
|
||||
CHECK_FALSE(test.beginsWith("foobar"));
|
||||
CHECK_FALSE(test.endsWith("foobar"));
|
||||
};
|
||||
|
||||
SECTION("trim / trimmed")
|
||||
{
|
||||
CHECK(rdcstr(" foo bar ").trimmed() == "foo bar");
|
||||
CHECK(rdcstr(" Foo bar").trimmed() == "Foo bar");
|
||||
CHECK(rdcstr(" Foo\nbar").trimmed() == "Foo\nbar");
|
||||
CHECK(rdcstr("FOO BAR ").trimmed() == "FOO BAR");
|
||||
CHECK(rdcstr("FOO BAR \t\n").trimmed() == "FOO BAR");
|
||||
CHECK(rdcstr("").trimmed() == "");
|
||||
CHECK(rdcstr(" ").trimmed() == "");
|
||||
CHECK(rdcstr(" \t \n ").trimmed() == "");
|
||||
};
|
||||
|
||||
SECTION("push_back and pop_back")
|
||||
@@ -1025,6 +1301,7 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
CHECK(test.find("Hello, World!!") == -1);
|
||||
CHECK(test.find("Hello, World?") == -1);
|
||||
CHECK(test.find("") == 0);
|
||||
CHECK(test.find(',') == 5);
|
||||
|
||||
CHECK(test.indexOf('H') == 0);
|
||||
CHECK(test.indexOf('l') == 2);
|
||||
@@ -1047,8 +1324,176 @@ TEST_CASE("Test string type", "[basictypes][string]")
|
||||
CHECK_FALSE(test.contains('!'));
|
||||
|
||||
CHECK(test == "ello, World");
|
||||
|
||||
CHECK(test.find_first_of("lo") == 1);
|
||||
CHECK(test.find_first_of("ol") == 1);
|
||||
CHECK(test.find_first_of("foobarl") == 1);
|
||||
CHECK(test.find_first_of("foobar") == 3);
|
||||
CHECK(test.find_first_of("oforab") == 3);
|
||||
CHECK(test.find_first_of("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!o") == 3);
|
||||
CHECK(test.find_first_of("!?$") == -1);
|
||||
CHECK(test.find_first_of("") == -1);
|
||||
|
||||
CHECK(test.find_last_of("or") == 8);
|
||||
CHECK(test.find_last_of("ro") == 8);
|
||||
CHECK(test.find_last_of("foobard") == 10);
|
||||
CHECK(test.find_last_of("foobar") == 8);
|
||||
CHECK(test.find_last_of("oforab") == 8);
|
||||
CHECK(test.find_last_of("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!r") == 8);
|
||||
CHECK(test.find_last_of("!?$") == -1);
|
||||
CHECK(test.find_last_of("") == -1);
|
||||
|
||||
CHECK(test.find_first_not_of("oel") == 4);
|
||||
CHECK(test.find_first_not_of("le") == 3);
|
||||
CHECK(test.find_first_not_of("oelWr") == 4);
|
||||
CHECK(test.find_first_not_of("ooollele") == 4);
|
||||
CHECK(test.find_first_not_of("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!e") == 1);
|
||||
CHECK(test.find_first_not_of("!?$") == 0);
|
||||
CHECK(test.find_first_not_of("") == 0);
|
||||
CHECK(test.find_first_not_of("W, rdleo") == -1);
|
||||
|
||||
CHECK(test.find_last_not_of("dl") == 8);
|
||||
CHECK(test.find_last_not_of("ld") == 8);
|
||||
CHECK(test.find_last_not_of("ldWr") == 7);
|
||||
CHECK(test.find_last_not_of("WWrldlRw") == 7);
|
||||
CHECK(test.find_last_not_of("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!d") == 9);
|
||||
CHECK(test.find_last_not_of("!?$") == 10);
|
||||
CHECK(test.find_last_not_of("") == 10);
|
||||
CHECK(test.find_last_not_of("W, rdleo") == -1);
|
||||
|
||||
// 0 1 2 3
|
||||
// 012345678901234567890123456789012345678
|
||||
test = "Test of substring matches and sub-find!";
|
||||
|
||||
// test with first before of the first 'sub'
|
||||
CHECK(test.find("sub") == 8);
|
||||
CHECK(test.find("sub", 4) == 8);
|
||||
CHECK(test.find("sub", 8) == 8);
|
||||
|
||||
// first after first and before second
|
||||
CHECK(test.find("sub", 9) == 30);
|
||||
CHECK(test.find("sub", 10) == 30);
|
||||
CHECK(test.find("sub", 11) == 30);
|
||||
CHECK(test.find("sub", 29) == 30);
|
||||
CHECK(test.find("sub", 30) == 30);
|
||||
|
||||
// first past the second
|
||||
CHECK(test.find("sub", 31) == -1);
|
||||
|
||||
// first past the end of the string
|
||||
CHECK(test.find("sub", 40) == -1);
|
||||
|
||||
// first and last around first sub
|
||||
CHECK(test.find("sub", 4, 12) == 8);
|
||||
CHECK(test.find("sub", 4, 11) == 8);
|
||||
CHECK(test.find("sub", 7, 11) == 8);
|
||||
CHECK(test.find("sub", 8, 11) == 8);
|
||||
|
||||
// first before but last not including first sub
|
||||
CHECK(test.find("sub", 4, 9) == -1);
|
||||
CHECK(test.find("sub", 8, 10) == -1);
|
||||
CHECK(test.find("sub", 8, 9) == -1);
|
||||
|
||||
// first after and last after
|
||||
CHECK(test.find("sub", 9, 11) == -1);
|
||||
|
||||
// empty range
|
||||
CHECK(test.find("sub", 9, 9) == -1);
|
||||
CHECK(test.find("sub", 8, 8) == -1);
|
||||
|
||||
// invalid range
|
||||
CHECK(test.find("sub", 10, 9) == -1);
|
||||
|
||||
CHECK(test.find("find!") == 34);
|
||||
CHECK(test.find("find!", 30, 39) == 34);
|
||||
CHECK(test.find("find!", 30, 38) == -1);
|
||||
|
||||
CHECK(test.find('s') == 2);
|
||||
CHECK(test.find('s', 2) == 2);
|
||||
CHECK(test.find('s', 5) == 8);
|
||||
CHECK(test.find('s', 2, 3) == 2);
|
||||
CHECK(test.find('s', 2, 2) == -1);
|
||||
CHECK(test.find('s', 3, 2) == -1);
|
||||
|
||||
CHECK(test.find('!') == 38);
|
||||
CHECK(test.find('!', 38) == 38);
|
||||
CHECK(test.find('!', 38) == 38);
|
||||
CHECK(test.find('!', 38, 39) == 38);
|
||||
CHECK(test.find('!', 38, 38) == -1);
|
||||
CHECK(test.find('!', 39, 38) == -1);
|
||||
|
||||
CHECK(test.find_first_of("sx!") == 2);
|
||||
CHECK(test.find_first_of("sx!", 2) == 2);
|
||||
CHECK(test.find_first_of("sx!", 5) == 8);
|
||||
CHECK(test.find_first_of("sx!", 2, 3) == 2);
|
||||
CHECK(test.find_first_of("sx!", 2, 2) == -1);
|
||||
CHECK(test.find_first_of("sx!", 3, 2) == -1);
|
||||
|
||||
CHECK(test.find_first_not_of("Teot") == 2);
|
||||
CHECK(test.find_first_not_of("Teot", 2) == 2);
|
||||
CHECK(test.find_first_not_of("Teot", 5) == 6);
|
||||
CHECK(test.find_first_not_of("Teot", 2, 3) == 2);
|
||||
CHECK(test.find_first_not_of("Teot", 2, 2) == -1);
|
||||
CHECK(test.find_first_not_of("Teot", 3, 2) == -1);
|
||||
|
||||
CHECK(test.find_last_of("pur") == 31);
|
||||
CHECK(test.find_last_of("pur", 30) == 31);
|
||||
CHECK(test.find_last_of("pur", 0, 30) == 13);
|
||||
CHECK(test.find_last_of("pur", 0, 31) == 13);
|
||||
CHECK(test.find_last_of("pur", 0, 32) == 31);
|
||||
CHECK(test.find_last_of("pur", 5) == 31);
|
||||
CHECK(test.find_last_of("pur", 0, 5) == -1);
|
||||
CHECK(test.find_last_of("pur", 10, 15) == 13);
|
||||
CHECK(test.find_last_of("pur", 13, 15) == 13);
|
||||
CHECK(test.find_last_of("pur", 14, 15) == -1);
|
||||
CHECK(test.find_last_of("pur", 10, 13) == -1);
|
||||
CHECK(test.find_last_of("pur", 13, 13) == -1);
|
||||
CHECK(test.find_last_of("pur", 15, 13) == -1);
|
||||
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc") == 33);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 20) == 33);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 20, 35) == 33);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 20, 33) == 29);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 29, 33) == 29);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 29, 30) == 29);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 29, 29) == -1);
|
||||
CHECK(test.find_last_not_of("ibe!fonudsc", 30, 29) == -1);
|
||||
};
|
||||
|
||||
SECTION("Comparisons")
|
||||
{
|
||||
rdcstr a = "Hello, World!";
|
||||
rdcstr b = "Hello, World!";
|
||||
|
||||
CHECK_FALSE(a < b);
|
||||
CHECK(a == b);
|
||||
CHECK_FALSE(a > b);
|
||||
|
||||
b.back() = '?';
|
||||
|
||||
CHECK(a < b);
|
||||
CHECK_FALSE(a == b);
|
||||
CHECK_FALSE(a > b);
|
||||
|
||||
CHECK_FALSE(b < a);
|
||||
CHECK_FALSE(b == a);
|
||||
CHECK(b > a);
|
||||
|
||||
b[1] = 'a';
|
||||
|
||||
a.pop_back();
|
||||
|
||||
CHECK_FALSE(a < b);
|
||||
CHECK_FALSE(a == b);
|
||||
CHECK(a > b);
|
||||
|
||||
b[1] = 'e';
|
||||
|
||||
CHECK(a < b);
|
||||
CHECK_FALSE(a == b);
|
||||
CHECK_FALSE(a > b);
|
||||
}
|
||||
|
||||
SECTION("String literal tests")
|
||||
{
|
||||
rdcstr test = STRING_LITERAL(LARGE_STRING);
|
||||
|
||||
Reference in New Issue
Block a user