-
-
Save KrzaQ/10a035a905d6cfe1a458 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdlib> | |
#include <ctime> | |
#include <algorithm> | |
#include <deque> | |
#include <iomanip> | |
#include <iostream> | |
#include <list> | |
#include <map> | |
#include <random> | |
#include <set> | |
#include <sstream> | |
#include <string> | |
#include <thread> | |
#include <utility> | |
#include <boost/optional.hpp> | |
#include <boost/property_tree/json_parser.hpp> | |
#include <boost/property_tree/ptree.hpp> | |
using namespace std; | |
string operator "" _s(char const* msg, size_t size){ | |
return string(msg, size); | |
} | |
template<typename T> | |
typename remove_reference<T>::type const& | |
as_const(T&& t){ | |
return t; | |
} | |
struct Year; | |
struct Specialization; | |
struct Faculty; | |
namespace pt = boost::property_tree; | |
namespace detail{ | |
template<typename Func> | |
class ExceptionWrapper | |
{ | |
public: | |
template<typename T, | |
typename U = typename enable_if< | |
!is_same< | |
typename decay<T>::type, | |
ExceptionWrapper | |
>::value, | |
void>::type | |
> | |
ExceptionWrapper(T&& t): f(std::forward<T>(t)){} | |
ExceptionWrapper(ExceptionWrapper const&) = default; | |
ExceptionWrapper(ExceptionWrapper &&) = default; | |
void operator()() const { | |
try{ | |
f(); | |
}catch(exception const& e){ | |
cout << "Exception: " << e.what() << endl; | |
} | |
} | |
private: | |
Func f; | |
}; | |
} | |
template<typename T> | |
auto makeExceptionWrapper(T&& t){ | |
return detail::ExceptionWrapper<typename decay<T>::type>(forward<T>(t)); | |
} | |
struct Student | |
{ | |
static Student from_ptree(pt::ptree const& pt); | |
pt::ptree to_ptree() const; | |
bool operator<(Student const& o) const { | |
return tie(firstName, lastName) < tie(o.firstName, o.lastName); | |
} | |
string firstName, lastName; | |
}; | |
struct Year | |
{ | |
static Year from_ptree(pt::ptree const& pt); | |
pt::ptree to_ptree() const; | |
set<Student> students; | |
}; | |
struct Specialization | |
{ | |
static Specialization from_ptree(pt::ptree const& pt); | |
pt::ptree to_ptree() const; | |
map<int, Year> years; | |
}; | |
struct Faculty | |
{ | |
static Faculty from_ptree(pt::ptree const& pt); | |
pt::ptree to_ptree() const; | |
map<string, Specialization> specs; | |
}; | |
class DB | |
{ | |
public: | |
void addStudent(string const& f, string const& s, int y, Student const& st); | |
void addYear(string const& f, string const& s, int y); | |
void addSpecialization(string const& f, string const& s); | |
void addFaculty(string const& f); | |
void removeStudent(string const& f, string const& s, int y, Student const& st); | |
void removeYear(string const& f, string const& s, int y); | |
void removeSpecialization(string const& f, string const& s); | |
void removeFaculty(string const& f); | |
map<string, Faculty> const& data() const { return faculties_; } | |
void load(); | |
void save(); | |
private: | |
map<string, Faculty> faculties_; | |
}; | |
class Menu | |
{ | |
public: | |
Menu(): | |
options_{{0,{"exit",[this]{exit();}}}}{} | |
enum class LoopStrategy{ | |
Infinite, | |
NoLoop | |
}; | |
template<typename T> | |
void addOption(int no, string const& name, T&& o){ | |
options_[no] = make_pair(name, forward<T>(o)); | |
} | |
template<typename T> | |
static T get(boost::optional<string> name){ | |
T ret; | |
if(name) cout << "Please enter the value of " << *name << ":" << endl; | |
while(!(cin >> ret)){ | |
cin.clear(); | |
cin.ignore(numeric_limits<streamsize>::max(),'\n'); | |
cout << "Please enter a valid value:" << endl; | |
} | |
return ret; | |
} | |
void operator()() const { | |
do{ | |
int selected; | |
do{ | |
cout << "Options:" << endl; | |
for(auto&& p : as_const(options_)){ | |
cout << setw(3) << p.first << " " << p.second.first << endl; | |
} | |
selected = Menu::get<int>("your selection"_s); | |
}while(options_.find(selected) == end(options_)); | |
options_.at(selected).second(); | |
}while(loopStrategy_ == LoopStrategy::Infinite); | |
} | |
void setLoopStrategy(LoopStrategy ls) { loopStrategy_ = ls; } | |
void exit(){ | |
setLoopStrategy(LoopStrategy::NoLoop); | |
} | |
private: | |
LoopStrategy loopStrategy_ = LoopStrategy::NoLoop; | |
std::map<int, pair<string,function<void()>>> options_; | |
}; | |
Menu prepareMenu(DB& db); | |
int main() | |
{ | |
DB db; | |
Menu m = prepareMenu(db); | |
m(); | |
} | |
Menu prepareMenu(DB& db) | |
{ | |
Menu m; | |
m.setLoopStrategy(Menu::LoopStrategy::Infinite); | |
Menu addMenu; | |
addMenu.addOption(1, "Add faculty", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
db.addFaculty(f); | |
}); | |
addMenu.addOption(2, "Add specialization", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
string s = Menu::get<string>("specialization"_s); | |
db.addSpecialization(f, s); | |
}); | |
addMenu.addOption(3, "Add year", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
string s = Menu::get<string>("specialization"_s); | |
int y = Menu::get<int>("year"_s); | |
db.addYear(f, s, y); | |
}); | |
addMenu.addOption(4, "Add student", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
string s = Menu::get<string>("specialization"_s); | |
int y = Menu::get<int>("year"_s); | |
Student st; | |
st.firstName = Menu::get<string>("first name"_s); | |
st.lastName = Menu::get<string>("last name"_s); | |
db.addStudent(f, s, y, st); | |
}); | |
Menu removeMenu; | |
removeMenu.addOption(1, "Remove faculty", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
db.removeFaculty(f); | |
}); | |
removeMenu.addOption(2, "Remove specialization", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
string s = Menu::get<string>("specialization"_s); | |
db.removeSpecialization(f, s); | |
}); | |
removeMenu.addOption(3, "Remove year", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
string s = Menu::get<string>("specialization"_s); | |
int y = Menu::get<int>("year"_s); | |
db.removeYear(f, s, y); | |
}); | |
removeMenu.addOption(4, "Remove student", | |
[&db]{ | |
string f = Menu::get<string>("faculty"_s); | |
string s = Menu::get<string>("specialization"_s); | |
int y = Menu::get<int>("year"_s); | |
Student st; | |
st.firstName = Menu::get<string>("first name"_s); | |
st.lastName = Menu::get<string>("last name"_s); | |
db.removeStudent(f, s, y, st); | |
}); | |
m.addOption(1, "Add item to the database", makeExceptionWrapper(addMenu)); | |
m.addOption(2, "Remove item from the database", makeExceptionWrapper(removeMenu)); | |
m.addOption(3, "Display contents of the database", makeExceptionWrapper([&db]{ | |
cout << setw(20) << "Faculty" << setw(20) << "Specialization" << | |
setw(5) << "Year" << setw(30) << "Student" << endl; | |
for(auto&& f : db.data()){ | |
for(auto&& s : f.second.specs){ | |
for(auto&& y : s.second.years){ | |
for(auto&& st : y.second.students){ | |
cout << setw(20) << f.first << | |
setw(20) << s.first << | |
setw(5) << y.first << | |
setw(15) << st.firstName << | |
setw(15) << st.lastName << | |
endl; | |
} | |
} | |
} | |
} | |
})); | |
m.addOption(4, "Load the database", makeExceptionWrapper([&db]{ db.load(); })); | |
m.addOption(5, "Save the databse", makeExceptionWrapper([&db]{ db.save(); })); | |
return m; | |
} | |
void DB::addStudent(const string & f, const string & s, int y, const Student & st) | |
{ | |
auto fit = faculties_.find(f); | |
if(fit == end(faculties_)) throw invalid_argument("No such faculty"); | |
auto sit = fit->second.specs.find(s); | |
if(sit == end(fit->second.specs)) throw invalid_argument("No such specialization"); | |
auto yit = sit->second.years.find(y); | |
if(yit == end(sit->second.years)) throw invalid_argument("No such year"); | |
yit->second.students.insert(st); | |
} | |
void DB::addYear(const string & f, const string & s, int y) | |
{ | |
auto fit = faculties_.find(f); | |
if(fit == end(faculties_)) throw invalid_argument("No such faculty"); | |
auto sit = fit->second.specs.find(s); | |
if(sit == end(fit->second.specs)) throw invalid_argument("No such specialization"); | |
sit->second.years[y]; | |
} | |
void DB::addSpecialization(const string & f, const string & s) | |
{ | |
auto fit = faculties_.find(f); | |
if(fit == end(faculties_)) throw invalid_argument("No such faculty"); | |
fit->second.specs[s]; | |
} | |
void DB::addFaculty(const string & f) | |
{ | |
faculties_[f]; | |
} | |
void DB::removeStudent(const string & f, const string & s, int y, const Student & st) | |
{ | |
auto fit = faculties_.find(f); | |
if(fit == end(faculties_)) throw invalid_argument("No such faculty"); | |
auto sit = fit->second.specs.find(s); | |
if(sit == end(fit->second.specs)) throw invalid_argument("No such specialization"); | |
auto yit = sit->second.years.find(y); | |
if(yit == end(sit->second.years)) throw invalid_argument("No such year"); | |
yit->second.students.erase(st); | |
} | |
void DB::removeYear(const string & f, const string & s, int y) | |
{ | |
auto fit = faculties_.find(f); | |
if(fit == end(faculties_)) throw invalid_argument("No such faculty"); | |
auto sit = fit->second.specs.find(s); | |
if(sit == end(fit->second.specs)) throw invalid_argument("No such specialization"); | |
auto yit = sit->second.years.erase(y); | |
} | |
void DB::removeSpecialization(const string & f, const string & s) | |
{ | |
auto fit = faculties_.find(f); | |
if(fit == end(faculties_)) throw invalid_argument("No such faculty"); | |
auto sit = fit->second.specs.erase(s); | |
} | |
void DB::removeFaculty(const string & f) | |
{ | |
faculties_.erase(f); | |
} | |
void DB::load() | |
{ | |
pt::ptree t; | |
pt::read_json("db.json", t); | |
try{ | |
for(auto&& p : as_const(t.get_child("faculties"))){ | |
try{ | |
faculties_[p.second.get<string>("name")] = Faculty::from_ptree(p.second); | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
} | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
} | |
void DB::save() | |
{ | |
pt::ptree t; | |
pt::ptree children; | |
transform(begin(faculties_), end(faculties_), back_inserter(children), | |
[&](decltype(faculties_)::value_type const& f){ | |
auto ft = f.second.to_ptree(); | |
ft.put("name", f.first); | |
return make_pair("", ft); | |
}); | |
t.add_child("faculties", children); | |
pt::write_json("db.json", t); | |
} | |
Faculty Faculty::from_ptree(const boost::property_tree::ptree & pt) | |
{ | |
Faculty f; | |
try{ | |
for(auto&& p : as_const(pt.get_child("specializations"))){ | |
try{ | |
f.specs[p.second.get<string>("name")] = Specialization::from_ptree(p.second); | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
} | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
return f; | |
} | |
boost::property_tree::ptree Faculty::to_ptree() const | |
{ | |
pt::ptree ret; | |
pt::ptree children; | |
transform(begin(specs), end(specs), back_inserter(children), | |
[&](decltype(specs)::value_type const& s){ | |
auto t = s.second.to_ptree(); | |
t.put("name", s.first); | |
return make_pair("",t); | |
}); | |
ret.add_child("specializations", children); | |
return ret; | |
} | |
Specialization Specialization::from_ptree(const boost::property_tree::ptree & pt) | |
{ | |
Specialization s; | |
try{ | |
for(auto&& p : as_const(pt.get_child("years"))){ | |
try{ | |
s.years[p.second.get<int>("year")] = Year::from_ptree(p.second); | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
} | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
return s; | |
} | |
boost::property_tree::ptree Specialization::to_ptree() const | |
{ | |
pt::ptree ret; | |
pt::ptree children; | |
transform(begin(years), end(years), back_inserter(children), | |
[&](decltype(years)::value_type const& y){ | |
auto t = y.second.to_ptree(); | |
t.put("year", y.first); | |
return make_pair("", t); | |
}); | |
ret.add_child("years", children); | |
return ret; | |
} | |
Year Year::from_ptree(const boost::property_tree::ptree & pt) | |
{ | |
Year y; | |
try{ | |
for(auto&& p : as_const(pt.get_child("students"))){ | |
try{ | |
y.students.insert(Student::from_ptree(p.second)); | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
} | |
}catch(std::exception const& e){ | |
// do nothing | |
} | |
return y; | |
} | |
boost::property_tree::ptree Year::to_ptree() const | |
{ | |
pt::ptree ret; | |
pt::ptree children; | |
transform(begin(students), end(students), back_inserter(children), | |
[&](Student const& s){ | |
return make_pair("",s.to_ptree()); | |
}); | |
ret.add_child("students", children); | |
return ret; | |
} | |
Student Student::from_ptree(const boost::property_tree::ptree & pt) | |
{ | |
Student s; | |
s.firstName = pt.get<std::string>("firstName"); | |
s.lastName = pt.get<std::string>("lastName"); | |
return s; | |
} | |
boost::property_tree::ptree Student::to_ptree() const | |
{ | |
pt::ptree pt; | |
pt.put("firstName", firstName); | |
pt.put("lastName", lastName); | |
return pt; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"faculties": | |
[ | |
{ | |
"specializations": | |
[ | |
{ | |
"years": | |
[ | |
{ | |
"students": | |
[ | |
{ | |
"firstName": "Adrian", | |
"lastName": "Kowalski" | |
}, | |
{ | |
"firstName": "Anna", | |
"lastName": "Okiennicka" | |
}, | |
{ | |
"firstName": "Jan", | |
"lastName": "Kowalski" | |
} | |
], | |
"year": "2014" | |
} | |
], | |
"name": "Politologia" | |
} | |
], | |
"name": "Europeistyka" | |
}, | |
{ | |
"specializations": | |
[ | |
{ | |
"years": | |
[ | |
{ | |
"students": | |
[ | |
{ | |
"firstName": "Donald", | |
"lastName": "Tusk" | |
} | |
], | |
"year": "2013" | |
} | |
], | |
"name": "Rekreacja" | |
} | |
], | |
"name": "Turystyka" | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment