operator ^ for last defined person

This commit is contained in:
Venelin
2024-06-15 13:48:08 +03:00
committed by vrd
parent a096a2a34c
commit 4d61963dae
8 changed files with 91 additions and 63 deletions
+1
View File
@@ -18,6 +18,7 @@ optimizations='
warnings=' warnings='
-Wall -Wall
-Wextra -Wextra
-Wno-implicit-fallthrough
-Wno-multichar' -Wno-multichar'
# -Wpedantic' #-fanalyzer # -Wpedantic' #-fanalyzer
+33 -4
View File
@@ -45,7 +45,8 @@ namespace /* internal */
NUMBER, NUMBER,
NEW_LINE, NEW_LINE,
SEPARATOR, /* , */ SEPARATOR, /* , */
REPEAT /* - */ REPEAT, /* - */
LAST // ^
}; };
struct token struct token
@@ -164,6 +165,14 @@ namespace /* internal */
exit(1); exit(1);
} }
[[noreturn]]void err_same_sex_spouse(const string& name, const Person& spouse)
{
endwin();
cerr << "Line " << line << ": '" << name << "' and their spouse " << spouse.name
<< " are both " << (spouse.sex == M ? "male" : "female") << '\n';
exit(1);
}
/* void err_name_index(const string& name, U32 i) */ /* void err_name_index(const string& name, U32 i) */
/* { */ /* { */
/* endwin(); */ /* endwin(); */
@@ -202,6 +211,9 @@ namespace /* internal */
case '-': case '-':
type = REPEAT; type = REPEAT;
break; break;
case '^':
type = LAST;
break;
case '\n': case '\n':
type = NEW_LINE; type = NEW_LINE;
} }
@@ -318,7 +330,7 @@ namespace /* internal */
Sex parseSex(TokenIt& it, TokenIt end) Sex parseSex(TokenIt& it, TokenIt end)
{ {
Sex res = M; Sex res = UNKNOWN_SEX;
if(it->type == SEPARATOR) if(it->type == SEPARATOR)
{ {
++it; ++it;
@@ -437,6 +449,12 @@ namespace /* internal */
parents = prev_parents; parents = prev_parents;
++it; ++it;
} }
else if(it->type == LAST)
{
parents.first = cur_tree->last();
prev_parents = parents;
++it;
}
else else
{ {
string name = parseName(it, end); string name = parseName(it, end);
@@ -475,6 +493,7 @@ namespace /* internal */
++it; ++it;
break; break;
case REPEAT: case REPEAT:
case LAST:
++it; ++it;
spouses.push_back( cur_tree->last() ); spouses.push_back( cur_tree->last() );
break; break;
@@ -548,11 +567,21 @@ namespace /* internal */
++line; ++line;
++it; ++it;
case STRING: // next person starts here case STRING: // next person starts here
for(person_id spouse: spouses) // validate spouses
{
if(sex == UNKNOWN_SEX)
sex = ((*cur_tree)[spouse].sex == M) ? F : M;
else if(sex == (*cur_tree)[spouse].sex)
err_same_sex_spouse(name, (*cur_tree)[spouse]);
}
/* todo str prevent copy */ /* todo str prevent copy */
cur_tree->addPerson(name.c_str(), sex, cur_tree->addPerson(name.c_str(), sex != F ? M : F, // Unknown is considered male
parents.first, parents.second, birth, death); parents.first, parents.second, birth, death);
for(person_id spouse: spouses) for(person_id spouse: spouses)
cur_tree->addRelation(spouse, Spouse, cur_tree->last()); cur_tree->addRelation(spouse, Spouse, cur_tree->last());
return; return;
default: default:
err_unexpected_token(*it); err_unexpected_token(*it);
+4 -4
View File
@@ -81,11 +81,11 @@ void Person::displayInfo()const
} }
static U16 strUtf8Symbols(const char* str) static U16 Utf8SymbolsCount(const string& str)
{ {
U16 num = 0; U16 num = 0;
for(; *str != '\0'; ++str) for(char c: str)
num += ((*str & 0xC0) != 0x80); num += ((c & 0xC0) != 0x80); // bytes that start with 0 are single, 11 are multiple, 10 are sucessors
return num; return num;
} }
@@ -113,7 +113,7 @@ U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse
} }
} }
const U16 width = strUtf8Symbols(display_name.data()) + 4; /* pad width */ const U16 width = Utf8SymbolsCount(display_name) + 4; /* pad width */
if(willBeVisible(drawY, drawX, BOX_HEIGHT, width)) if(willBeVisible(drawY, drawX, BOX_HEIGHT, width))
{ {
+2 -1
View File
@@ -23,7 +23,8 @@ struct EventTime
enum Sex: U8 enum Sex: U8
{ {
M = 0, M = 0,
F F,
UNKNOWN_SEX
}; };
enum BoxColors: U8 { enum BoxColors: U8 {
+15 -6
View File
@@ -94,6 +94,11 @@ person_id Tree::last()
return people_.size() - 1; return people_.size() - 1;
} }
const Person& Tree::operator[](person_id id) const
{
return people_[id];
}
vector<person_id> Tree::findId(const string& name) const vector<person_id> Tree::findId(const string& name) const
{ {
vector<person_id> res; vector<person_id> res;
@@ -118,15 +123,19 @@ vector<person_id> Tree::findId(const string& name) const
person_id Tree::findRootAncestor(person_id id) const person_id Tree::findRootAncestor(person_id id) const
{ {
for(person_id dad = findParent(id, M); dad != Nobody; dad = findParent(id, M)) while(true)
{ {
id = dad; person_id dad = findParent(id, M);
person_id mom = findParent(id, F);
if(dad != Nobody)
id = dad;
else if(mom != Nobody)
id = mom;
else
break;
} }
for(person_id mom = findParent(id, F); mom != Nobody; mom = findParent(id, F))
{
id = mom;
}
return id; return id;
} }
+3
View File
@@ -43,6 +43,9 @@ public:
bool isEmpty(); bool isEmpty();
person_id last(); person_id last();
// Get person by id
const Person& operator[](person_id) const;
std::vector<person_id> findId(const std::string& name) const; std::vector<person_id> findId(const std::string& name) const;
person_id findId(const std::string& name, Sex) const; person_id findId(const std::string& name, Sex) const;
person_id findRootAncestor(person_id) const; person_id findRootAncestor(person_id) const;
+32 -48
View File
@@ -175,66 +175,50 @@ namespace
person_id selectLeftSibSpouse(const Tree& t, person_id selected) /* todo: return a value and split */ person_id selectLeftSibSpouse(const Tree& t, person_id selected) /* todo: return a value and split */
{ {
person_id leftSib = Nobody; person_id sel_par = t.findParent(selected, M);
if(t.findRelation(selected, t.focused()) == Child) // todo: why not just the else? if( sel_par == Nobody )
{ sel_par = t.findParent(selected, F);
auto siblings = t.findChildren(t.focused()); if( sel_par == Nobody )
for(auto it = siblings.begin()+1; it < siblings.end(); ++it) return selected;
{
if(*it == selected)
{
leftSib = *(it-1);
break;
}
}
}
else if(person_id sel_par = t.findParent(selected, M); sel_par != Nobody)
{
auto siblings = t.findChildren(sel_par);
for(auto it = siblings.begin()+1; it < siblings.end(); ++it)
{
if(*it == selected)
{
leftSib = *(it-1);
break;
}
}
}
if(leftSib != Nobody) auto siblings = t.findChildren(sel_par);
person_id left_sib = Nobody;
for(auto it = siblings.begin()+1; it < siblings.end(); ++it)
{ {
person_id leftSibSpouse = t.findSpouse(leftSib); if(*it == selected)
selected = (leftSibSpouse != Nobody) ? leftSibSpouse : leftSib; {
left_sib = *(it-1);
person_id sib_spouse = t.findSpouse(left_sib);
if(sib_spouse != Nobody)
selected = sib_spouse;
else
selected = left_sib;
break;
}
} }
return selected; return selected;
} }
person_id selectRightSib(const Tree& t, person_id selected) person_id selectRightSib(const Tree& t, person_id selected)
{ {
if(t.findRelation(selected, t.focused()) == Child) person_id sel_par = t.findParent(selected, M);
if( sel_par == Nobody )
sel_par = t.findParent(selected, F);
if( sel_par == Nobody )
return selected;
auto siblings = t.findChildren(sel_par);
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
{ {
auto siblings = t.findChildren(t.focused()); if(*it == selected)
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
{ {
if(*it == selected) selected = *(it+1);
{ break;
selected = *(it+1);
break;
}
}
}
else if(person_id sel_par = t.findParent(selected, M); sel_par != Nobody)
{
auto siblings = t.findChildren(sel_par);
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
{
if(*it == selected)
{
selected = *(it+1);
break;
}
} }
} }
return selected; return selected;
} }
} }
+1
View File
@@ -33,6 +33,7 @@ Compilation
Refactoring Refactoring
- comment style /* - comment style /*
- check return codes - setlocale, - check return codes - setlocale,
- focused -> root ?
test test
- no Adam - no Adam