@@ -15,7 +15,11 @@ class Target;
1515class Monitor ;
1616class 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+ */
1923class 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
0 commit comments