35     virtual ~Visitor() = 
default;
 
   38     virtual void visit(DirectoryEntry& 
e);
 
   41     virtual void visit(DurationEntry&) {}
 
   42     virtual void visit(SizeEntry&) {}
 
   43     virtual void visit(TextEntry&) {}
 
   44     virtual void visit(TimeEntry&) {}
 
   58     Entry(std::string key) : key(
std::move(key)) {}
 
   59     virtual ~
Entry() = 
default;
 
   62     const std::string& getKey()
 const {
 
   67     virtual void accept(Visitor& v) = 0;
 
   70     virtual void print(std::ostream& os, 
int tabpos) 
const = 0;
 
   76 class DirectoryEntry : 
public Entry {
 
   78     std::map<std::string, Own<Entry>> entries;
 
   79     mutable std::mutex lock;
 
   82     DirectoryEntry(
const std::string& name) : 
Entry(name) {}
 
   85     const std::set<std::string> getKeys()
 const {
 
   86         std::set<std::string> result;
 
   87         std::lock_guard<std::mutex> guard(lock);
 
   88         for (
auto const& cur : entries) {
 
   89             result.insert(cur.first);
 
   95     Entry* writeEntry(Own<Entry> entry) {
 
   96         assert(entry != 
nullptr && 
"null entry");
 
   97         std::lock_guard<std::mutex> guard(lock);
 
   98         const std::string& keyToWrite = entry->getKey();
 
  100         if (entries.count(keyToWrite) == 0) {
 
  101             entries[keyToWrite] = std::move(entry);
 
  103         return entries[keyToWrite].get();
 
  107     Entry* readEntry(
const std::string& keyToRead)
 const {
 
  108         std::lock_guard<std::mutex> guard(lock);
 
  109         auto it = entries.find(keyToRead);
 
  110         if (it != entries.end()) {
 
  111             return (*it).second.get();
 
  118     DirectoryEntry* readDirectoryEntry(
const std::string& keyToRead)
 const {
 
  119         return dynamic_cast<DirectoryEntry*
>(readEntry(keyToRead));
 
  123     void accept(Visitor& v)
 override {
 
  128     void print(std::ostream& os, 
int tabpos)
 const override {
 
  129         os << std::string(tabpos, 
' ') << 
'"' << getKey() << 
"\": {" << std::endl;
 
  131         for (
auto const& cur : entries) {
 
  133                 os << 
',' << std::endl;
 
  137             cur.second->print(os, tabpos + 1);
 
  139         os << std::endl << std::string(tabpos, 
' ') << 
'}';
 
  146 class SizeEntry : 
public Entry {
 
  153     size_t getSize()
 const {
 
  158     void accept(Visitor& v)
 override {
 
  163     void print(std::ostream& os, 
int tabpos)
 const override {
 
  164         os << std::string(tabpos, 
' ') << 
"\"" << getKey() << 
"\": " << 
size;
 
  171 class TextEntry : 
public Entry {
 
  177     TextEntry(
const std::string& key, std::string text) : 
Entry(key), text(
std::move(text)) {}
 
  180     const std::string& getText()
 const {
 
  185     void accept(Visitor& v)
 override {
 
  190     void print(std::ostream& os, 
int tabpos)
 const override {
 
  191         os << std::string(tabpos, 
' ') << 
"\"" << getKey() << 
"\": \"" << text << 
"\"";
 
  198 class DurationEntry : 
public Entry {
 
  207     DurationEntry(
const std::string& key, microseconds start, microseconds end)
 
  208             : 
Entry(key), start(start), end(end) {}
 
  211     microseconds getStart()
 const {
 
  216     microseconds getEnd()
 const {
 
  221     void accept(Visitor& v)
 override {
 
  226     void print(std::ostream& os, 
int tabpos)
 const override {
 
  227         os << std::string(tabpos, 
' ') << 
'"' << getKey();
 
  228         os << R
"_(": { "start": )_"; 
  239 class TimeEntry : 
public Entry {
 
  248     microseconds getTime()
 const {
 
  253     void accept(Visitor& v)
 override {
 
  258     void print(std::ostream& os, 
int tabpos)
 const override {
 
  259         os << std::string(tabpos, 
' ') << 
'"' << getKey();
 
  260         os << R
"_(": { "time": )_"; 
  266 inline void Visitor::visit(DirectoryEntry& 
e) {
 
  267     std::cout << 
"Dir " << 
e.getKey() << 
"\n";
 
  268     for (
const auto& cur : 
e.getKeys()) {
 
  269         std::cout << 
"\t :" << cur << 
"\n";
 
  270         e.readEntry(cur)->accept(*
this);
 
  274 class Counter : 
public Visitor {
 
  280     Counter(std::string key) : key(
std::move(key)) {}
 
  281     void visit(SizeEntry& 
e)
 override {
 
  282         std::cout << 
"Size entry : " << 
e.getKey() << 
" " << 
e.getSize() << 
"\n";
 
  283         if (
e.getKey() == key) {
 
  287     size_t getCounter()
 const {
 
  295 class ProfileDatabase {
 
  297     Own<DirectoryEntry> root;
 
  303     DirectoryEntry* lookupPath(
const std::vector<std::string>& path) {
 
  304         DirectoryEntry* dir = root.get();
 
  305         for (
const std::string& key : path) {
 
  306             assert(!key.empty() && 
"Key is empty!");
 
  307             DirectoryEntry* newDir = dir->readDirectoryEntry(key);
 
  308             if (newDir == 
nullptr) {
 
  309                 newDir = 
dynamic_cast<DirectoryEntry*
>(dir->writeEntry(mk<DirectoryEntry>(key)));
 
  311             assert(newDir != 
nullptr && 
"Attempting to overwrite an existing entry");
 
  317     void parseJson(
const json11::Json& json, Own<DirectoryEntry>& node) {
 
  319             if (cur.second.is_object()) {
 
  322                 if (cur.second.has_shape(
 
  323                             {{
"start", json11::Json::NUMBER}, {
"end", json11::Json::NUMBER}}, 
err)) {
 
  324                     auto start = std::chrono::microseconds(cur.second[
"start"].long_value());
 
  325                     auto end = std::chrono::microseconds(cur.second[
"end"].long_value());
 
  326                     node->writeEntry(mk<DurationEntry>(cur.first, start, end));
 
  327                 } 
else if (cur.second.has_shape({{
"time", json11::Json::NUMBER}}, 
err)) {
 
  328                     auto time = std::chrono::microseconds(cur.second[
"time"].long_value());
 
  329                     node->writeEntry(mk<TimeEntry>(cur.first, 
time));
 
  331                     auto dir = mk<DirectoryEntry>(cur.first);
 
  332                     parseJson(cur.second, dir);
 
  333                     node->writeEntry(std::move(dir));
 
  335             } 
else if (cur.second.is_string()) {
 
  336                 node->writeEntry(mk<TextEntry>(cur.first, cur.second.string_value()));
 
  337             } 
else if (cur.second.is_number()) {
 
  338                 node->writeEntry(mk<SizeEntry>(cur.first, cur.second.long_value()));
 
  341                 cur.second.dump(
err);
 
  342                 std::cerr << 
"Unknown types in profile log: " << cur.first << 
": " << 
err << std::endl;
 
  348     ProfileDatabase() : root(
mk<DirectoryEntry>(
"root")) {}
 
  350     ProfileDatabase(
const std::string& filename) : root(
mk<DirectoryEntry>(
"root")) {
 
  351         std::ifstream file(filename);
 
  352         if (!file.is_open()) {
 
  353             throw std::runtime_error(
"Log file could not be opened.");
 
  355         std::string jsonString((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
 
  358         if (!error.empty()) {
 
  359             throw std::runtime_error(
"Parse error: " + error);
 
  361         parseJson(json[
"root"], root);
 
  365     void addSizeEntry(std::vector<std::string> qualifier, 
size_t size) {
 
  366         assert(qualifier.size() > 0 && 
"no qualifier");
 
  367         std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
 
  368         DirectoryEntry* dir = lookupPath(path);
 
  370         const std::string& key = qualifier.back();
 
  371         Own<SizeEntry> entry = mk<SizeEntry>(key, 
size);
 
  372         dir->writeEntry(std::move(entry));
 
  376     void addTextEntry(std::vector<std::string> qualifier, 
const std::string& text) {
 
  377         assert(qualifier.size() > 0 && 
"no qualifier");
 
  378         std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
 
  379         DirectoryEntry* dir = lookupPath(path);
 
  381         const std::string& key = qualifier.back();
 
  382         Own<TextEntry> entry = std::make_unique<TextEntry>(key, text);
 
  383         dir->writeEntry(std::move(entry));
 
  387     void addDurationEntry(std::vector<std::string> qualifier, microseconds start, microseconds end) {
 
  388         assert(qualifier.size() > 0 && 
"no qualifier");
 
  389         std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
 
  390         DirectoryEntry* dir = lookupPath(path);
 
  392         const std::string& key = qualifier.back();
 
  393         Own<DurationEntry> entry = std::make_unique<DurationEntry>(key, start, end);
 
  394         dir->writeEntry(std::move(entry));
 
  398     void addTimeEntry(std::vector<std::string> qualifier, microseconds 
time) {
 
  399         assert(qualifier.size() > 0 && 
"no qualifier");
 
  400         std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
 
  401         DirectoryEntry* dir = lookupPath(path);
 
  403         const std::string& key = qualifier.back();
 
  404         Own<TimeEntry> entry = std::make_unique<TimeEntry>(key, 
time);
 
  405         dir->writeEntry(std::move(entry));
 
  409     size_t computeSum(
const std::vector<std::string>& qualifier) {
 
  410         assert(qualifier.size() > 0 && 
"no qualifier");
 
  411         std::vector<std::string> path(qualifier.begin(), qualifier.end() - 1);
 
  412         DirectoryEntry* dir = lookupPath(path);
 
  414         const std::string& key = qualifier.back();
 
  415         std::cout << 
"Key: " << key << std::endl;
 
  418         return ctr.getCounter();
 
  424     Entry* lookupEntry(
const std::vector<std::string>& path)
 const {
 
  425         DirectoryEntry* dir = root.get();
 
  426         auto last = --path.end();
 
  427         for (
auto it = path.begin(); it != last; ++it) {
 
  428             dir = dir->readDirectoryEntry(*it);
 
  429             if (dir == 
nullptr) {
 
  433         return dir->readEntry(*last);
 
  439     std::map<std::string, std::string> getStringMap(
const std::vector<std::string>& path)
 const {
 
  440         std::map<std::string, std::string> kvps;
 
  441         auto* parent = 
dynamic_cast<DirectoryEntry*
>(lookupEntry(path));
 
  442         if (parent == 
nullptr) {
 
  446         for (
const auto& key : parent->getKeys()) {
 
  447             auto* text = 
dynamic_cast<TextEntry*
>(parent->readEntry(key));
 
  448             if (text != 
nullptr) {
 
  449                 kvps[key] = text->getText();
 
  457     void print(std::ostream& os)
 const {
 
  458         os << 
'{' << std::endl;
 
  460         os << std::endl << 
'}' << std::endl;