This Code Throw Run-Time Check Failure #2 - Stack around the variable 'WidthC' was corrupted. This Code Draws Button.
After Adding This.
INT WidthC; GetCharWidth(ControlStyles->hDC, 0, length, &WidthC);
But If I Ignore Error Program works and GetCharWidth() function returns character Width, but after program exit from DrawItem Function Error Occurs. Error Occurs after destroying WidthC variable.
if (ControlStyles->CtlID == ID_PREVIEW_BUTTON || ControlStyles->CtlID == ID_PREVIEW_STATIC || ControlStyles->CtlID == ID_PREVIEW_EDIT) {
SetTextColor(ControlStyles->hDC, PreviewTextControlColor);
SetBkMode(ControlStyles->hDC, PreviewControlsBackgroundMode);
if (PreviewControlsBackgroundMode == OPAQUE) {
SetBkColor(ControlStyles->hDC, PreviewTextBackgroundControlColor);
}
FillRect(ControlStyles->hDC, &ControlStyles->rcItem, CreateSolidBrush(PreviewBackgroundControlColor));
WCHAR StaticText[MAX_NAME_STRING] = { 0 };
INT length = GetWindowText(ControlStyles->hwndItem, StaticText, ARRAYSIZE(StaticText));
INT WidthC;
GetCharWidth(ControlStyles->hDC, 0, length, &WidthC);
TextOut(ControlStyles->hDC, ControlStyles->rcItem.right / 2 - ((length - 1) * WidthC) / 2, ControlStyles->rcItem.bottom / 2 - FontSize / 2, StaticText, length);
}
The 4th parameter of GetCharWidth() expects a pointer to a buffer that can hold as many INTs as are in the range of characters you specify in the 2nd and 3rd parameters. Since you are asking for a range of length number of characters, you need a buffer of length number of INTs. But, you are passing in the address of a single INT, so you will overwrite surrounding memory if length > 1 is true.
So, you would need something more like this instead:
WCHAR StaticText[MAX_NAME_STRING] = { 0 };
INT length = GetWindowText(ControlStyles->hwndItem, StaticText, ARRAYSIZE(StaticText));
if (length) {
INT WidthC[MAX_NAME_STRING] = { 0 };
GetCharWidth(ControlStyles->hDC, 0, length-1, WidthC);
// use WidthC[0]..WidthC[length-1] as needed...
}
Or, perhaps you meant to do this instead for a single INT:
WCHAR StaticText[MAX_NAME_STRING] = { 0 };
INT length = GetWindowText(ControlStyles->hwndItem, StaticText, ARRAYSIZE(StaticText));
if (length) {
INT WidthC;
GetCharWidth(ControlStyles->hDC, 0, 0, WidthC);
// use WidthC as needed...
}
That being said, GetCharWidth() is long deprecated, you should be using GetCharWidth32() instead, as the documentation says:
Note This function is provided only for compatibility with 16-bit versions of Windows. Applications should call the GetCharWidth32 function, which provides more accurate results.
I have added a transposition table to my TicTacToe minmax algorithm
int AI::findBestMove()
{
hash = tTable->recalculateHash();
int bestMove = minMax().second;
return bestMove;
}
std::pair<int, int> AI::minMax(int reverseDepth, std::pair<int, int> bestScoreMove, player currentPlayer, int alpha, int beta, int lastPlay)
{
Entry e = (*tTable)[hash];
if (e && e.depth == reverseDepth)
return e.scoreMove;
if (reverseDepth == 0)
return { 0, -2 };
else if (field->canDrawOrWin() && lastPlay != -1)
{
if (field->hasWon(lastPlay))
return { evaluateScore(currentPlayer), -1 };
else if (field->isDraw())
return { 0, -1 };
}
bestScoreMove.first = currentPlayer == player::AI ? INT_MIN : INT_MAX;
for (int i = 0; i < field->size(); i++)
{
if ((*field)[i] == player::None && field->isCoordWorthChecking(i))
{
(*field)[i] = currentPlayer;
hash = tTable->calculateHash(hash, i);
std::pair<int, int> scoreMove = minMax(reverseDepth - 1, bestScoreMove, getOpponent(currentPlayer), alpha, beta, i);
if (currentPlayer == player::AI)
{
alpha = std::max(alpha, scoreMove.first);
if (bestScoreMove.first < scoreMove.first)
bestScoreMove = { scoreMove.first, i };
}
else
{
beta = std::min(beta, scoreMove.first);
if (bestScoreMove.first > scoreMove.first)
bestScoreMove = { scoreMove.first, i };
}
hash = tTable->calculateHash(hash, i);
(*field)[i] = player::None;
if (beta <= alpha)
break;
}
}
tTable->placeEntry(hash, bestScoreMove, reverseDepth);
return bestScoreMove;
}
To test it I made an acceptance test that plays every possible board and checks for human wins
TEST(AcceptanceTest, EveryBoard)
{
int winstate = 0;
std::shared_ptr<Field> field = std::make_shared<Field>(4);
AI ai(field);
playEveryBoard(ai, field, winstate);
std::cout <<"Human wins: " << winstate << std::endl;
}
void playEveryBoard(AI& ai, std::shared_ptr<Field> f, int& winstate)
{
int bestMove = 0;
auto it = f->begin();
while (true)
{
it = std::find(it, f->end(), player::None);
if (it == f->end())
break;
*it = player::Human;
if (f->hasWon())
winstate++;
EXPECT_TRUE(!f->hasWon());
bestMove = ai.findBestMove();
if (bestMove == -1)//TIE
{
*it = player::None;
break;
}
(*f)[bestMove] = player::AI;
if (f->hasWon())//AI WIN
{
*it = player::None;
(*f)[bestMove] = player::None;
break;
}
playEveryBoard(ai, f, winstate);
*it = player::None;
(*f)[bestMove] = player::None;
if (it == f->end())
break;
it++;
}
}
The test never returned any loosing states until I added the transposition table, to test when the loosing state appears I made a test that plays every permutation of the loosing field, but it never found a loosing state, what could cause the AI to loose only in the EveryBoard test?
TEST(LoosePossible, AllPermutations)
{
std::vector<int> loosingField = { 2, 3, 7, 11, 12, 13, 15 };
do{
std::shared_ptr<Field> field = std::make_shared<Field>(4);
AI *ai = new AI(field);
for (auto i : loosingField)
{
if ((*field)[i] != player::None || field->hasWon())
break;
(*field)[i] = player::Human;
EXPECT_TRUE(!field->hasWon());
(*field)[ai->findBestMove()] = player::AI;
}
delete ai;
} while (next_permutation(loosingField.begin(), loosingField.end()));
}
I see at least two places these errors could be arising.
One potential problem is in this line:
Entry e = (*tTable)[hash];
if (e && e.depth == reverseDepth)
return e.scoreMove;
In addition to checking if the transposition table stores the result of a search that is the same depth, you also need to check that the stored bounds in the table are compatible with the bounds in the table.
I addressed this as part of an answer to another question:
When you store values in the transposition table, you also need to store the alpha and beta bounds used during the search. When you get a value back at a node mid-search it is either an upper bound on the true value (because value = beta), a lower bound on the true value (because value = alpha) or the actual value of the node (alpha < value < beta). You need to store this in your transposition table. Then, when you want to re-use the value, you have to check that you can use the value given your current alpha and beta bounds. (You can validate this by actually doing the search after finding the value in the transposition table to see if you get the same value from search that you got in the table.)
The way to test this is to modify AI::minMax. Set a flag to true when you have a value returned from the transposition table. Then, each time you return a value, if the transposition table flag is true, compare the value you are about to return to the value that was found in the transposition table. If they are not the same, then something is wrong.
In addition, minimax is typically used with zero-sum games, which means that the sum of scores for the two players should add to 0. I don't know what all the returned values mean in your code, but sometimes you are returning {0, -1} and sometimes {0, -2}. This is problematic, because now you have a non-zero-sum game and much of the theory falls apart.
In particular, the max player may treat {0, -1} and {0, -2} the same, but the min player will not. Thus, if the move ordering changes in any way you may see these in different orders, and thus the value at the root of the tree will not be stable.
As an aside, this is a fundamental issue in multi-player games. Practically speaking it arises when one player is a king-maker. They can't win the game themselves, but they can decide who does.
I am trying to make a combination lock using an Arduino, a keypad and a Servo but I have come across an obstacle.
I can't find a way to store a 4 digit value in a variable. since keypad.getKey only allows to store one digit.
After some browsing on the internet I came upon a solution for my problem on a forum but the answer didn't include a code sample, and I couldn't find anything else about in on the internet.
The answer said to either use a time limit for the user to input the number or a terminating character (which would be the better option according to them).
I would like to know more bout these terminating characters and how to implement them, or if anybody could suggest a better solution that would be much appreciated as well.
Thank you in advance,
To store 4 digit values, the easiest and naive way to do it is probably to use an array of size 4. Assuming keypad.getKey returns an int, you could do something like this: int input[4] = {0};.
You will need a cursor variable to know into which slot of the array you need to write when the next key is pressed so you can do some kind of loop like this:
int input[4] = {0};
for (unsigned cursor = 0; cursor < 4; ++cursor) {
input[cursor] = keypad.getKey();
}
If you want to use a terminating character (lets say your keyboard have 0-9 and A-F keys, we could say the F is the terminating key), the code changes for something like:
bool checkPassword() {
static const int expected[4] = {4,8,6,7}; // our password
int input[4] = {0};
// Get the next 4 key presses
for (unsigned cursor = 0; cursor < 4; ++cursor) {
int key = keypad.getKey();
// if F is pressed too early, then it fails
if (key == 15) {
return false;
}
// store the keypress value in our input array
input[cursor] = key;
}
// If the key pressed here isn't F (terminating key), it fails
if (keypad.getKey() != 15)
return false;
// Check if input equals expected
for (unsigned i = 0; i < 4; ++i) {
// If it doesn't, it fails
if (expected[i] != input[i]) {
return false;
}
}
// If we manage to get here the password is right :)
return true;
}
Now you can use the checkPassword function in your main function like this:
int main() {
while (true) {
if (checkPassword())
//unlock the thing
}
return 0;
}
NB: Using a timer sounds possible too (and can be combined with the terminating character option, they are not exclusive). The way to do this is to set a timer to the duration of your choice and when it ends you reset the cursor variable to 0.
(I never programmed on arduino and don't know about its keypad library but the logic is here, its up to you now)
In comment OP says a single number is wanted. The typical algorithm is that for each digit entered you multiply an accumulator by 10 and add the digit entered. This assumes that the key entry is ASCII, hence subtracting '0' from it to get a digit 0..9 instead of '0'..'9'.
#define MAXVAL 9999
int value = 0; // the number accumulator
int keyval; // the key press
int isnum; // set if a digit was entered
do {
keyval = getkey(); // input the key
isnum = (keyval >= '0' && keyval <= '9'); // is it a digit?
if(isnum) { // if so...
value = value * 10 + keyval - '0'; // accumulate the input number
}
} while(isnum && value <= MAXVAL); // until not a digit
If you have a backspace key, you simply divide the accumulator value by 10.
I'm going to go over everything being used before I ask questions about it...
I've created a array of char pointers here, I use the array in a function right after
char *TShirtsText[] = { "Black", "Yellow", "Blue" };
ModelChanger->AddVariantItem("R* T-Shirts", TShirtsText[0], -1, 0, 2, 1, DevShirt, (bool*)true);
Now I have the function here, take notice of optionstext
// Add a variant item to the menu
void GTAVMenu::AddVariantItem(char *displayText, char *optionstext, float var, float min, float max, float changeby, GTAVMenuCallback functionCallback, void *functionParameters) {
GTAVMenuItem menuItem;
// Set menu type
menuItem.menuItemType = MENU_TYPE_VARIANT;
// Add variant text to item text
char newDisplayText[32];
if (functionParameters == NULL)
sprintf_s(newDisplayText, sizeof(newDisplayText), "%s: < %g >", displayText, var);
else
sprintf_s(newDisplayText, sizeof(newDisplayText), "%s: < Not Set >", displayText);
// Copy menu item text
strcpy_s(menuItem.itemText, 32, newDisplayText);
// Function callback
menuItem.functionCallback = functionCallback;
// No display callback
menuItem.displayCallback = NULL;
// Sub menu
menuItem.subMenu = NULL;
// Function params
menuItem.functionParameters = functionParameters;
// Menu item toggling
menuItem.itemToggleable = false;
menuItem.itemToggled = false;
// Keep memory of displayText, optionstext, var, min, max, changeby
menuItem.vartext = displayText;
if (functionParameters != NULL) menuItem.optionstext = optionstext;
menuItem.var = var;
menuItem.min = min;
menuItem.max = max;
menuItem.changeby = changeby;
// Add our menu item
menuItems->push_back(menuItem);
}
here's a sample of code where I press a button and this is what happens roughly, take notice of optionstext
switch(menuItem->menuItemType)
{
case MENU_TYPE_VARIANT:
{
if (menuItem->var <= menuItem->min)
menuItem->var = menuItem->max;
else
//menuItem->var--;
menuItem->var -= menuItem->changeby;
selectedNum = menuItem->var;
play_sound_frontend(0, "NAV_UP_DOWN", "HUD_FRONTEND_DEFAULT_SOUNDSET");
// Add variant text to item text
char newDisplayText[32];
if (menuItem->functionParameters == NULL)
sprintf_s(newDisplayText, sizeof(newDisplayText), "%s: < %g >", menuItem->vartext, menuItem->var);
else
sprintf_s(newDisplayText, sizeof(newDisplayText), "%s: < %s >", menuItem->vartext, menuItem->optionstext);
// Copy menu item text
strcpy_s(menuItem->itemText, 32, newDisplayText);
// Calling function - never used to be here
menuItem->functionCallback(selectedMenuItem, menuIndexStack, menuItem->itemText, menuItem->functionParameters);
break;
}
}
And this is where the question comes along. So, I'm using an array of char pointers, and I'm using the first element from that array as you can see from the first bit of code. In the last bit of code, one of the sprintf_s places menuItem->optionstext into newDisplayText. In the output, when I press the left button, sprintf_s uses the last element of the char pointer array, and if I press the right button on my controller, it changes it to the next element.
Why does it change it to the next element when I haven't stated which element I want it to copy? and why is the program allowing me to do this especially when all I'm using in the function is one element from the array?
You reserve only 32 bytes for the string:
char newDisplayText[32];
But then you put the full 32 chars in it, so there is no space for the closing '\0'.
Any access will therefore overrun and read or write over whatever happens to be next in memory. That typically produces all kind of funny and wild errors.
You need to declare char newDisplayText[33]; to have space for 32 chars.
I have a list of lexicographical ranges, for example
[a,an) [an,bb) [bb,d) [c,h)
Given a string say apple, I need to find which range it belongs to. In this case it is in the second range. If the string could belong to multiple ranges, the first one needs to be returned. Eg: cat should return range3 and not range4.
Brute force approach would be to loop through the list in order and check if the string fits in there.
Better approach would be to resolve overlaps first, sort the ranges and do a binary search.
Any suggestions for further optimized algorithm? Also implementation tips for c++ is welcome. This logic happens to occur on a critical execution path and has to be fast.
Update:
Yes, there could be gaps in the ranges.
Yes binary search can make it O(log(n)). Is there someway I can come up with a hash and make it even better? How would the hash look like? We can assume we have only lowercase characters in all the strings and ranges.
Here is what you should do:
First sort the ranges with respect to their beginnings in lexicographical order. Then you should do the following pre-processing on them - for each range make it's beginning the greater of it's begining and the end of the previous range(if this makes the current range empty, simply ignore it). You do that because if a word is before the end of the previous range, then it will belong to some of the previous ranges and will never be classified in the current one. After this pre-processing all the ranges are non-overlapping and so each word you search for will belong to at most one of them. So all you need to do is to perform a binarry search on the resulting pre-processed ranges which will be in O(log(n)) complexity. I doubt you can achieve better complexity for this problem.
Some kind of index to the start of each range, perhaps a binary tree, would probably be a good idea. Not sure if you need to index to the end of each range, unless there may be gaps.
One solution comes to my mind, may be you can sort the word apple and identify the character that comes last in the a-z order. And just check for that one character in your ranges. Thinking more...
If you have memory to spare and are limited to lowercase, you can build a multi-way tree. Top node has an array of 26 pointers. Pointers are Null if no range starts with that character. They point to a range if all words starting with that character fall into the range, and point to another node if the ranges split on a following character. (so given [aa-ap],[ar-bl]; the 'a' entry would point to another node where entries 'a' through 'p' pointed to range 1, entry 'q' was null, and 'r' thru 'z' pointed to range 2. )
This should be O(max(range_specifier)).
You might approach this by "gridding".
Use an array with 26 entries corresponding to the first letter. Every bin contains the list of ranges having a nonempty intersection with it. Like
'a' -> [a,an) [an,bb), 'b' -> [an,bb) [bb,d), 'c' -> [bb,d) [c,h) ...
You easily generalize the idea to a prefix of a few letters
'aaa' -> [a,an), 'aab' -> [a,an), 'aac' -> [a,an) ...
This can much shorten the list of ranges to be tried, especially if there are little overlaps, at the expense of storage and preprocessing time.
A special convention can be used to indicate that a bin is wholly covered.
Happy distributions can lead to O(1), I guess.
I wouldn't be surprised that your set of ranges can be represented with a trie (http://en.wikipedia.org/wiki/Trie). Once the trie is filled, the query time should not exceed the length of the longest range bound nor the length of the query string.
This is optimal in terms of query time (in fact O(1) in your computational model).
My approach would be
a range has two limits (the lower and upper limit)
each range partitions the space into three parts (below, inside, above)
each limit partitions the space into two parts (below, above_or_equal)
So the method could be:
number the ranges
decompose the ranges into two limits
put the limits into a tree, in nodes containing two lists with the ranges that refer to them (one list for nodes that use this limit as lower limit, one for upper limit)
these lists can be bitmaps, since the ranges are numbered
to find a string
you walk the tree, and every time you step down you actually cross a limit and gain knowledge about which limits you have to your right/left, and which ranges you are left/right/inside.
you need two additional lists (of range numbers) to do this traversal.
these lists can be bitmaps
every time you cross a border you add the range number from one of the lists and remove it from the other.
once you are inside a range (x >= lower limit && x < upper limit; with the limits corresponding to the same range of course) the algorihtm finishes.
(given that this is actually the range with the lowest number: first match)
this can be detected if the two lists share one or more members
we want the lowest-numbered overlapping member.
Since this method is a tree search, it has O(log(N)) complexity.
UPDATE: On second thought, bitmaps are not good way to store the usage lists or the results. A linked list (actually two) is better. Code is 300 lines. Should I post it here ?
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define COUNTOF(a) (sizeof a / sizeof a[0])
#define WANT_DUPLICATES 0
struct range {
/* separate linked lists for {lo,hi})
** for limits that this range participates in. */
struct range *next_lo;
struct range *next_hi;
unsigned num;
char *str_lo, *str_hi;
} ranges[] =
{{NULL,NULL,0, "a","an"}, {NULL,NULL,1, "an", "bb"}
,{NULL,NULL,2, "bb", "d"}, {NULL,NULL,3, "c", "h"}
,{NULL,NULL,4, "bb", "c"}, {NULL,NULL,5, "c", "d"}
};
#define NRANGE COUNTOF(ranges)
void add_range(struct range *pp);
void list_dmp(FILE *fp, int isupper, struct range *bp);
struct treetwo {
struct treetwo *prev;
struct treetwo *next;
char *str;
struct range *list_lo; /* ranges that use str as lower limit */
struct range *list_hi; /* ranges that use str as upper limit */
};
struct treetwo *root = NULL;
struct treetwo ** find_hnd(struct treetwo **tpp, char *str);
void tree_dmp(FILE *fp, struct treetwo *tp, char *msg, unsigned indent);
struct result {
unsigned size;
unsigned used;
struct {
unsigned num;
unsigned mask;
} *entries;
};
#define MASK_BELOW_LO 1
#define MASK_ABOVE_LO 2
#define MASK_BELOW_HI 4
#define MASK_ABOVE_HI 8
int result_resize(struct result *res, unsigned newsize);
void init_structures(void);
struct result *find_matches (char *str);
unsigned update_state(struct result *rp, struct treetwo *tp, int isabove);
int main (void)
{
char buff[100];
struct result *res;
size_t pos;
unsigned idx;
static char *legend[4] = { "unknown", "below", "above", "impossible"};
init_structures();
tree_dmp(stderr, root, "Root", 0);
while (fgets (buff, sizeof buff, stdin) ) {
pos=strcspn(buff, "\r\n");
buff[pos] = 0;
res = find_matches (buff);
for (idx=0; idx < res->used; idx++) {
unsigned num = res->entries[idx].num;
unsigned mask = res->entries[idx].mask;
fprintf(stdout, "[%u]Range%u %x: '%s' %s '%s' and '%s' %s '%s'\n"
, idx, num, mask
, buff, legend[mask & 3], ranges[num].str_lo
, buff, legend[(mask>>2) & 3], ranges[num].str_hi
);
}
}
return 0;
}
unsigned update_state(struct result *rp, struct treetwo *tp, int isabove)
{
struct range *p;
unsigned mask_lo, mask_hi;
unsigned hitcnt,idx;
/* State: (lower limit)
** 0 : unknown
** MASK_BELOW_LO: below limit
** MASK_ABOVE_LO: above limit
** 3: impossible
** State: (upper limit)
** 0 : unknown
** MASK_BELOW_HI: below limit
** MASK_ABOVE_HI: above limit
** c: impossible
** Combined states:
** required state 2|4 := 6
** 5: unreachable
** a: unreachable
** 9: impossible
** f: impossible
*/
if (!tp) return 0;
hitcnt=0;
mask_lo = (isabove>=0) ? MASK_ABOVE_LO : MASK_BELOW_LO;
mask_hi = (isabove>=0) ? MASK_ABOVE_HI : MASK_BELOW_HI;
fprintf(stderr , "Update_state(start{%s}, isabove=%d, mask=%x,%x)\n"
, tp->str , isabove, mask_lo, mask_hi);
fprintf(stderr , "Update_state(Lo=%s)=", tp->str);
list_dmp(stderr , 0, tp->list_lo);
idx=0;
for (p = tp->list_lo; p ; p = p->next_lo) {
unsigned num = p->num;
fprintf(stderr , "Update_state:[%u] |= %u", num, mask_lo );
for ( ;idx < rp->used;idx++) { if (rp->entries[idx].num >= num) break; }
if ( idx < rp->used ) {
fprintf(stderr , " Old was:%u\n", rp->entries[idx].mask );
rp->entries[idx].mask |= mask_lo;
if (rp->entries[idx].mask == (MASK_ABOVE_LO|MASK_BELOW_HI)) hitcnt++;
continue;
}
if ( idx >= rp->used) {
if ( rp->used >= rp->size && result_resize(rp, rp->size ? rp->size*2 : 8)) break;
fprintf(stderr , " New at:%u\n", idx );
rp->entries[idx].num = num;
rp->entries[idx].mask = mask_lo;
rp->used++;
}
}
fprintf(stderr , "Update_state(Hi=%s)=", tp->str);
list_dmp(stderr , 1, tp->list_hi);
idx=0;
for (p = tp->list_hi; p ; p = p->next_hi) {
unsigned num = p->num;
fprintf(stderr , "Update_state:[%u] |= %u", num, mask_lo );
for ( ;idx < rp->used;idx++) { if (rp->entries[idx].num >= num) break; }
if ( idx < rp->used ) {
fprintf(stderr , " Old was:%u\n", rp->entries[idx].mask );
rp->entries[idx].mask |= mask_hi;
if (rp->entries[idx].mask == (MASK_ABOVE_LO|MASK_BELOW_HI)) hitcnt++;
continue;
}
if ( idx >= rp->used) {
if ( rp->used >= rp->size && result_resize(rp, rp->size ? rp->size*2 : 8)) break;
fprintf(stderr , " New at:%u\n", idx );
rp->entries[idx].num = num;
rp->entries[idx].mask = mask_hi;
rp->used++;
}
}
return hitcnt;
}
struct result *find_matches (char *str)
{
int rc;
struct treetwo **hnd;
struct result *res = malloc (sizeof *res);
unsigned dst,src;
res->used=res->size=0; res->entries=0;
for (hnd= &root; *hnd; hnd = (rc < 0) ? &(*hnd)->prev : &(*hnd)->next ) {
rc = strcmp( str, (*hnd)->str);
fprintf(stderr, "####\nStr=%s Node={%s} rc=%d\n"
, str, (*hnd)->str, rc );
list_dmp(stderr , 0, (*hnd)->list_lo );
list_dmp(stderr , 1, (*hnd)->list_hi );
rc = update_state(res, *hnd , rc);
#if WANT_DUPLICATES
continue;
#else
/* if we don't want duplicates we can bail out on the first match */
if (rc) break;
#endif
}
/* Now cleanup the results.
** Below(lower limit) and above(upper limit) and variations can be removed.
** Some results are incomplete, because one of there limits is out
** of reach (shadowed by a narrower range). We'll have to recompute these.
** The result structure is compacted: if entries are deleted, the remaining ones are shifted down.
** Note: part of this cleanup (removal of unreacheables) could be done in update_state(),
** that would keep the array with partial results as short as possible.
*/
for (dst=src=0; src < res->used; src++) {
int rc;
unsigned num = res->entries[src].num;
rescan:
switch (res->entries[src].mask & 0xf) {
default: break;
case 0: /* impossible */
goto rescan;
#if WANT_DUPLICATES
case MASK_ABOVE_LO:
rc = strcmp(str, ranges[num].str_hi);
res->entries[src].mask |= (rc >=0) ? MASK_ABOVE_HI : MASK_BELOW_HI;
goto rescan;
case MASK_BELOW_HI:
rc = strcmp(str, ranges[num].str_lo);
res->entries[src].mask |= (rc >=0) ? MASK_ABOVE_LO : MASK_BELOW_LO;
goto rescan;
#endif
case MASK_BELOW_HI|MASK_ABOVE_LO:
if (dst != src) res->entries[dst] = res->entries[src];
dst++;
}
}
fprintf(stderr, "####\nFinal pass: %u/%u\n", dst, res->used );
res->used = dst;
return res;
}
void init_structures(void)
{
unsigned idx;
for (idx = 0; idx < NRANGE; idx++) {
add_range( &ranges[idx]);
}
}
void list_dmp(FILE *fp, int isupper, struct range *bp)
{
fprintf(fp, "%s", (isupper) ? "Upper" :"Lower" );
for ( ; bp ; bp = (isupper) ? bp->next_hi : bp->next_lo) {
fprintf(fp, " %u:{%s,%s}"
, bp->num , bp->str_lo , bp->str_hi
);
}
fprintf( stdout, "\n" );
}
void add_range(struct range *pp)
{
struct treetwo **tpp;
struct range **rpp;
fprintf(stderr, "Inserting range %u->{%s,%s}\n", pp->num, pp->str_lo, pp->str_hi);
/* find low boundary for this interval */
tpp = find_hnd (&root, pp->str_lo);
if (!*tpp) {
fprintf(stderr, "Creating node for %u->%s (low)\n", pp->num, pp->str_lo);
*tpp = malloc(sizeof **tpp);
(*tpp)->list_lo = NULL;
(*tpp)->list_hi = NULL;
(*tpp)->str = pp->str_lo;
}
for (rpp = &(*tpp)->list_lo; *rpp ; rpp = &(*rpp)->next_lo) {;}
*rpp = pp;
fprintf(stderr, "Added range %u->{%s,%s} to treenode(%s)->list_lo\n"
, pp->num, pp->str_lo, pp->str_hi
, (*tpp)->str
);
/* find high boundary */
tpp = find_hnd (&root, pp->str_hi);
if (!*tpp) {
fprintf(stderr, "Creating node for %u->%s (High)\n", pp->num, pp->str_hi);
*tpp = malloc(sizeof **tpp);
(*tpp)->list_lo = NULL;
(*tpp)->list_hi = NULL;
(*tpp)->str = pp->str_hi;
}
for (rpp = &(*tpp)->list_hi; *rpp ; rpp = &(*rpp)->next_hi) {;}
*rpp = pp;
fprintf(stderr, "Added range %u->{%s,%s} to treenode(%s)->list_hi\n"
, pp->num, pp->str_lo, pp->str_hi
, (*tpp)->str
);
}
struct treetwo ** find_hnd(struct treetwo **tpp, char *str)
{
int rc;
for ( ; *tpp; tpp = (rc < 0) ? &(*tpp)->prev : &(*tpp)->next ) {
rc = strcmp( str, (*tpp)->str);
if (!rc) break;
}
return tpp;
}
void tree_dmp(FILE *fp, struct treetwo *tp, char *msg, unsigned indent)
{
unsigned uu;
if (!tp) return;
if (!msg) msg = "";
for (uu=0; uu < indent; uu++) { fputc( ' ', fp); }
fprintf(fp, "%s:{%s}\n", msg, tp->str );
for (uu=0; uu < indent+1; uu++) { fputc( ' ', fp); }
list_dmp(fp , 0, tp->list_lo);
for (uu=0; uu < indent+1; uu++) { fputc( ' ', fp); }
list_dmp(fp , 1, tp->list_hi);
tree_dmp(fp, tp->prev, "Prev", indent+2);
tree_dmp(fp, tp->next, "Next", indent+2);
}
int result_resize(struct result *res, unsigned newsize)
{
void *old;
old = res->entries;
res->entries = realloc ( res->entries , newsize * sizeof *res->entries);
if ( !res->entries) {
res->entries = old; return -1;
}
res->size = newsize;
if (res->used > newsize) res->used = newsize;
return 0;
}