Refactored template loading to its own class for performance
authorHarishankar <v.harishankar@gmail.com>
Thu, 21 May 2020 09:39:03 +0000 (15:09 +0530)
committerHarishankar <v.harishankar@gmail.com>
Thu, 21 May 2020 09:53:20 +0000 (15:23 +0530)
Refactored template string loading to its own class to avoid
reading the template directory for every call to to_html() or
output_to_html ()

biaweb.cpp
biawebdoclist.hpp
biawebdocument.hpp
biawebdocumenttree.hpp
biawebnavigationbit.hpp
biawebsidebar.hpp
biawebtemplate.hpp [new file with mode: 0644]
biawebutil.hpp
templates/main.tpl.html
templates/style.tpl.css

index 22e4121..2ed34fb 100644 (file)
@@ -36,11 +36,16 @@ int main (int argc, char *argv[]) {
 // //     else {
 // //         std::cout << "Usage: " << argv[0] << " <main tree>" << std::endl;
 
+    std::chrono::steady_clock::time_point t1 (std::chrono::steady_clock::now());
     DocumentTree tree (""); 
     tree.document_tree_builder ("Test/Reviews");
     tree.visualize_tree ();
-    tree.create_tree_html ("templates", 
-                        "Test/Out");
+    Template tpl ("templates");
+    tree.create_tree_html (&tpl, "Test/Out");
+    std::chrono::steady_clock::time_point t2 (std::chrono::steady_clock::now());
+    std::chrono::duration<double> dur (t2 - t1);
+    std::cout << dur.count () << std::endl;
+
 // //   }
 
     // Document doc;
index 547664a..8a92cdd 100644 (file)
@@ -10,6 +10,7 @@
 #include <fmt/chrono.h>
 #include "biawebstrings.hpp"
 #include "biawebdocument.hpp"
+#include "biawebtemplate.hpp"
 
 // to implement a list of items (documents) with creation/modified date/time display
 namespace biaweb {
@@ -59,16 +60,12 @@ namespace biaweb {
         }
         
         // output to HTML vide the template
-        std::string to_html (std::string templatedir);
+        std::string to_html (Template *t);
     };
     
     // output to HTML vide the template 
-    std::string DocListItem::to_html (std::string templatedir) {
-        std::ifstream templ (templatedir + "/doclistitem.tpl.html");
-        std::string templstr ((std::istreambuf_iterator<char> (templ)),
-                            (std::istreambuf_iterator<char> ()) );
-        templ.close ();
-
+    std::string DocListItem::to_html (Template *t) {
+        std::string templstr = t->get_doclistitem_tpl ();
         std::tm c, m;
         c = *std::localtime (&this->ctime);
         m = *std::localtime (&this->mtime);
@@ -95,22 +92,18 @@ namespace biaweb {
             this->items.insert (this->items.cend(), docitem);
         }
         // render to HTML from a template
-        std::string to_html (std::string templatedir);
+        std::string to_html (Template *t);
     };
 
-    std::string DocList::to_html (std::string templatedir) {
-        std::ifstream templ (templatedir + "/doclist.tpl.html");
-        std::string templstr ( (std::istreambuf_iterator<char> (templ) ),
-                                (std::istreambuf_iterator<char> ()));
-
-        templ.close ();
+    std::string DocList::to_html (Template *t) {
+        std::string templstr = t->get_doclist_tpl ();
 
         std::string outputhtml = "";
         // if the number of elements is non zero
         if (this->items.size () != 0) {
             std::string docitems = "";
             for (DocListItem item : this->items)
-                docitems += item.to_html (templatedir);
+                docitems += item.to_html (t);
 
             outputhtml = fmt::format (templstr, 
                                             fmt::arg ("title", this->title),
index 65005dd..3972107 100644 (file)
@@ -8,11 +8,11 @@
 #include <iomanip>
 #include <ctime>
 #include <fmt/format.h>
-#include <fmt/chrono.h>
 #include "biawebutil.hpp"
 #include "biawebsidebar.hpp"
 #include "biawebstrings.hpp"
 #include "biawebnavigationbit.hpp"
+#include "biawebtemplate.hpp"
 
 // class to represent a biaweb document which can have a file name, title, description, 
 // keywords, content and sidebar items
@@ -101,8 +101,8 @@ namespace biaweb {
             return this->cdate;
         }
 
-        // output the document to HTML using the templates in templatedir
-        void output_to_html (std::string templatedir, std::string path); 
+        // output the document to HTML using the template specified
+        void output_to_html (Template *t, std::string path); 
 
         // set the content portion of document as raw HTML content
         void set_content (std::string content) {
@@ -194,26 +194,20 @@ namespace biaweb {
     }
     
     // output the document using the provided template
-    void Document::output_to_html (std::string templatedir, std::string path)
+    void Document::output_to_html (Template *t, std::string path)
     {
-        // read the main template file
-        std::ifstream tpl (templatedir + "/main.tpl.html");
-        std::string templstr ( (std::istreambuf_iterator<char> (tpl)),
-                                (std::istreambuf_iterator<char> ()) );
-        tpl.close ();
+        std::string templstr = t->get_main_tpl ();
+
         // read the style template file
-        std::ifstream style (templatedir + "/style.tpl.css");
-        std::string stylesheet ( (std::istreambuf_iterator<char> (style)),
-                                (std::istreambuf_iterator<char> ()));
-        style.close ();
+        std::string stylesheet = t->get_style_tpl ();
         // first render the sidebars
         std::string sidebartext;
         for (SideBar bar : sidebars) {
-            sidebartext += bar.to_html (templatedir);
+            sidebartext += bar.to_html (t);
         }
 
         // render the navigation bit
-        std::string navbit_str = this->navbit.to_html (templatedir);
+        std::string navbit_str = this->navbit.to_html (t);
 
         // time of creation and modification 
         struct std::tm c, m;
index 9122feb..e1e6401 100644 (file)
@@ -11,6 +11,7 @@
 #include "biawebstrings.hpp"
 #include "biawebutil.hpp"
 #include "biawebdoclist.hpp"
+#include "biawebtemplate.hpp"
 
 // class to implement a document tree - both with or without subtrees
 namespace biaweb {
@@ -29,17 +30,12 @@ namespace biaweb {
         std::string stub;
         // list of documents in this tree
         std::list<Document> docs;
-        // common strings used for template generation 
-        std::array<std::string, 6> doc_strings;
         // set the parent - protected function as this has to be 
         // called only by add_child
         void set_parent (DocumentTree *parent) {
             this->parent = parent;
         }
 
-        // load document generation strings from file stringbits.txt from template dir
-        void load_doc_strings (std::string templatedir);
-
       public:
         // method to build a document tree from a path
         void document_tree_builder (std::string srcpath);
@@ -77,7 +73,7 @@ namespace biaweb {
         }
 
         // create the document index for this tree
-        void create_tree_html (std::string templatedir, std::string destdir);
+        void create_tree_html (Template *t, std::string destdir);
 
         // set the title 
         void set_title (std::string title) {
@@ -136,22 +132,6 @@ namespace biaweb {
             return lev;
     }
 
-    // load document generation strings from file stringbits.txt from template dir
-    void DocumentTree::load_doc_strings (std::string templatedir) {
-        // load the template file
-        std::ifstream stringsfile (templatedir + "/stringbits.txt");
-        
-        std::string line;
-        // read line by line and append it to doc_strings
-        int i = 0;
-        while (! stringsfile.eof () && i < this->doc_strings.size ()) {
-            std::getline (stringsfile, line);
-            this->doc_strings[i] = line;
-            i ++;
-        }
-        stringsfile.close ();
-    }
-
     // get the stub hierarchy for this tree
     std::string DocumentTree::stub_hierarchy () {
             std::list<std::string> levels;
@@ -185,9 +165,7 @@ namespace biaweb {
 
     // create the tree - the index file for this tree and all the documents and
     // the child trees recursively - using the template specified
-    void DocumentTree::create_tree_html (std::string templatedir, std::string destdir) {
-        // load the document string bits to be used in templates
-        this->load_doc_strings (templatedir);
+    void DocumentTree::create_tree_html (Template *tpl, std::string destdir) {
 
         // create a document to represent the index of the tree.
         std::unique_ptr<Document> index (new Document (this->title));
@@ -208,13 +186,13 @@ namespace biaweb {
         // If this tree has a parent, create a sidebar link to the level up
         std::unique_ptr<SideBar> bar1 (new SideBar());
         GenericLinkItem item0;
-        bar1.get()->set_title (this->doc_strings [NAVIGATION]);
-        item0.set_item_text (this->doc_strings[INDEX]);
+        bar1.get()->set_title (tpl->get_stringbit (NAVIGATION));
+        item0.set_item_text (tpl->get_stringbit (INDEX));
         item0.set_item_url (urlpath + "index.html");
         bar1.get()->add_sidebar_item (item0);
         if (this->get_parent() != nullptr) {
             GenericLinkItem item1;
-            item1.set_item_text (this->doc_strings[GO_UP]);
+            item1.set_item_text (tpl->get_stringbit(GO_UP));
             item1.set_item_url (this->stub_hierarchy() + "index.html");
             bar1.get()->add_sidebar_item (item1);
         }
@@ -222,7 +200,7 @@ namespace biaweb {
 
         // create a sidebar for the child levels if there are children
         std::unique_ptr<SideBar> bar2 (new SideBar ());
-        bar2.get()->set_title (this->doc_strings[SUB_CAT] + this->title);
+        bar2.get()->set_title (tpl->get_stringbit (SUB_CAT) + this->title);
         for (DocumentTree tree : this->children) {
             // we use site relative URLs that rely on the base href tag
             // so for biaweb generated sites, the base href tag should be 
@@ -238,7 +216,7 @@ namespace biaweb {
 
         // Create the list of documents in this tree with links
         std::unique_ptr<DocList> article_list (new DocList ());
-        article_list.get()->set_title (this->title + ": " + this->doc_strings[ARTICLES_LIST]);
+        article_list.get()->set_title (this->title + ": " + tpl->get_stringbit (ARTICLES_LIST));
         // sort the documents as per creation time and then add the document
         // links - newest documents should appear above older ones.
         sort_documents_creation_time ();
@@ -253,7 +231,7 @@ namespace biaweb {
                 navbit.get()->add_link_item (GenericLinkItem(par1->stub, 
                             par1->stub_hierarchy() + par1->stub + "/index.html"));
             else
-                navbit.get()->add_link_item (GenericLinkItem(this->doc_strings[HOME], "index.html"));
+                navbit.get()->add_link_item (GenericLinkItem(tpl->get_stringbit(HOME), "index.html"));
             par1 = par1->parent;
         }
 
@@ -267,20 +245,20 @@ namespace biaweb {
             doc.set_navigation_bit (*navbit.get());
             doc.add_side_bar (*bar1.get());
             doc.add_side_bar (*bar2.get());
-            doc.output_to_html (templatedir, filepath);
+            doc.output_to_html (tpl, filepath);
         }
 
         // add the navigation bit
         index.get()->set_navigation_bit (*navbit.get());
         // index should contain the summary followed by the article list
-        index.get()->set_content (this->summary + article_list.get()->to_html(templatedir));
+        index.get()->set_content (this->summary + article_list.get()->to_html(tpl));
 
         // output the index file
-        index.get()->output_to_html (templatedir, filepath);
+        index.get()->output_to_html (tpl, filepath);
 
         // recursively create index for children
         for (DocumentTree tree : this->children)
-            tree.create_tree_html (templatedir, destdir);
+            tree.create_tree_html (tpl, destdir);
     }
 
     // build a document tree from a filesystem path recursively
@@ -307,9 +285,7 @@ namespace biaweb {
                     // the contents to the summary of the Doctree 
                     if (fsitem.path().stem().string() == "index")
                     {
-                        std::ifstream infile (fsitem.path());
-                        std::string infilestr ( (std::istreambuf_iterator<char> (infile)),
-                                                (std::istreambuf_iterator<char> ()) );
+                        std::string infilestr = load_from_file (fsitem.path ()); 
                         this->set_markdown_summary (infilestr);
                     }
                     // else it is a non-index file-  
index 6be5b40..08a2cc5 100644 (file)
@@ -6,6 +6,7 @@
 #include <fmt/format.h>
 #include "biawebutil.hpp"
 #include "biawebsidebar.hpp"
+#include "biawebtemplate.hpp"
 
 namespace biaweb {
     // class to represent a navigation bit like this in html
@@ -21,20 +22,17 @@ namespace biaweb {
         }
 
         // render using the given template directory
-        std::string to_html (std::string templatedir) ;
+        std::string to_html (Template *t) ;
     };
 
     // render using the given template 
-    std::string NavigationBit::to_html (std::string templatedir) {
-        std::ifstream templ (templatedir + "/navigationbit.tpl.html");
-        std::string templ_str ((std::istreambuf_iterator<char> (templ)),
-                               (std::istreambuf_iterator<char> ()));
-        
+    std::string NavigationBit::to_html (Template *t) {
+        std::string templ_str = t->get_navigationbit_tpl ();
 
         std::string output_html = "";
         std::string items_str = "";
         for (GenericLinkItem item : this->items)
-            items_str += item.to_html (templatedir);
+            items_str += item.to_html (t);
 
         if (this->items.size () > 0)
             output_html = fmt::format (templ_str, fmt::arg ("items", items_str));
index 6f419fa..226f51a 100644 (file)
@@ -6,6 +6,7 @@
 #include <fstream>
 #include <fmt/format.h>
 #include "biawebutil.hpp"
+#include "biawebtemplate.hpp"
 
 // classes to describe the a list of (link) items and sidebar containers which form part of 
 // main document
@@ -30,8 +31,8 @@ namespace biaweb {
         void set_item_url (std::string url) {
             this->itemurl = escape_html (url);
         }
-        // output to HTML using a template directory specified
-        std::string to_html (std::string templatedir);
+        // output to HTML using a template specified
+        std::string to_html (Template *t);
     
         GenericLinkItem (std::string text = "", std::string url = "") {
             this->itemtext = escape_html (text);
@@ -39,17 +40,13 @@ namespace biaweb {
         }
     };
 
-    std::string GenericLinkItem::to_html (std::string templatedir) {
+    std::string GenericLinkItem::to_html (Template *t) {
         std::string html = "";
         // if url is not empty it is a link item so load the sidebar link template
         if (! this->itemurl.empty ()) {
             if (!this->itemtext.empty ())
             {
-                std::ifstream tpl_linkitem (templatedir + "/genericlinklistitem.tpl.html");
-
-                std::string tpl_linkitem_str ( (std::istreambuf_iterator<char> (tpl_linkitem)),
-                                                (std::istreambuf_iterator<char> ()));
-                tpl_linkitem.close ();
+                std::string tpl_linkitem_str = t->get_genericlinklistitem_tpl ();
                 html = fmt::format (tpl_linkitem_str, 
                                         fmt::arg ("itemurl", this->itemurl),
                                         fmt::arg ("itemtext", this->itemtext));
@@ -58,11 +55,7 @@ namespace biaweb {
         // Non link item. Load the normal sidebar item template.
         else if (! this->itemtext.empty ())
         {
-            std::ifstream tpl_item (templatedir + "/genericlistitem.tpl.html");
-
-            std::string tpl_item_str ( (std::istreambuf_iterator<char> (tpl_item)),
-                                        (std::istreambuf_iterator<char> ()));
-            tpl_item.close ();
+            std::string tpl_item_str = t->get_genericlistitem_tpl ();
             html = fmt::format (tpl_item_str, fmt::arg ("itemtext", this->itemtext) );
         } 
         return html;
@@ -84,20 +77,18 @@ namespace biaweb {
             this->items.insert (this->items.cend(), item);
         }
 
-        // render the sidebar using the template directory specified
-        std::string to_html (std::string templatedir) ;
+        // render the sidebar using the template specified
+        std::string to_html (Template *t) ;
     };
 
     // render the sidebar to HTML representation from the template.
-    std::string SideBar::to_html (std::string templatedir) {
-        std::ifstream sidetpl (templatedir + "/sidebar.tpl.html");
-        std::string sidetpl_str ( ( std::istreambuf_iterator<char> (sidetpl)) , 
-                                       (std::istreambuf_iterator<char> ()));
-        sidetpl.close ();
+    std::string SideBar::to_html (Template *t) {
+        std::string sidetpl_str = t->get_sidebar_tpl ();
+
         std::string listitems;
         // first get the sidebar items and render them to HTML
         for (GenericLinkItem item : this->items) {
-            listitems += item.to_html (templatedir);
+            listitems += item.to_html (t);
         }
         
         std::string html = "";
diff --git a/biawebtemplate.hpp b/biawebtemplate.hpp
new file mode 100644 (file)
index 0000000..604cb26
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __BIAWEBTEMPLATE__
+#define __BIAWEBTEMPLATE__
+
+#include <array>
+#include <fstream>
+#include "biawebutil.hpp"
+
+namespace biaweb {
+    // class to load template from a directory for use with classes requiring to output 
+    // via templates
+    class Template {
+      protected:
+        // all the template bits stored as strings
+        std::string main_tpl;
+        std::string doclist_tpl;
+        std::string doclistitem_tpl;
+        std::string genericlinklistitem_tpl;
+        std::string genericlistitem_tpl;
+        std::string navigationbit_tpl;
+        std::string sidebar_tpl;
+        std::string style_tpl;
+        std::array<std::string, 6> stringbits;
+      public:
+        // constructor: generate the template bits from a template directory 
+        Template (std::string templatedir) ;
+
+        // getters;
+        std::string get_main_tpl () { return this->main_tpl; }
+        std::string get_doclist_tpl () { return this->doclist_tpl; }
+        std::string get_doclistitem_tpl () { return this->doclistitem_tpl; }
+        std::string get_genericlistitem_tpl () { return this->genericlistitem_tpl; }
+        std::string get_genericlinklistitem_tpl () { return this->genericlinklistitem_tpl; }
+        std::string get_navigationbit_tpl () { return this->navigationbit_tpl; }
+        std::string get_sidebar_tpl () { return this->sidebar_tpl; }
+        std::string get_style_tpl () { return this->style_tpl; } 
+        std::string get_stringbit (unsigned int id) { return this->stringbits[id]; }
+    };
+
+    // construct a template from a source directory
+    Template::Template (std::string templatedir) {
+        // read the templates
+        this->main_tpl = load_from_file (templatedir + "/main.tpl.html");
+        this->doclist_tpl = load_from_file (templatedir + "/doclist.tpl.html");
+        this->doclistitem_tpl = load_from_file (templatedir + "/doclistitem.tpl.html");
+        this->genericlinklistitem_tpl = load_from_file 
+                        (templatedir + "/genericlinklistitem.tpl.html");
+        this->genericlistitem_tpl = load_from_file (templatedir + "/genericlistitem.tpl.html");
+        this->navigationbit_tpl = load_from_file (templatedir + "/navigationbit.tpl.html");
+        this->sidebar_tpl = load_from_file (templatedir + "/sidebar.tpl.html");
+        this->style_tpl = load_from_file (templatedir + "/style.tpl.css");
+
+
+        // read the stringbits into the array
+        std::ifstream f (templatedir + "/stringbits.txt");
+        unsigned int i = 0;
+        std::string line;
+        while (! f.eof () && i < this->stringbits.size ()) {
+            std::getline (f, line);
+            this->stringbits[i] = line;
+            i ++;
+        }
+        f.close ();
+    }
+
+}
+
+#endif
\ No newline at end of file
index c8603ea..279d394 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __BIAWEBUTIL__
 #define __BIAWEBUTIL__
 #include <string>
+#include <fstream>
 
 // "discount" markdown library is a C library and hence requires to be wrapped in 
 // extern "C"
@@ -11,6 +12,13 @@ extern "C" {
 // utility functions for Biaweb that don't fit into any class and can be used by 
 // any class
 namespace biaweb {
+    // load a string from file
+    std::string load_from_file (std::string filename) {
+        std::ifstream f (filename);
+        std::string r ((std::istreambuf_iterator<char> (f)),
+                        (std::istreambuf_iterator<char> ()));
+        return r;
+    }
 
     // convert markdown
     std::string convert_to_markdown (std::string str) {
@@ -29,11 +37,7 @@ namespace biaweb {
         FILE *f = fdopen (fd, "w");
         markdown (doc, f, 0);
         fclose (f);
-        std::ifstream ftmp (tempfile);
-        std::string tmpl ( (std::istreambuf_iterator<char> (ftmp)),
-                            (std::istreambuf_iterator<char> ())
-                                );
-        ftmp.close ();
+        std::string tmpl = load_from_file (tempfile);
         mkd_cleanup (doc);
         remove (tempfile);
         return tmpl;
index 198a3c5..c57f20c 100644 (file)
@@ -1,9 +1,10 @@
 <!DOCTYPE html>
 <html lang="en">
 <head>
+<!-- change as appropriate - just don't touch anything within the curly braces!! -->
 <title>My Site - {title}</title>
-<meta name="keywords" content="{keywords}">
-<meta name="description" content="{description}">
+<meta name="keywords" content="site key words {keywords}">
+<meta name="description" content="Site Description - {description}">
 <!-- change base href to your site URL -->
 <base href="http://my.site">
 <style>
@@ -11,7 +12,8 @@
 </style>
 </head>
 <body>
-    <header></header>
+    <!-- change My Site to your own header -->
+    <header><h1>My Site</h1></header>
     <section id="content">
         <div id="modification">Created on: {cdate:%d %b %Y, %H:%M %Z}, 
             last modified: {mdate:%d %b %Y, %H:%M %Z}</div>
@@ -22,6 +24,7 @@
         {sidebar}
     </nav>
     <footer>
+        <!-- change copyright to your own copyright -->
         My copyright
     </footer>
 </body>
index 3b3358e..d1688ca 100644 (file)
@@ -13,8 +13,8 @@ header {
     width: 100%;
     color: white;
     background-color:#a1a0c0;
-    height: 50px;
     float: left;
+    text-align: center;
 }
 
 .inlinelist {