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
+33 -4
View File
@@ -45,7 +45,8 @@ namespace /* internal */
NUMBER,
NEW_LINE,
SEPARATOR, /* , */
REPEAT /* - */
REPEAT, /* - */
LAST // ^
};
struct token
@@ -164,6 +165,14 @@ namespace /* internal */
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) */
/* { */
/* endwin(); */
@@ -202,6 +211,9 @@ namespace /* internal */
case '-':
type = REPEAT;
break;
case '^':
type = LAST;
break;
case '\n':
type = NEW_LINE;
}
@@ -318,7 +330,7 @@ namespace /* internal */
Sex parseSex(TokenIt& it, TokenIt end)
{
Sex res = M;
Sex res = UNKNOWN_SEX;
if(it->type == SEPARATOR)
{
++it;
@@ -437,6 +449,12 @@ namespace /* internal */
parents = prev_parents;
++it;
}
else if(it->type == LAST)
{
parents.first = cur_tree->last();
prev_parents = parents;
++it;
}
else
{
string name = parseName(it, end);
@@ -475,6 +493,7 @@ namespace /* internal */
++it;
break;
case REPEAT:
case LAST:
++it;
spouses.push_back( cur_tree->last() );
break;
@@ -548,11 +567,21 @@ namespace /* internal */
++line;
++it;
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 */
cur_tree->addPerson(name.c_str(), sex,
parents.first, parents.second, birth, death);
cur_tree->addPerson(name.c_str(), sex != F ? M : F, // Unknown is considered male
parents.first, parents.second, birth, death);
for(person_id spouse: spouses)
cur_tree->addRelation(spouse, Spouse, cur_tree->last());
return;
default:
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;
for(; *str != '\0'; ++str)
num += ((*str & 0xC0) != 0x80);
for(char c: str)
num += ((c & 0xC0) != 0x80); // bytes that start with 0 are single, 11 are multiple, 10 are sucessors
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))
{
+2 -1
View File
@@ -23,7 +23,8 @@ struct EventTime
enum Sex: U8
{
M = 0,
F
F,
UNKNOWN_SEX
};
enum BoxColors: U8 {
+15 -6
View File
@@ -94,6 +94,11 @@ person_id Tree::last()
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> res;
@@ -118,15 +123,19 @@ vector<person_id> Tree::findId(const string& name) 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;
}
+3
View File
@@ -43,6 +43,9 @@ public:
bool isEmpty();
person_id last();
// Get person by id
const Person& operator[](person_id) const;
std::vector<person_id> findId(const std::string& name) const;
person_id findId(const std::string& name, Sex) 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 leftSib = Nobody;
if(t.findRelation(selected, t.focused()) == Child) // todo: why not just the else?
{
auto siblings = t.findChildren(t.focused());
for(auto it = siblings.begin()+1; it < siblings.end(); ++it)
{
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;
}
}
}
person_id sel_par = t.findParent(selected, M);
if( sel_par == Nobody )
sel_par = t.findParent(selected, F);
if( sel_par == Nobody )
return selected;
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);
selected = (leftSibSpouse != Nobody) ? leftSibSpouse : leftSib;
if(*it == selected)
{
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;
}
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());
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
if(*it == selected)
{
if(*it == selected)
{
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;
}
selected = *(it+1);
break;
}
}
return selected;
}
}