Skip to content

Instantly share code, notes, and snippets.

@KrzaQ

KrzaQ/db.cpp Secret

Created September 13, 2014 16:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KrzaQ/10a035a905d6cfe1a458 to your computer and use it in GitHub Desktop.
Save KrzaQ/10a035a905d6cfe1a458 to your computer and use it in GitHub Desktop.
#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;
}
{
"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