commit cd12b2fea38be76fe6bd2c607598c785d979c25e
parent 199eba24714cb83271e636100315011def07ded9
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Fri, 14 Jun 2024 11:33:39 +0200
Split menu in its own set of headers
Diffstat:
11 files changed, 154 insertions(+), 165 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -70,14 +70,10 @@ install(
)
install(
- EXPORT
- stamenTargets
- NAMESPACE
- "stamen::"
- DESTINATION
- ${INSTALL_CMAKEDIR}
- COMPONENT
- dev
+ EXPORT stamenTargets
+ NAMESPACE "stamen::"
+ DESTINATION ${INSTALL_CMAKEDIR}
+ COMPONENT dev
)
include(CMakePackageConfigHelpers)
diff --git a/demo/dynamic.cpp b/demo/dynamic.cpp
@@ -1,6 +1,7 @@
-#include "stamen.hpp"
#include <iostream>
+#include "menu.hpp"
+
int finish(int) { exit(1); }
int operation1(int) {
@@ -20,15 +21,15 @@ int operation3(int) {
int main() {
// read the configuration
- stamen::read("./bin/demo_menu.conf");
+ stamen::menu::read("./bin/demo_menu.conf");
// register free functions
- stamen::insert("finish", finish);
- stamen::insert("operation1", operation1);
- stamen::insert("operation2", operation2);
- stamen::insert("operation3", operation3);
+ stamen::menu::insert("finish", finish);
+ stamen::menu::insert("operation1", operation1);
+ stamen::menu::insert("operation2", operation2);
+ stamen::menu::insert("operation3", operation3);
// start the menu on specific panel
- stamen::dynamic("menu_main", stamen::builtin_display);
+ stamen::menu::dynamic("menu_main", stamen::builtin_display);
return 0;
}
diff --git a/include/menu.h b/include/menu.h
@@ -1,91 +1,20 @@
#ifndef STAMEN_MENU_H
#define STAMEN_MENU_H
-#include "stamen.hpp"
-
-#include <cstring>
-#include <iostream>
-#include <string>
-#include <unordered_map>
-#include <vector>
+#include "stamen.h"
+#ifdef __cplusplus
+extern "C" {
namespace stamen {
+#endif
-class Menu {
- struct private_ctor_t {};
-
- public:
- // Tag type dispatch
- Menu(private_ctor_t, const std::string &code, const std::string &prompt)
- : Menu(code, prompt) {}
-
- Menu(const Menu &) = delete;
- Menu &operator=(const Menu &) = delete;
- Menu(Menu &&) = delete;
- Menu &operator=(Menu &&) = delete;
- ~Menu() noexcept = default;
-
- static int dynamic(const std::string &code, display_f display) {
- Menu::display_stub_default = code;
- Menu::display = display;
- return display_stub(-1);
- };
-
- static void read(const std::string &s);
- static void insert(const std::string &s, callback_f callback) {
- free_lookup.emplace(s, callback);
- }
-
- const std::string &getCode() const { return code; }
- const std::string &getTitle() const { return title; }
-
- const item_t *getItemv() const { return entries.items.data(); }
- std::size_t getSize() const { return entries.items.size(); }
-
- callback_f getCallback(std::size_t idx) const;
- const std::string &getCode(std::size_t idx) const;
- const std::string &getPrompt(std::size_t idx) const;
-
- static std::unordered_map<std::string, Menu> menu_lookup;
-
- private:
- Menu(std::string code, std::string prompt)
- : code(std::move(code)), title(std::move(prompt)) {}
-
- struct entries_t {
- entries_t() = default;
- entries_t(const entries_t &) = delete;
- entries_t &operator=(const entries_t &) = delete;
- entries_t(entries_t &&) = delete;
- entries_t &operator=(entries_t &&) = delete;
- ~entries_t() noexcept {
- for (const auto [_, prompt] : items) {
- delete[] prompt;
- }
- }
-
- void insert(const std::string &code, const std::string &prompt,
- callback_f callback = display_stub);
-
- struct code_t {
- std::string code;
- std::string prompt;
- };
-
- std::vector<code_t> codes;
- std::vector<item_t> items;
- };
-
- const std::string code, title;
- entries_t entries;
-
- static int display_stub(int idx);
-
- static std::unordered_map<std::string, callback_f> free_lookup;
- static std::string display_stub_default;
- static display_f display;
-};
+void stamen_menu_read(const char *filename);
+void stamen_menu_insert(const char *code, stamen_callback_f callback);
+int stamen_menu_dynamic(const char *code, stamen_display_f display);
+#ifdef __cplusplus
} // namespace stamen
+} // extern "C"
+#endif
#endif
diff --git a/include/menu.hpp b/include/menu.hpp
@@ -0,0 +1,77 @@
+#ifndef STAMEN_MENU_HPP
+#define STAMEN_MENU_HPP
+
+#include "stamen.hpp"
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace stamen {
+namespace menu {
+
+class menu_t;
+
+extern std::unordered_map<std::string, callback_f> free_lookup;
+extern std::unordered_map<std::string, menu_t> menu_lookup;
+extern std::string display_stub_default;
+extern display_f display;
+
+void read(const char *filename);
+void insert(const char *code, callback_f callback);
+int dynamic(const char *code, display_f display);
+int display_stub(int idx);
+
+class menu_t {
+ struct private_ctor_t {};
+ friend void read(const char *filename);
+
+ public:
+ // Tag type dispatch
+ menu_t(private_ctor_t, const std::string &code, const std::string &prompt)
+ : menu_t(code, prompt) {}
+
+ ~menu_t() noexcept {
+ for (const auto [_, prompt] : items) {
+ delete[] prompt;
+ }
+ }
+
+ const std::string &getCode() const { return code; }
+ const std::string &getTitle() const { return title; }
+
+ const item_t *getItemv() const { return items.data(); }
+ std::size_t getSize() const { return items.size(); }
+
+ auto getCallback(std::size_t idx) const { return items[idx].callback; }
+ const auto &getCode(std::size_t idx) const { return codes[idx].code; }
+ const auto &getPrompt(std::size_t idx) const { return codes[idx].prompt; }
+
+ private:
+ menu_t(std::string code, std::string prompt)
+ : code(std::move(code)), title(std::move(prompt)) {}
+
+ menu_t(const menu_t &) = delete;
+ menu_t &operator=(const menu_t &) = delete;
+ menu_t(menu_t &&) = delete;
+ menu_t &operator=(menu_t &&) = delete;
+
+ void insert(const std::string &code, const std::string &prompt,
+ callback_f callback = display_stub);
+
+ struct code_t {
+ std::string code;
+ std::string prompt;
+ };
+
+ const std::string code, title;
+ std::vector<code_t> codes;
+ std::vector<item_t> items;
+};
+
+} // namespace menu
+} // namespace stamen
+
+#endif
diff --git a/include/stamen.h b/include/stamen.h
@@ -18,10 +18,6 @@ typedef int (*stamen_display_f)(const char *, const stamen_item_t[], int);
#if !defined __cplusplus || defined WITH_C_BINDINGS
-void stamen_read(const char *filename);
-void stamen_insert(const char *code, stamen_callback_f callback);
-
-int stamen_dynamic(const char *code, stamen_display_f display);
int stamen_builtin_display(const char *title, const stamen_item_t itemv[],
int size);
@@ -32,4 +28,4 @@ int stamen_builtin_display(const char *title, const stamen_item_t itemv[],
} // extern "C"
#endif
-#endif // STAMEN_STAMEN_H
+#endif
diff --git a/include/stamen.hpp b/include/stamen.hpp
@@ -9,10 +9,6 @@ using callback_f = stamen_callback_f;
using display_f = stamen_display_f;
using item_t = stamen_item_t;
-void read(const char *filename);
-void insert(const char *code, callback_f callback);
-
-int dynamic(const char *code, display_f display);
int builtin_display(const char *title, const item_t itemv[], int size);
} // namespace stamen
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -7,7 +7,7 @@ set_target_properties(stamen PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
DEBUG_POSTFIX "d"
- PUBLIC_HEADER "include/stamen.h;include/stamen.hpp"
+ PUBLIC_HEADER "include/stamen.h;include/stamen.hpp;include/menu.h;include/menu.hpp"
MACOSX_RPATH ON
WINDOWS_EXPORT_ALL_SYMBOLS ON
)
diff --git a/src/c_bindings.cpp b/src/c_bindings.cpp
@@ -1,21 +1,23 @@
-#include "stamen.h"
+#include "menu.hpp"
#include "stamen.hpp"
namespace stamen {
-void stamen_read(const char *filename) { return read(filename); }
+int stamen_builtin_display(const char *title, const stamen_item_t itemv[], int size) {
+ return builtin_display(title, itemv, size);
+}
+
+namespace menu {
+
+void stamen_menu_read(const char *filename) { return read(filename); }
-void stamen_insert(const char *code, stamen_callback_f callback) {
+void stamen_menu_insert(const char *code, stamen_callback_f callback) {
return insert(code, callback);
}
-int stamen_dynamic(const char *code, stamen_display_f display) {
+int stamen_menu_dynamic(const char *code, stamen_display_f display) {
return dynamic(code, display);
}
-int stamen_builtin_display(const char *title, const stamen_item_t itemv[],
- int size) {
- return builtin_display(title, itemv, size);
-}
-
+} // namespace menu
} // namespace stamen
diff --git a/src/generate.cpp b/src/generate.cpp
@@ -1,7 +1,7 @@
#include <args/args.hpp>
-#include "menu.h"
-#include "stamen.h"
+#include "menu.hpp"
+#include "stamen.hpp"
#include <format>
#include <fstream>
@@ -31,7 +31,7 @@ void generateInclude(std::ostream &os) {
generateIncludeHeaders(os);
- for (const auto &[code, menu] : stamen::Menu::menu_lookup) {
+ for (const auto &[code, menu] : stamen::menu::menu_lookup) {
os << std::format("int {}(int);\n", menu.getCode());
}
@@ -46,7 +46,7 @@ void generateSource(std::ostream &os) {
if (opt.cpp) os << "const stamen::item_t itemv[], int size);\n\n";
else os << "const stamen_item_t itemv[], int size);\n\n";
- for (const auto &[code, menu] : stamen::Menu::menu_lookup) {
+ for (const auto &[code, menu] : stamen::menu::menu_lookup) {
os << std::format("int {}(int) {{\n", menu.getCode());
if (opt.cpp) os << "\tstatic const stamen::item_t items[] = ";
@@ -116,7 +116,7 @@ int main(int argc, char *argv[]) {
}
const auto &config = opt.config;
- stamen::Menu::read(config);
+ stamen::menu::read(config.c_str());
std::string::size_type pos = opt.config.rfind('.');
std::string base =
diff --git a/src/menu.cpp b/src/menu.cpp
@@ -1,4 +1,4 @@
-#include "menu.h"
+#include "menu.hpp"
#include <deque>
#include <format>
@@ -9,36 +9,16 @@
#include <utility>
namespace stamen {
+namespace menu {
-std::unordered_map<std::string, Menu> Menu::menu_lookup;
-std::unordered_map<std::string, callback_f> Menu::free_lookup;
-std::string Menu::display_stub_default;
-display_f Menu::display;
+std::unordered_map<std::string, menu_t> menu_lookup;
+std::unordered_map<std::string, callback_f> free_lookup;
+std::string display_stub_default;
+display_f display;
-void Menu::entries_t::insert(const std::string &code,
- const std::string &prompt, callback_f callback) {
- char *buffer = new char[prompt.size() + 1];
- strcpy(buffer, prompt.c_str());
-
- items.emplace_back(callback, buffer);
- codes.emplace_back(code, prompt);
-}
-
-const std::string &Menu::getCode(std::size_t idx) const {
- return entries.codes[idx].code;
-}
-
-const std::string &Menu::getPrompt(std::size_t idx) const {
- return entries.codes[idx].prompt;
-}
-
-callback_f Menu::getCallback(std::size_t idx) const {
- return entries.items[idx].callback;
-}
-
-void Menu::read(const std::string &s) {
+void read(const char *filename) {
std::string line, delim, code, prompt;
- std::fstream fs(s);
+ std::fstream fs(filename);
auto last = menu_lookup.end();
while (std::getline(fs, line)) {
@@ -48,28 +28,40 @@ void Menu::read(const std::string &s) {
ss >> delim >> code >> std::ws;
std::getline(ss, prompt);
- if (delim != "+") last->second.entries.insert(code, prompt);
+ if (delim != "+") last->second.insert(code, prompt);
else {
const auto [iter, succ] = menu_lookup.emplace(
std::piecewise_construct, std::forward_as_tuple(code),
- std::forward_as_tuple(private_ctor_t{}, code, prompt));
+ std::forward_as_tuple(menu_t::private_ctor_t{}, code, prompt));
last = iter;
}
}
}
-int Menu::display_stub(int idx) {
- static std::deque<const Menu *> st;
+void insert(const char *code, callback_f callback) {
+ free_lookup.emplace(code, callback);
+}
+
+int dynamic(const char *code, display_f display) {
+ menu::display_stub_default = code;
+ menu::display = display;
+ return display_stub(-1);
+}
+
+int display_stub(int idx) {
+ static std::deque<const menu_t *> st;
const std::string &code =
!st.empty() ? st.back()->getCode(idx) : display_stub_default;
const auto ml_it = menu_lookup.find(code);
if (ml_it != menu_lookup.end()) {
- const Menu &menu = ml_it->second;
- st.push_back(&menu);
- int ret = display(menu.title.c_str(), menu.getItemv(), menu.getSize());
+ const auto &m = ml_it->second;
+
+ st.push_back(&m);
+ int ret = display(m.getTitle().c_str(), m.getItemv(), m.getSize());
st.pop_back();
+
return ret;
}
@@ -80,4 +72,14 @@ int Menu::display_stub(int idx) {
return 1;
}
+void menu_t::insert(const std::string &code, const std::string &prompt,
+ callback_f callback) {
+ char *buffer = new char[prompt.size() + 1];
+ strcpy(buffer, prompt.c_str());
+
+ items.emplace_back(callback, buffer);
+ codes.emplace_back(code, prompt);
+}
+
+} // namespace menu
} // namespace stamen
diff --git a/src/stamen.cpp b/src/stamen.cpp
@@ -9,16 +9,6 @@
namespace stamen {
-void read(const char *filename) { Menu::read(filename); }
-
-void insert(const char *code, callback_f callback) {
- Menu::insert(code, callback);
-}
-
-int dynamic(const char *code, display_f display) {
- return Menu::dynamic(code, display);
-}
-
int builtin_display(const char *title, const item_t itemv[], int size) {
const auto items = std::span(itemv, size_t(size));
const size_t dgts = size_t(std::log10(size)) + 1;