Skip to content

Commit 7c0912f

Browse files
committed
List: Do not deallocate deleted items
1 parent 395e14a commit 7c0912f

File tree

2 files changed

+66
-40
lines changed

2 files changed

+66
-40
lines changed

include/scratchcpp/list.h

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ class Target;
1515
class Monitor;
1616
class ListPrivate;
1717

18-
/*! \brief The List class represents a Scratch list. */
18+
/*!
19+
* \brief The List class represents a Scratch list.
20+
*
21+
* Due to the high optimization of the methods, indices out of range will result in undefined behavior!
22+
*/
1923
class LIBSCRATCHCPP_EXPORT List : public Entity
2024
{
2125
public:
@@ -34,15 +38,15 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
3438
void setMonitor(Monitor *monitor);
3539

3640
/*! Returns the list size. */
37-
inline size_t size() const { return m_dataPtr->size(); }
41+
inline size_t size() const { return m_size; }
3842

3943
/*! Returns true if the list is empty. */
40-
inline bool empty() const { return m_dataPtr->empty(); }
44+
inline bool empty() const { return m_size == 0; }
4145

4246
/*! Returns the index of the given item. */
4347
inline size_t indexOf(const ValueData &value) const
4448
{
45-
for (size_t i = 0; i < m_dataPtr->size(); i++) {
49+
for (size_t i = 0; i < m_size; i++) {
4650
if (value_equals(&m_dataPtr->operator[](i), &value))
4751
return i;
4852
}
@@ -60,47 +64,37 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
6064
inline bool contains(const Value &value) const { return contains(value.data()); }
6165

6266
/*! Clears the list. */
63-
inline void clear()
64-
{
65-
for (ValueData &v : *m_dataPtr)
66-
value_free(&v);
67+
inline void clear() { m_size = 0; }
6768

68-
m_dataPtr->clear();
69+
/*! Appends an empty item and returns the reference to it. Can be used for custom initialization. */
70+
inline ValueData &appendEmpty()
71+
{
72+
m_size++;
73+
reserve(getAllocSize(m_size));
74+
return m_dataPtr->operator[](m_size - 1);
6975
}
7076

7177
/*! Appends an item. */
72-
inline void append(const ValueData &value)
73-
{
74-
m_dataPtr->push_back(ValueData());
75-
value_init(&m_dataPtr->back());
76-
value_assign_copy(&m_dataPtr->back(), &value);
77-
}
78+
inline void append(const ValueData &value) { value_assign_copy(&appendEmpty(), &value); }
7879

7980
/*! Appends an item. */
8081
inline void append(const Value &value) { append(value.data()); }
8182

82-
/*! Appends an empty item and returns the reference to it. Can be used for custom initialization. */
83-
inline ValueData &appendEmpty()
84-
{
85-
m_dataPtr->push_back(ValueData());
86-
value_init(&m_dataPtr->back());
87-
return m_dataPtr->back();
88-
}
89-
9083
/*! Removes the item at index. */
9184
inline void removeAt(size_t index)
9285
{
9386
assert(index >= 0 && index < size());
94-
value_free(&m_dataPtr->operator[](index));
95-
m_dataPtr->erase(m_dataPtr->begin() + index);
87+
std::rotate(m_dataPtr->begin() + index, m_dataPtr->begin() + index + 1, m_dataPtr->begin() + m_size);
88+
m_size--;
9689
}
9790

9891
/*! Inserts an item at index. */
9992
inline void insert(size_t index, const ValueData &value)
10093
{
10194
assert(index >= 0 && index <= size());
102-
m_dataPtr->insert(m_dataPtr->begin() + index, ValueData());
103-
value_init(&m_dataPtr->operator[](index));
95+
m_size++;
96+
reserve(getAllocSize(m_size));
97+
std::rotate(m_dataPtr->rbegin() + m_dataPtr->size() - m_size, m_dataPtr->rbegin() + m_dataPtr->size() - m_size + 1, m_dataPtr->rend() - index);
10498
value_assign_copy(&m_dataPtr->operator[](index), &value);
10599
}
106100

@@ -128,16 +122,18 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
128122
{
129123
dst.clear();
130124
veque::veque<std::string> strings;
131-
strings.reserve(m_dataPtr->size());
125+
strings.reserve(m_size);
132126
bool digits = true;
127+
size_t i;
133128

134-
for (const auto &item : *m_dataPtr) {
129+
for (i = 0; i < m_size; i++) {
130+
const ValueData *item = &m_dataPtr->operator[](i);
135131
strings.push_back(std::string());
136-
value_toString(&item, &strings.back());
132+
value_toString(item, &strings.back());
137133

138-
if (value_isValidNumber(&item) && !strings.back().empty()) {
139-
double doubleNum = value_toDouble(&item);
140-
long num = value_toLong(&item);
134+
if (value_isValidNumber(item) && !strings.back().empty()) {
135+
double doubleNum = value_toDouble(item);
136+
long num = value_toLong(item);
141137

142138
if (doubleNum != num) {
143139
digits = false;
@@ -154,30 +150,29 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
154150
}
155151
}
156152

157-
size_t i;
158153
std::string s;
159154

160155
if (digits) {
161156
for (i = 0; i < strings.size(); i++)
162157
dst.append(strings[i]);
163158

164-
for (; i < m_dataPtr->size(); i++) {
159+
for (; i < m_size; i++) {
165160
value_toString(&m_dataPtr->operator[](i), &s);
166161
dst.append(s);
167162
}
168163
} else {
169164
for (i = 0; i < strings.size(); i++) {
170165
dst.append(strings[i]);
171166

172-
if (i + 1 < m_dataPtr->size())
167+
if (i + 1 < m_size)
173168
dst.push_back(' ');
174169
}
175170

176-
for (; i < m_dataPtr->size(); i++) {
171+
for (; i < m_size; i++) {
177172
value_toString(&m_dataPtr->operator[](i), &s);
178173
dst.append(s);
179174

180-
if (i + 1 < m_dataPtr->size())
175+
if (i + 1 < m_size)
181176
dst.push_back(' ');
182177
}
183178
}
@@ -194,8 +189,37 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
194189
std::shared_ptr<List> clone();
195190

196191
private:
192+
inline void reserve(size_t size)
193+
{
194+
assert(size >= m_size);
195+
196+
while (size > m_dataPtr->size()) {
197+
m_dataPtr->push_back(ValueData());
198+
value_init(&m_dataPtr->back());
199+
}
200+
201+
while (size < m_dataPtr->size()) {
202+
value_free(&m_dataPtr->back());
203+
m_dataPtr->erase(m_dataPtr->end());
204+
}
205+
}
206+
207+
inline size_t getAllocSize(size_t x)
208+
{
209+
if (x == 0)
210+
return 0;
211+
212+
size_t ret = 1;
213+
214+
while (ret < x)
215+
ret *= 2;
216+
217+
return ret;
218+
}
219+
197220
spimpl::unique_impl_ptr<ListPrivate> impl;
198221
veque::veque<ValueData> *m_dataPtr = nullptr; // NOTE: accessing through pointer is faster! (from benchmarks)
222+
size_t m_size = 0;
199223
};
200224

201225
} // namespace libscratchcpp

src/scratch/list.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ List::List(const std::string &id, const std::string &name) :
1919
List::~List()
2020
{
2121
clear();
22+
reserve(m_size);
2223
}
2324

2425
/*! Returns the name of the list. */
@@ -61,9 +62,10 @@ void List::setMonitor(Monitor *monitor)
6162
std::shared_ptr<List> List::clone()
6263
{
6364
auto copy = std::make_shared<List>(id(), impl->name);
65+
copy->reserve(m_size);
6466

65-
for (const ValueData &item : *m_dataPtr)
66-
copy->append(item);
67+
for (size_t i = 0; i < m_size; i++)
68+
copy->append(m_dataPtr->operator[](i));
6769

6870
return copy;
6971
}

0 commit comments

Comments
 (0)