Changeset View
Changeset View
Standalone View
Standalone View
src/script/interpreter.cpp
Show First 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||||
* Conceptually it acts like a vector of booleans, one for each level of nested | * Conceptually it acts like a vector of booleans, one for each level of nested | ||||
* IF/THEN/ELSE, indicating whether we're in the active or inactive branch of | * IF/THEN/ELSE, indicating whether we're in the active or inactive branch of | ||||
* each. | * each. | ||||
* | * | ||||
* The elements on the stack cannot be observed individually; we only need to | * The elements on the stack cannot be observed individually; we only need to | ||||
* expose whether the stack is empty and whether or not any false values are | * expose whether the stack is empty and whether or not any false values are | ||||
* present at all. To implement OP_ELSE, a toggle_top modifier is added, which | * present at all. To implement OP_ELSE, a toggle_top modifier is added, which | ||||
* flips the last value without returning it. | * flips the last value without returning it. | ||||
* | |||||
* This uses an optimized implementation that does not materialize the | |||||
* actual stack. Instead, it just stores the size of the would-be stack, | |||||
* and the position of the first false value in it. | |||||
*/ | */ | ||||
class ConditionStack { | class ConditionStack { | ||||
private: | private: | ||||
std::vector<bool> m_flags; | //! A constant for m_first_false_pos to indicate there are no falses. | ||||
static constexpr uint32_t NO_FALSE = std::numeric_limits<uint32_t>::max(); | |||||
//! The size of the implied stack. | |||||
uint32_t m_stack_size = 0; | |||||
//! The position of the first false value on the implied stack, or NO_FALSE | |||||
//! if all true. | |||||
uint32_t m_first_false_pos = NO_FALSE; | |||||
public: | public: | ||||
bool empty() { return m_flags.empty(); } | bool empty() { return m_stack_size == 0; } | ||||
bool all_true() { | bool all_true() { return m_first_false_pos == NO_FALSE; } | ||||
return !std::count(m_flags.begin(), m_flags.end(), false); | void push_back(bool f) { | ||||
} | if (m_first_false_pos == NO_FALSE && !f) { | ||||
void push_back(bool f) { m_flags.push_back(f); } | // The stack consists of all true values, and a false is added. | ||||
void pop_back() { m_flags.pop_back(); } | // The first false value will appear at the current size. | ||||
void toggle_top() { m_flags.back() = !m_flags.back(); } | m_first_false_pos = m_stack_size; | ||||
} | |||||
++m_stack_size; | |||||
} | |||||
void pop_back() { | |||||
assert(m_stack_size > 0); | |||||
--m_stack_size; | |||||
if (m_first_false_pos == m_stack_size) { | |||||
// When popping off the first false value, everything becomes true. | |||||
m_first_false_pos = NO_FALSE; | |||||
} | |||||
} | |||||
void toggle_top() { | |||||
assert(m_stack_size > 0); | |||||
if (m_first_false_pos == NO_FALSE) { | |||||
// The current stack is all true values; the first false will be the | |||||
// top. | |||||
m_first_false_pos = m_stack_size - 1; | |||||
} else if (m_first_false_pos == m_stack_size - 1) { | |||||
// The top is the first false value; toggling it will make | |||||
// everything true. | |||||
m_first_false_pos = NO_FALSE; | |||||
} else { | |||||
// There is a false value, but not on top. No action is needed as | |||||
// toggling anything but the first false value is unobservable. | |||||
} | |||||
} | |||||
}; | }; | ||||
} // namespace | } // namespace | ||||
bool EvalScript(std::vector<valtype> &stack, const CScript &script, | bool EvalScript(std::vector<valtype> &stack, const CScript &script, | ||||
uint32_t flags, const BaseSignatureChecker &checker, | uint32_t flags, const BaseSignatureChecker &checker, | ||||
ScriptExecutionMetrics &metrics, ScriptError *serror) { | ScriptExecutionMetrics &metrics, ScriptError *serror) { | ||||
static const CScriptNum bnZero(0); | static const CScriptNum bnZero(0); | ||||
static const CScriptNum bnOne(1); | static const CScriptNum bnOne(1); | ||||
▲ Show 20 Lines • Show All 1,712 Lines • Show Last 20 Lines |