@@ -289,16 +289,56 @@ namespace {
289289 * expose whether the stack is empty and whether or not any false values are
290290 * present at all. To implement OP_ELSE, a toggle_top modifier is added, which
291291 * 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.
292296 */
293297class ConditionStack {
294298private:
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+
296307public:
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+ }
302342};
303343}
304344
0 commit comments