[dasher] NewRender: make single recursive calls into tail calls (saves stack space)
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher] NewRender: make single recursive calls into tail calls (saves stack space)
- Date: Tue, 18 Jan 2011 17:19:26 +0000 (UTC)
commit 915e4ef8526130a572574234be9e06d5457c305b
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Tue Dec 28 22:00:10 2010 +0000
NewRender: make single recursive calls into tail calls (saves stack space)
by goto to beginning (could be a "while" loop but this actually seems neater?)
We very occassionally get stack-overflow errors because rendering the largest
child even if too small can lead to very deep recursion; this should fix this.
Src/DasherCore/DasherViewSquare.cpp | 22 ++++++++++++++--------
1 files changed, 14 insertions(+), 8 deletions(-)
---
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index c7ff775..6e5be20 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -644,6 +644,10 @@ void CDasherViewSquare::NewRender(CDasherNode *pRender, myint y1, myint y2,
CTextString *pPrevText, CExpansionPolicy &policy, double dMaxCost,
int parent_color, CDasherNode *&pOutput)
{
+ //when we have only one child node to render, which'll be the last thing we
+ // do before returning, we make a tail call by jumping here, rather than
+ // pushing another stack frame:
+beginning:
DASHER_ASSERT_VALIDPTR_RW(pRender);
++m_iRenderCount;
@@ -743,11 +747,10 @@ void CDasherViewSquare::NewRender(CDasherNode *pRender, myint y1, myint y2,
if ((newy2-newy1 < GetLongParameter(LP_MIN_NODE_SIZE) //too small, but stored as only - so all others are smaller still...
&& newy1 <= iDasherMaxY && newy2 >= iDasherMinY) //check too-small node is at least partly onscreen
|| (newy1 < iDasherMinY && newy2 > iDasherMaxY)) { //covers entire y-axis!
- //render just that child; nothing more to do for this node
- NewRender(pChild, newy1, newy2, pPrevText,
- policy, dMaxCost, myColor, pOutput);
- //leave pRender->onlyChildRendered set for next time
- return;
+ //render just that child; nothing more to do for this node => tail call to beginning
+ pRender = pChild; y1=newy1; y2=newy2;
+ parent_color = myColor;
+ goto beginning;
}
pRender->onlyChildRendered = NULL;
}
@@ -790,10 +793,13 @@ void CDasherViewSquare::NewRender(CDasherNode *pRender, myint y1, myint y2,
if (pBestCh) {
if (bestRange <= norm) {
//yup - no child big enough outright, so render the biggest
- NewRender(pBestCh, y1+(Range*(myint)pBestCh->Lbnd())/(myint)norm,
- y1 + (Range * (myint)pBestCh->Hbnd())/(myint)norm,
- pPrevText, policy, dMaxCost, myColor, pOutput);
pRender->onlyChildRendered = pBestCh; //cache for next time - the IF but not ONLY IF, above :-(
+ //and make tail call to beginning, as nothing more to do for the current node
+ pRender = pBestCh;
+ parent_color = myColor;
+ y2 = y1 + (Range * (myint)pRender->Hbnd())/(myint)norm;
+ y1+=(Range*(myint)pRender->Lbnd())/(myint)norm;
+ goto beginning;
} else if (!pBestCh->GetFlag(NF_GAME | NF_SEEN))
pBestCh->Delete_children();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]