@@ -289,16 +289,56 @@ namespace {
289
289
* expose whether the stack is empty and whether or not any false values are
290
290
* present at all. To implement OP_ELSE, a toggle_top modifier is added, which
291
291
* flips the last value without returning it.
292
+ *
293
+ * This uses an optimized implementation that does not materialize the
294
+ * actual stack. Instead, it just stores the size of the would-be stack,
295
+ * and the position of the first false value in it.
292
296
*/
293
297
class ConditionStack {
294
298
private:
295
- std::vector<bool > m_flags;
299
+ // ! A constant for m_first_false_pos to indicate there are no falses.
300
+ static constexpr uint32_t NO_FALSE = std::numeric_limits<uint32_t >::max();
301
+
302
+ // ! The size of the implied stack.
303
+ uint32_t m_stack_size = 0 ;
304
+ // ! The position of the first false value on the implied stack, or NO_FALSE if all true.
305
+ uint32_t m_first_false_pos = NO_FALSE;
306
+
296
307
public:
297
- bool empty () { return m_flags.empty (); }
298
- bool all_true () { return !std::count (m_flags.begin (), m_flags.end (), false ); }
299
- void push_back (bool f) { m_flags.push_back (f); }
300
- void pop_back () { m_flags.pop_back (); }
301
- void toggle_top () { m_flags.back () = !m_flags.back (); }
308
+ bool empty () { return m_stack_size == 0 ; }
309
+ bool all_true () { return m_first_false_pos == NO_FALSE; }
310
+ void push_back (bool f)
311
+ {
312
+ if (m_first_false_pos == NO_FALSE && !f) {
313
+ // The stack consists of all true values, and a false is added.
314
+ // The first false value will appear at the current size.
315
+ m_first_false_pos = m_stack_size;
316
+ }
317
+ ++m_stack_size;
318
+ }
319
+ void pop_back ()
320
+ {
321
+ assert (m_stack_size > 0 );
322
+ --m_stack_size;
323
+ if (m_first_false_pos == m_stack_size) {
324
+ // When popping off the first false value, everything becomes true.
325
+ m_first_false_pos = NO_FALSE;
326
+ }
327
+ }
328
+ void toggle_top ()
329
+ {
330
+ assert (m_stack_size > 0 );
331
+ if (m_first_false_pos == NO_FALSE) {
332
+ // The current stack is all true values; the first false will be the top.
333
+ m_first_false_pos = m_stack_size - 1 ;
334
+ } else if (m_first_false_pos == m_stack_size - 1 ) {
335
+ // The top is the first false value; toggling it will make everything true.
336
+ m_first_false_pos = NO_FALSE;
337
+ } else {
338
+ // There is a false value, but not on top. No action is needed as toggling
339
+ // anything but the first false value is unobservable.
340
+ }
341
+ }
302
342
};
303
343
}
304
344
0 commit comments