mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Use automatic allocation for RPN stack
This commit is contained in:
@@ -219,7 +219,7 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
|
|||||||
} else if (fmt->type == 'f') {
|
} else if (fmt->type == 'f') {
|
||||||
// Special case for fixed-point
|
// Special case for fixed-point
|
||||||
|
|
||||||
// Default fractional width (C's is 6 for "%f"; here 5 is enough for Q16.16)
|
// Default fractional width (C++'s is 6 for "%f"; here 5 is enough for Q16.16)
|
||||||
size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
||||||
|
|
||||||
if (fracWidth > 255) {
|
if (fracWidth > 255) {
|
||||||
|
|||||||
@@ -17,58 +17,16 @@
|
|||||||
#include "opmath.hpp"
|
#include "opmath.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
|
|
||||||
/*
|
struct RPNStackEntry {
|
||||||
* This is an "empty"-type stack. Apart from the actual values, we also remember
|
int32_t value;
|
||||||
* whether the value is a placeholder inserted for error recovery. This allows
|
bool errorFlag; // Whether the value is a placeholder inserted for error recovery
|
||||||
* us to avoid cascading errors.
|
};
|
||||||
*
|
|
||||||
* The best way to think about this is a stack of (value, errorFlag) pairs.
|
|
||||||
* They are only separated for reasons of memory efficiency.
|
|
||||||
*/
|
|
||||||
struct RPNStack {
|
|
||||||
int32_t *values;
|
|
||||||
bool *errorFlags;
|
|
||||||
size_t size;
|
|
||||||
size_t capacity;
|
|
||||||
} stack;
|
|
||||||
|
|
||||||
static void initRPNStack(void)
|
std::deque<struct RPNStackEntry> rpnStack;
|
||||||
{
|
|
||||||
stack.capacity = 64;
|
|
||||||
stack.values = (int32_t *)malloc(sizeof(*stack.values) * stack.capacity);
|
|
||||||
stack.errorFlags = (bool *)malloc(sizeof(*stack.errorFlags) * stack.capacity);
|
|
||||||
if (!stack.values || !stack.errorFlags)
|
|
||||||
err("Failed to init RPN stack");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clearRPNStack(void)
|
|
||||||
{
|
|
||||||
stack.size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pushRPN(int32_t value, bool comesFromError)
|
static void pushRPN(int32_t value, bool comesFromError)
|
||||||
{
|
{
|
||||||
if (stack.size >= stack.capacity) {
|
rpnStack.push_front({ .value = value, .errorFlag = comesFromError });
|
||||||
static const size_t increase_factor = 2;
|
|
||||||
|
|
||||||
if (stack.capacity > SIZE_MAX / increase_factor)
|
|
||||||
errx("Overflow in RPN stack resize");
|
|
||||||
|
|
||||||
stack.capacity *= increase_factor;
|
|
||||||
stack.values =
|
|
||||||
(int32_t *)realloc(stack.values, sizeof(*stack.values) * stack.capacity);
|
|
||||||
stack.errorFlags =
|
|
||||||
(bool *)realloc(stack.errorFlags, sizeof(*stack.errorFlags) * stack.capacity);
|
|
||||||
// Static analysis tools complain that the capacity might become
|
|
||||||
// zero due to overflow, but fail to realize that it's caught by
|
|
||||||
// the overflow check above. Hence the stringent check below.
|
|
||||||
if (!stack.values || !stack.errorFlags || !stack.capacity)
|
|
||||||
err("Failed to resize RPN stack");
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.values[stack.size] = value;
|
|
||||||
stack.errorFlags[stack.size] = comesFromError;
|
|
||||||
stack.size++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This flag tracks whether the RPN op that is currently being evaluated
|
// This flag tracks whether the RPN op that is currently being evaluated
|
||||||
@@ -77,18 +35,14 @@ static bool isError = false;
|
|||||||
|
|
||||||
static int32_t popRPN(struct FileStackNode const *node, uint32_t lineNo)
|
static int32_t popRPN(struct FileStackNode const *node, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
if (stack.size == 0)
|
if (rpnStack.empty())
|
||||||
fatal(node, lineNo, "Internal error, RPN stack empty");
|
fatal(node, lineNo, "Internal error, RPN stack empty");
|
||||||
|
|
||||||
stack.size--;
|
struct RPNStackEntry entry = rpnStack.front();
|
||||||
isError |= stack.errorFlags[stack.size];
|
|
||||||
return stack.values[stack.size];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freeRPNStack(void)
|
rpnStack.pop_front();
|
||||||
{
|
isError |= entry.errorFlag;
|
||||||
free(stack.values);
|
return entry.value;
|
||||||
free(stack.errorFlags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPN operators
|
// RPN operators
|
||||||
@@ -132,7 +86,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
uint8_t const *expression = patch->rpnExpression;
|
uint8_t const *expression = patch->rpnExpression;
|
||||||
int32_t size = patch->rpnSize;
|
int32_t size = patch->rpnSize;
|
||||||
|
|
||||||
clearRPNStack();
|
rpnStack.clear();
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
enum RPNCommand command = (enum RPNCommand)getRPNByte(&expression, &size,
|
enum RPNCommand command = (enum RPNCommand)getRPNByte(&expression, &size,
|
||||||
@@ -142,7 +96,7 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
isError = false;
|
isError = false;
|
||||||
|
|
||||||
// Be VERY careful with two `popRPN` in the same expression.
|
// Be VERY careful with two `popRPN` in the same expression.
|
||||||
// C does not guarantee order of evaluation of operands!
|
// C++ does not guarantee order of evaluation of operands!
|
||||||
// So, if there are two `popRPN` in the same expression, make
|
// So, if there are two `popRPN` in the same expression, make
|
||||||
// sure the operation is commutative.
|
// sure the operation is commutative.
|
||||||
switch (command) {
|
switch (command) {
|
||||||
@@ -447,9 +401,9 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
pushRPN(value, isError);
|
pushRPN(value, isError);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack.size > 1)
|
if (rpnStack.size() > 1)
|
||||||
error(patch->src, patch->lineNo,
|
error(patch->src, patch->lineNo,
|
||||||
"RPN stack has %zu entries on exit, not 1", stack.size);
|
"RPN stack has %zu entries on exit, not 1", rpnStack.size());
|
||||||
|
|
||||||
isError = false;
|
isError = false;
|
||||||
return popRPN();
|
return popRPN();
|
||||||
@@ -460,7 +414,6 @@ static int32_t computeRPNExpr(struct Patch const *patch,
|
|||||||
void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
|
void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
|
||||||
{
|
{
|
||||||
verbosePrint("Checking assertions...\n");
|
verbosePrint("Checking assertions...\n");
|
||||||
initRPNStack();
|
|
||||||
|
|
||||||
for (struct Assertion &assert : assertions) {
|
for (struct Assertion &assert : assertions) {
|
||||||
int32_t value = computeRPNExpr(&assert.patch,
|
int32_t value = computeRPNExpr(&assert.patch,
|
||||||
@@ -491,8 +444,6 @@ void patch_CheckAssertions(std::deque<struct Assertion> &assertions)
|
|||||||
assert.message);
|
assert.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
freeRPNStack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -563,8 +514,5 @@ static void applyPatches(struct Section *section)
|
|||||||
|
|
||||||
void patch_ApplyPatches(void)
|
void patch_ApplyPatches(void)
|
||||||
{
|
{
|
||||||
initRPNStack();
|
|
||||||
sect_ForEach(applyPatches);
|
sect_ForEach(applyPatches);
|
||||||
freeRPNStack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user