commit 69b2fecb3c6afe1358abb309dd8a3a95cdf417e7
parent 8af1469e5448a18f63b83bf7b144d18d87940f5b
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Thu, 23 Nov 2023 19:34:45 +0000
Consistency Improvement
* Move generation code to generate.cpp
* Improve exception safety
* Improve decomposition
Diffstat:
3 files changed, 78 insertions(+), 69 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Stamen
- VERSION 0.0.10
+ VERSION 0.0.11
DESCRIPTION "Static menu generator"
LANGUAGES CXX
)
diff --git a/include/stamen.h b/include/stamen.h
@@ -15,6 +15,7 @@ namespace stamen {
class Menu {
public:
+ friend class Generator;
typedef int (*callback_f)(void);
Menu(const Menu &) = delete;
@@ -22,35 +23,27 @@ public:
struct private_ctor_t {};
+ // Tag type dispatch
Menu(private_ctor_t, const std::string &code, const std::string &prompt)
: Menu(code, prompt) {}
Menu(private_ctor_t, const std::string &code, const callback_f callback)
: Menu(code, callback) {}
- class EMenu : std::exception {
- virtual const char *what() const noexcept override {
- return "Trying to access an unknown menu";
- }
- };
-
struct item_t {
- friend class Menu;
-
item_t(const callback_f func, const std::string &prompt)
: callback(func), prompt(prompt) {}
+ item_t(const std::string &code, const std::string &prompt)
+ : code(code), prompt(prompt) {}
+
+ const std::string getCode(void) const { return code; }
const std::string getPrompt(void) const { return prompt; }
const callback_f getCallback(void) const { return callback; }
- int operator()(void) const {
- return callback ? callback() : getMenu(code)();
- }
+ int operator()(void) const { return callback ? callback() : start(code); }
private:
- item_t(const std::string &code, const std::string &prompt)
- : code(code), prompt(prompt) {}
-
const std::string prompt, code;
const callback_f callback = nullptr;
};
@@ -61,11 +54,12 @@ public:
static void read(const std::string &s);
static void insert(const std::string &code, const callback_f callback);
- static int start(const std::string &entry) { return getMenu(entry)(); }
static void print(const std::string &entry) { print(entry, 1); }
-
- static void generateSource(std::ostream &os);
- static void generateInclude(std::ostream &os);
+ static int start(const std::string &entry) {
+ const Menu *menu = getMenu(entry);
+ if (!menu) return 1;
+ return menu->operator()();
+ }
int operator()() const {
return callback ? callback() : display(title, items.data(), items.size());
@@ -86,11 +80,11 @@ private:
static void print(const std::string &entry, const int depth);
- static const Menu &getMenu(const std::string &code) {
+ static const Menu *getMenu(const std::string &code) {
static lookup_t &lookup = getLookup();
const auto it = lookup.find(code);
- if (it == lookup.end()) throw EMenu();
- return it->second;
+ if (it == lookup.end()) return nullptr;
+ return &it->second;
}
const std::string code, title;
@@ -126,55 +120,17 @@ inline void Menu::insert(const std::string &code, const callback_f callback) {
std::forward_as_tuple(private_ctor_t{}, code, callback));
}
-inline void Menu::generateInclude(std::ostream &os) {
- os << "#ifndef STAMEN_MENU_H\n";
- os << "#define STAMEN_MENU_H\n\n";
- os << "#include <stamen.h>\n\n";
- os << "namespace stamen {\n\n";
- for (const auto &[code, _] : getLookup()) {
- const Menu &menu = getMenu(code);
- if (menu.callback) continue;
- os << std::format("int {}(void);\n", menu.code);
- }
- os << "\n}\n";
- os << "#endif\n";
-}
-
-inline void Menu::generateSource(std::ostream &os) {
- os << "#include <stamen.h>\n";
- os << "#include \"shared.h\"\n";
- os << "\nnamespace stamen {\n";
- for (const auto &[code, _] : getLookup()) {
- const Menu &menu = getMenu(code);
- if (menu.callback) continue;
-
- os << std::format("int {}(void) {{\n", menu.code);
- os << std::format("\tstatic const Menu::item_t items[] = {{\n");
- for (const auto &item : menu.items) {
- os << std::format("\t\t{{{}, \"{}\"}},\n", item.code, item.prompt);
- }
- os << std::format("\t}};\n");
- os << std::format("\treturn Menu::display(\"{}\", items, "
- "sizeof(items) / sizeof(Menu::item_t));\n",
- menu.title);
- os << std::format("}}\n\n");
- }
- os << "\n}\n";
-}
-
inline void Menu::print(const std::string &code, const int depth) {
- static lookup_t &lookup = getLookup();
- const auto it = lookup.find(code);
- if (it == lookup.end()) return;
- const Menu &menu = it->second;
+ const Menu *menu = getMenu(code);
+ if (!menu) return;
- if (depth == 1) std::cout << std::format("{}({})\n", menu.title, code);
+ if (depth == 1) std::cout << std::format("{}({})\n", menu->title, code);
- if (!menu.callback) {
- for (const auto &item : menu.items) {
+ if (!menu->callback) {
+ for (const auto &item : menu->items) {
std::cout << std::format("{}{} ({})\n", std::string(depth << 1, ' '),
- item.prompt, item.code);
- menu.print(item.code, depth + 1);
+ item.getPrompt(), item.getCode());
+ menu->print(item.getCode(), depth + 1);
}
}
}
diff --git a/src/generate.cpp b/src/generate.cpp
@@ -3,6 +3,58 @@
using namespace stamen;
+namespace stamen {
+
+class Generator {
+public:
+ class EGenerate : std::exception {
+ virtual const char *what() const noexcept override {
+ return "Trying to access unknown code";
+ }
+ };
+
+ static void generateInclude(std::ostream &os) {
+ os << "#ifndef STAMEN_MENU_H\n";
+ os << "#define STAMEN_MENU_H\n\n";
+ os << "#include <stamen.h>\n\n";
+ os << "namespace stamen {\n\n";
+ for (const auto &[code, _] : Menu::getLookup()) {
+ const Menu *menu = Menu::getMenu(code);
+ if (!menu) throw EGenerate();
+ if (menu->callback) continue;
+ os << std::format("int {}(void);\n", menu->code);
+ }
+ os << "\n}\n";
+ os << "#endif\n";
+ }
+
+ static void generateSource(std::ostream &os) {
+ os << "#include <stamen.h>\n";
+ os << "#include \"shared.h\"\n";
+ os << "\nnamespace stamen {\n";
+ for (const auto &[code, _] : Menu::getLookup()) {
+ const Menu *menu = Menu::getMenu(code);
+ if (!menu) throw EGenerate();
+ if (menu->callback) continue;
+
+ os << std::format("int {}(void) {{\n", menu->code);
+ os << std::format("\tstatic const Menu::item_t items[] = {{\n");
+ for (const auto &item : menu->items) {
+ os << std::format("\t\t{{{}, \"{}\"}},\n", item.getCode(),
+ item.getPrompt());
+ }
+ os << std::format("\t}};\n");
+ os << std::format("\treturn Menu::display(\"{}\", items, "
+ "sizeof(items) / sizeof(Menu::item_t));\n",
+ menu->title);
+ os << std::format("}}\n\n");
+ }
+ os << "\n}\n";
+ }
+};
+
+} // namespace stamen
+
int main(const int argc, const char *argv[]) {
if (argc != 2) {
std::cout << "please enter exaclty one config file" << std::endl;
@@ -15,8 +67,9 @@ int main(const int argc, const char *argv[]) {
std::string::size_type pos = path.rfind('.');
std::string base = pos != std::string::npos ? path.substr(0, pos) : path;
std::ofstream cpp(base + ".cpp"), h(base + ".h");
- Menu::generateSource(cpp);
- Menu::generateInclude(h);
+
+ Generator::generateSource(cpp);
+ Generator::generateInclude(h);
return 0;
}