Skip to content

Commit ed0c342

Browse files
committed
Hide list data in List class
1 parent ecef707 commit ed0c342

File tree

10 files changed

+377
-186
lines changed

10 files changed

+377
-186
lines changed

include/scratchcpp/list.h

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ class Monitor;
1616
class ListPrivate;
1717

1818
/*! \brief The List class represents a Scratch list. */
19-
class LIBSCRATCHCPP_EXPORT List
20-
: public veque::veque<Value>
21-
, public Entity
19+
class LIBSCRATCHCPP_EXPORT List : public Entity
2220
{
2321
public:
2422
List(const std::string &id, const std::string &name);
2523
List(const List &) = delete;
2624

25+
~List();
26+
2727
const std::string &name();
2828
void setName(const std::string &name);
2929

@@ -33,24 +33,103 @@ class LIBSCRATCHCPP_EXPORT List
3333
Monitor *monitor() const;
3434
void setMonitor(Monitor *monitor);
3535

36-
long indexOf(const Value &value) const;
37-
bool contains(const Value &value) const;
36+
/*! Returns the list size. */
37+
inline size_t size() const { return m_dataPtr->size(); }
38+
39+
/*! Returns true if the list is empty. */
40+
inline bool empty() const { return m_dataPtr->empty(); }
41+
42+
/*! Returns the index of the given item. */
43+
inline size_t indexOf(const ValueData &value) const
44+
{
45+
for (size_t i = 0; i < m_dataPtr->size(); i++) {
46+
if (value_equals(&m_dataPtr->operator[](i), &value))
47+
return i;
48+
}
49+
50+
return -1;
51+
}
52+
53+
/*! Returns the index of the given item. */
54+
inline size_t indexOf(const Value &value) const { return indexOf(value.data()); }
55+
56+
/*! Returns true if the list contains the given item. */
57+
inline bool contains(const ValueData &value) const { return (indexOf(value) != -1); }
58+
59+
/*! Returns true if the list contains the given item. */
60+
inline bool contains(const Value &value) const { return contains(value.data()); }
61+
62+
/*! Clears the list. */
63+
inline void clear()
64+
{
65+
for (ValueData &v : *m_dataPtr)
66+
value_free(&v);
67+
68+
m_dataPtr->clear();
69+
}
70+
71+
/*! 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+
79+
/*! Appends an item. */
80+
inline void append(const Value &value) { append(value.data()); }
81+
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+
}
3889

3990
/*! Removes the item at index. */
40-
void removeAt(int index) { erase(begin() + index); }
91+
inline void removeAt(size_t index)
92+
{
93+
assert(index >= 0 && index < size());
94+
value_free(&m_dataPtr->operator[](index));
95+
m_dataPtr->erase(m_dataPtr->begin() + index);
96+
}
97+
98+
/*! Inserts an item at index. */
99+
inline void insert(size_t index, const ValueData &value)
100+
{
101+
assert(index >= 0 && index <= size());
102+
m_dataPtr->insert(m_dataPtr->begin() + index, ValueData());
103+
value_init(&m_dataPtr->operator[](index));
104+
value_assign_copy(&m_dataPtr->operator[](index), &value);
105+
}
41106

42107
/*! Inserts an item at index. */
43-
void insert(int index, const Value &value) { veque<Value>::insert(begin() + index, value); }
108+
inline void insert(size_t index, const Value &value) { insert(index, value.data()); }
109+
110+
/*! Replaces the item at index. */
111+
inline void replace(size_t index, const ValueData &value)
112+
{
113+
assert(index >= 0 && index < size());
114+
value_assign_copy(&m_dataPtr->operator[](index), &value);
115+
}
44116

45117
/*! Replaces the item at index. */
46-
void replace(int index, const Value &value) { at(index) = value; }
118+
inline void replace(size_t index, const Value &value) { replace(index, value.data()); }
119+
120+
inline ValueData &operator[](size_t index)
121+
{
122+
assert(index >= 0 && index < size());
123+
return m_dataPtr->operator[](index);
124+
}
47125

48126
std::string toString() const;
49127

50128
std::shared_ptr<List> clone();
51129

52130
private:
53131
spimpl::unique_impl_ptr<ListPrivate> impl;
132+
veque::veque<ValueData> *m_dataPtr = nullptr; // NOTE: accessing through pointer is faster! (from benchmarks)
54133
};
55134

56135
} // namespace libscratchcpp

include/scratchcpp/value.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ class LIBSCRATCHCPP_EXPORT Value
8484
value_assign_special(&m_data, specialValue);
8585
}
8686

87+
/*! Constructs value from ValueData. */
88+
Value(const ValueData &v)
89+
{
90+
value_init(&m_data);
91+
value_assign_copy(&m_data, &v);
92+
}
93+
8794
Value(const Value &v)
8895
{
8996
value_init(&m_data);
@@ -92,6 +99,18 @@ class LIBSCRATCHCPP_EXPORT Value
9299

93100
~Value() { value_free(&m_data); }
94101

102+
/*!
103+
* Returns a read-only reference to the data.
104+
* \note Valid until the Value object is destroyed.
105+
*/
106+
const ValueData &data() const { return m_data; };
107+
108+
/*!
109+
* Returns a read/write reference to the data.
110+
* \note Valid until the Value object is destroyed.
111+
*/
112+
ValueData &data() { return m_data; }
113+
95114
/*! Returns the type of the value. */
96115
ValueType type() const { return m_data.type; }
97116

@@ -204,6 +223,12 @@ class LIBSCRATCHCPP_EXPORT Value
204223
return *this;
205224
}
206225

226+
const Value &operator=(const ValueData &v)
227+
{
228+
value_assign_copy(&m_data, &v);
229+
return *this;
230+
}
231+
207232
const Value &operator=(const Value &v)
208233
{
209234
value_assign_copy(&m_data, &v.m_data);

src/engine/virtualmachine_p.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset)
613613
DISPATCH();
614614

615615
OP(LIST_APPEND) :
616-
lists[*++pos]->push_back(*READ_LAST_REG());
616+
lists[*++pos]->append(*READ_LAST_REG());
617617
FREE_REGS(1);
618618
DISPATCH();
619619

@@ -659,7 +659,7 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset)
659659
} else {
660660
const std::string &str = indexValue->toString();
661661
if (str == "last") {
662-
list->push_back(*READ_REG(0, 2));
662+
list->append(*READ_REG(0, 2));
663663
index = 0;
664664
} else if (str == "random") {
665665
size_t size = list->size();
@@ -669,7 +669,7 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset)
669669
}
670670
if ((index != 0) || list->empty()) {
671671
if (list->empty())
672-
list->push_back(*READ_REG(0, 2));
672+
list->append(*READ_REG(0, 2));
673673
else
674674
list->insert(index - 1, *READ_REG(0, 2));
675675
}
@@ -696,7 +696,7 @@ unsigned int *VirtualMachinePrivate::run(unsigned int *pos, bool reset)
696696
index = 0;
697697
}
698698
if (index != 0)
699-
list->operator[](index - 1) = *READ_REG(1, 2);
699+
list->replace(index - 1, *READ_REG(1, 2));
700700
FREE_REGS(2);
701701
DISPATCH();
702702
}

src/internal/scratch3reader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ bool Scratch3Reader::load()
6363
auto list = std::make_shared<List>(it.key(), listInfo[0]);
6464
auto arr = listInfo[1];
6565
for (auto item : arr)
66-
list->push_back(jsonToValue(item));
66+
list->append(jsonToValue(item));
6767
target->addList(list);
6868
}
6969

src/scratch/list.cpp

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ List::List(const std::string &id, const std::string &name) :
1212
Entity(id),
1313
impl(spimpl::make_unique_impl<ListPrivate>(name))
1414
{
15+
m_dataPtr = &impl->data;
16+
}
17+
18+
/*! Destroys List. */
19+
List::~List()
20+
{
21+
clear();
1522
}
1623

1724
/*! Returns the name of the list. */
@@ -50,33 +57,21 @@ void List::setMonitor(Monitor *monitor)
5057
impl->monitor = monitor;
5158
}
5259

53-
/*! Returns the index of the given item. */
54-
long List::indexOf(const Value &value) const
55-
{
56-
auto it = std::find(begin(), end(), value);
57-
58-
if (it != end())
59-
return it - begin();
60-
else
61-
return -1;
62-
}
63-
64-
/*! Returns true if the list contains the given item. */
65-
bool List::contains(const Value &value) const
66-
{
67-
return (indexOf(value) != -1);
68-
}
69-
7060
/*! Joins the list items with spaces or without any separator if there are only digits. */
7161
std::string List::toString() const
7262
{
7363
std::string ret;
64+
veque::veque<std::string> strings;
65+
strings.reserve(m_dataPtr->size());
7466
bool digits = true;
7567

76-
for (const auto &item : *this) {
77-
if (item.isValidNumber() && !item.toString().empty()) {
78-
double doubleNum = item.toDouble();
79-
long num = item.toLong();
68+
for (const auto &item : *m_dataPtr) {
69+
strings.push_back(std::string());
70+
value_toString(&item, &strings.back());
71+
72+
if (value_isValidNumber(&item) && !strings.back().empty()) {
73+
double doubleNum = value_toDouble(&item);
74+
long num = value_toLong(&item);
8075

8176
if (doubleNum != num) {
8277
digits = false;
@@ -93,13 +88,30 @@ std::string List::toString() const
9388
}
9489
}
9590

91+
size_t i;
92+
std::string s;
93+
9694
if (digits) {
97-
for (const auto &item : *this)
98-
ret.append(item.toString());
95+
for (i = 0; i < strings.size(); i++)
96+
ret.append(strings[i]);
97+
98+
for (; i < m_dataPtr->size(); i++) {
99+
value_toString(&m_dataPtr->operator[](i), &s);
100+
ret.append(s);
101+
}
99102
} else {
100-
for (int i = 0; i < size(); i++) {
101-
ret.append(at(i).toString());
102-
if (i + 1 < size())
103+
for (i = 0; i < strings.size(); i++) {
104+
ret.append(strings[i]);
105+
106+
if (i + 1 < m_dataPtr->size())
107+
ret.push_back(' ');
108+
}
109+
110+
for (; i < m_dataPtr->size(); i++) {
111+
value_toString(&m_dataPtr->operator[](i), &s);
112+
ret.append(s);
113+
114+
if (i + 1 < m_dataPtr->size())
103115
ret.push_back(' ');
104116
}
105117
}
@@ -112,8 +124,8 @@ std::shared_ptr<List> List::clone()
112124
{
113125
auto copy = std::make_shared<List>(id(), impl->name);
114126

115-
for (const Value &item : *this)
116-
copy->push_back(item);
127+
for (const ValueData &item : *m_dataPtr)
128+
copy->append(item);
117129

118130
return copy;
119131
}

src/scratch/list_p.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#pragma once
44

55
#include <string>
6+
#include <scratchcpp/veque.h>
7+
#include <scratchcpp/valuedata.h>
68

79
namespace libscratchcpp
810
{
@@ -17,6 +19,7 @@ struct ListPrivate
1719
std::string name;
1820
Target *target = nullptr;
1921
Monitor *monitor = nullptr;
22+
veque::veque<ValueData> data;
2023
};
2124

2225
} // namespace libscratchcpp

test/engine/engine_test.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -496,19 +496,19 @@ TEST(EngineTest, ExecutionOrder)
496496
auto list = GET_LIST(stage, "order");
497497
ASSERT_EQ(list->size(), 13);
498498

499-
ASSERT_EQ((*list)[0].toString(), "Sprite2");
500-
ASSERT_EQ((*list)[1].toString(), "Sprite3");
501-
ASSERT_EQ((*list)[2].toString(), "Sprite1");
502-
ASSERT_EQ((*list)[3].toString(), "Stage");
503-
ASSERT_EQ((*list)[4].toString(), "Sprite1 1");
504-
ASSERT_EQ((*list)[5].toString(), "Sprite1 2");
505-
ASSERT_EQ((*list)[6].toString(), "Sprite1 3");
506-
ASSERT_EQ((*list)[7].toString(), "Sprite2 msg");
507-
ASSERT_EQ((*list)[8].toString(), "Sprite3 msg");
508-
ASSERT_EQ((*list)[9].toString(), "Sprite1 1 msg");
509-
ASSERT_EQ((*list)[10].toString(), "Sprite1 2 msg");
510-
ASSERT_EQ((*list)[11].toString(), "Sprite1 3 msg");
511-
ASSERT_EQ((*list)[12].toString(), "Stage msg");
499+
ASSERT_EQ(Value((*list)[0]).toString(), "Sprite2");
500+
ASSERT_EQ(Value((*list)[1]).toString(), "Sprite3");
501+
ASSERT_EQ(Value((*list)[2]).toString(), "Sprite1");
502+
ASSERT_EQ(Value((*list)[3]).toString(), "Stage");
503+
ASSERT_EQ(Value((*list)[4]).toString(), "Sprite1 1");
504+
ASSERT_EQ(Value((*list)[5]).toString(), "Sprite1 2");
505+
ASSERT_EQ(Value((*list)[6]).toString(), "Sprite1 3");
506+
ASSERT_EQ(Value((*list)[7]).toString(), "Sprite2 msg");
507+
ASSERT_EQ(Value((*list)[8]).toString(), "Sprite3 msg");
508+
ASSERT_EQ(Value((*list)[9]).toString(), "Sprite1 1 msg");
509+
ASSERT_EQ(Value((*list)[10]).toString(), "Sprite1 2 msg");
510+
ASSERT_EQ(Value((*list)[11]).toString(), "Sprite1 3 msg");
511+
ASSERT_EQ(Value((*list)[12]).toString(), "Stage msg");
512512
}
513513

514514
TEST(EngineTest, KeyState)
@@ -1859,19 +1859,19 @@ TEST(EngineTest, Clones)
18591859

18601860
for (int i = 0; i < list->size(); i++) {
18611861
if (i < 10)
1862-
ASSERT_EQ((*list)[i].toInt(), 1);
1862+
ASSERT_EQ(value_toInt(&(*list)[i]), 1);
18631863
else
1864-
ASSERT_EQ((*list)[i].toInt(), 2);
1864+
ASSERT_EQ(value_toInt(&(*list)[i]), 2);
18651865
}
18661866

18671867
ASSERT_LIST(stage, "log2");
18681868
list = GET_LIST(stage, "log2");
18691869

18701870
for (int i = 0; i < list->size(); i++) {
18711871
if (i < 10)
1872-
ASSERT_EQ((*list)[i].toInt(), 1);
1872+
ASSERT_EQ(value_toInt(&(*list)[i]), 1);
18731873
else
1874-
ASSERT_EQ((*list)[i].toString(), "12");
1874+
ASSERT_EQ(Value((*list)[i]).toString(), "12");
18751875
}
18761876
}
18771877

0 commit comments

Comments
 (0)