From 74930f86b3845423def4f61375adfc29f5a68a30 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 31 May 2005 19:05:55 +0000 Subject: [PATCH] Adding framework for an option parser. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@448 e378c898-3ddf-0310-93e7-cc216c733640 --- Makefile.am | 3 +- TODO | 7 ++-- configure.ac | 4 +- src/Makefile.am | 4 ++ src/core/Makefile.am | 1 + src/core/download_slot_map.h | 52 ++++++++++++++++++++++++ src/core/manager.cc | 3 ++ src/core/manager.h | 5 +++ src/main.cc | 75 ++++++++++++++++++----------------- src/option_handler.cc | 73 ++++++++++++++++++++++++++++++++++ src/option_handler.h | 65 ++++++++++++++++++++++++++++++ src/option_handler_rules.cc | 44 +++++++++++++++++++++ src/option_handler_rules.h | 48 +++++++++++++++++++++++ src/option_parser.cc | 76 ++++++++++++++++++++++++------------ src/option_parser.h | 40 ++++++++++--------- 15 files changed, 415 insertions(+), 85 deletions(-) create mode 100644 src/core/download_slot_map.h create mode 100644 src/option_handler.cc create mode 100644 src/option_handler.h create mode 100644 src/option_handler_rules.cc create mode 100644 src/option_handler_rules.h diff --git a/Makefile.am b/Makefile.am index f16791e1..4d2ccdeb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,4 +5,5 @@ EXTRA_DIST= \ doc/rtorrent.1.txt \ rak/algorithm.h \ rak/functional.h \ - scripts/checks.m4 + scripts/checks.m4 \ + scripts/common.m4 diff --git a/TODO b/TODO index 452c9b04..69075137 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,3 @@ -core::Manager::stop() should make sure ongoing hash checks get cleaned -up. - Polling during last phase of shutdown should be very quick, don't use normal timeout. @@ -34,4 +31,6 @@ Show torrent creation date? Recheck hash key. -BUG: Doesn't show the last file in the file list. +Seperate download management from core::management. + +Allow switching/cycling of tracker. \ No newline at end of file diff --git a/configure.ac b/configure.ac index d38bd745..2a771d78 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(rtorrent, 0.2.3, jaris@ifi.uio.no) +AC_INIT(rtorrent, 0.2.4, jaris@ifi.uio.no) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -20,7 +20,7 @@ TORRENT_CHECK_EXECINFO() TORRENT_CHECK_CURL() TORRENT_OTFD() -PKG_CHECK_MODULES(STUFF, sigc++-2.0 libtorrent >= 0.6.3, +PKG_CHECK_MODULES(STUFF, sigc++-2.0 libtorrent >= 0.6.4, CXXFLAGS="$CXXFLAGS $STUFF_CFLAGS $CURL_CFLAGS"; LIBS="$LIBS $STUFF_LIBS $CURL_LIBS") diff --git a/src/Makefile.am b/src/Makefile.am index 49848088..1db80528 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,10 @@ rtorrent_LDADD = \ rtorrent_SOURCES = \ main.cc \ + option_handler.cc \ + option_handler.h \ + option_handler_rules.cc \ + option_handler_rules.h \ option_parser.cc \ option_parser.h \ signal_handler.cc \ diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 9a6f56da..4be0ad71 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -9,6 +9,7 @@ libsub_core_a_SOURCES = \ download.h \ download_list.cc \ download_list.h \ + download_slot_map.h \ download_store.cc \ download_store.h \ hash_queue.cc \ diff --git a/src/core/download_slot_map.h b/src/core/download_slot_map.h new file mode 100644 index 00000000..bff2c9e1 --- /dev/null +++ b/src/core/download_slot_map.h @@ -0,0 +1,52 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H +#define RTORRENT_CORE_DOWNLOAD_SLOT_MAP_H + +#include +#include +#include + +#include "download.h" + +namespace core { + +class DownloadSlotMap : public std::map > { +public: + typedef sigc::slot1 SlotDownload; + typedef std::map Base; + + void insert(const std::string& key, SlotDownload s) { Base::operator[](key) = s; } + + void for_each(Download* d); +}; + +inline void +DownloadSlotMap::for_each(Download* d) { + for (iterator itr = begin(), last = end(); itr != last; ++itr) + itr->second(d); +} + +} + +#endif diff --git a/src/core/manager.cc b/src/core/manager.cc index 8176b798..f89ba489 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -180,6 +180,7 @@ Manager::create_final(std::istream* s) { void Manager::setup_download(Download* d) { + // These should be in m_defaultSettings. d->get_download().set_ip(m_dns); if (!m_defaultRoot.empty()) @@ -188,6 +189,8 @@ Manager::setup_download(Download* d) { d->get_download().get_name() : "")); + m_defaultSettings.for_each(d); + if (m_debugTracker >= 0) d->get_download().signal_tracker_dump(sigc::mem_fun(*this, &Manager::receive_debug_tracker)); diff --git a/src/core/manager.h b/src/core/manager.h index 76426582..6b025665 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -26,6 +26,7 @@ #include #include "download_list.h" +#include "download_slot_map.h" #include "download_store.h" #include "hash_queue.h" #include "http_queue.h" @@ -51,6 +52,8 @@ public: HashQueue& get_hash_queue() { return m_hashQueue; } HttpQueue& get_http_queue() { return m_httpQueue; } + DownloadSlotMap& get_default_settings() { return m_defaultSettings; } + Poll& get_poll() { return m_poll; } Log& get_log_important() { return m_logImportant; } Log& get_log_complete() { return m_logComplete; } @@ -91,6 +94,8 @@ private: HashQueue m_hashQueue; HttpQueue m_httpQueue; + DownloadSlotMap m_defaultSettings; + Poll m_poll; Log m_logImportant; Log m_logComplete; diff --git a/src/main.cc b/src/main.cc index 2dce8ebe..c2a58de4 100644 --- a/src/main.cc +++ b/src/main.cc @@ -48,6 +48,8 @@ #include "utils/task_schedule.h" #include "signal_handler.h" +#include "option_handler.h" +#include "option_handler_rules.h" #include "option_parser.h" int64_t utils::Timer::m_cache; @@ -89,19 +91,19 @@ do_shutdown(ui::Control* c) { } int -parse_options(ui::Control* c, int argc, char** argv) { +parse_options(ui::Control* c, OptionHandler* optionHandler, int argc, char** argv) { OptionParser optionParser; + optionParser.insert_flag('h', sigc::ptr_fun(&print_help)); + optionParser.insert_flag('t', sigc::mem_fun(c->get_core(), &core::Manager::debug_tracker)); optionParser.insert_option('b', sigc::mem_fun(c->get_core(), &core::Manager::set_listen_ip)); optionParser.insert_option('d', sigc::mem_fun(c->get_core(), &core::Manager::set_default_root)); optionParser.insert_option('i', sigc::mem_fun(c->get_core(), &core::Manager::set_dns)); - - optionParser.insert_option('p', sigc::bind(sigc::ptr_fun(OptionParser::call_int_pair), - sigc::mem_fun(c->get_core(), &core::Manager::set_port_range))); optionParser.insert_option('s', sigc::mem_fun(c->get_core().get_download_store(), &core::DownloadStore::activate)); - optionParser.insert_flag('t', sigc::mem_fun(c->get_core(), &core::Manager::debug_tracker)); + optionParser.insert_int_pair('p', sigc::mem_fun(c->get_core(), &core::Manager::set_port_range)); + optionParser.insert_option_list('o', sigc::mem_fun(*optionHandler, &OptionHandler::process)); return optionParser.process(argc, argv); } @@ -135,52 +137,57 @@ initialize_core(ui::Control* c) { int main(int argc, char** argv) { - ui::Control uiControl; - ui::Root uiRoot(&uiControl); + OptionHandler optionHandler; + ui::Control uiControl; + ui::Root uiRoot(&uiControl); utils::Timer::update(); srandom(utils::Timer::cache().usec()); srand48(utils::Timer::cache().usec()); + optionHandler.insert("min_peers", new OptionHandlerDownloadMinPeers(&uiControl.get_core().get_default_settings())); + try { - SignalHandler::set_ignore(SIGPIPE); - SignalHandler::set_handler(SIGINT, sigc::bind(sigc::mem_fun(uiRoot, &ui::Root::set_shutdown_received), true)); - SignalHandler::set_handler(SIGSEGV, sigc::bind(sigc::ptr_fun(&do_panic), SIGSEGV)); - SignalHandler::set_handler(SIGBUS, sigc::bind(sigc::ptr_fun(&do_panic), SIGBUS)); + SignalHandler::set_ignore(SIGPIPE); + SignalHandler::set_handler(SIGINT, sigc::bind(sigc::mem_fun(uiRoot, &ui::Root::set_shutdown_received), true)); + SignalHandler::set_handler(SIGSEGV, sigc::bind(sigc::ptr_fun(&do_panic), SIGSEGV)); + SignalHandler::set_handler(SIGBUS, sigc::bind(sigc::ptr_fun(&do_panic), SIGBUS)); - int firstArg = parse_options(&uiControl, argc, argv); + int firstArg = parse_options(&uiControl, &optionHandler, argc, argv); - initialize_display(&uiControl); - initialize_core(&uiControl); + initialize_display(&uiControl); + initialize_core(&uiControl); - uiRoot.init(); + uiRoot.init(); - load_session_torrents(&uiControl); - load_arg_torrents(&uiControl, argv + firstArg, argv + argc); + load_session_torrents(&uiControl); + load_arg_torrents(&uiControl, argv + firstArg, argv + argc); - uiControl.get_display().adjust_layout(); + uiControl.get_display().adjust_layout(); - while (!is_shutting_down || !torrent::get(torrent::SHUTDOWN_DONE)) { + while (!is_shutting_down || !torrent::get(torrent::SHUTDOWN_DONE)) { - if (uiRoot.get_shutdown_received()) { - do_shutdown(&uiControl); - uiRoot.set_shutdown_received(false); + if (uiRoot.get_shutdown_received()) { + do_shutdown(&uiControl); + uiRoot.set_shutdown_received(false); + } + + utils::Timer::update(); + utils::TaskSchedule::perform(utils::Timer::cache()); + + // This needs to be called every second or so. Currently done by + // the throttle task in libtorrent. + uiControl.get_display().do_update(); + + uiControl.get_core().get_poll().poll(utils::TaskSchedule::get_timeout()); } - utils::Timer::update(); - utils::TaskSchedule::perform(utils::Timer::cache()); - - // This needs to be called every second or so. Currently done by - // the throttle task in libtorrent. - uiControl.get_display().do_update(); + uiRoot.cleanup(); + display::Canvas::cleanup(); - uiControl.get_core().get_poll().poll(utils::TaskSchedule::get_timeout()); - } - - uiRoot.cleanup(); - display::Canvas::cleanup(); + uiControl.get_core().cleanup(); } catch (std::exception& e) { display::Canvas::cleanup(); @@ -189,8 +196,6 @@ main(int argc, char** argv) { return -1; } - uiControl.get_core().cleanup(); - return 0; } diff --git a/src/option_handler.cc b/src/option_handler.cc new file mode 100644 index 00000000..48642533 --- /dev/null +++ b/src/option_handler.cc @@ -0,0 +1,73 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include + +#include "option_handler.h" + +OptionHandlerBase::~OptionHandlerBase() { +} + +void +OptionHandler::insert(const std::string& key, OptionHandlerBase* opt) { + iterator itr = find(key); + + if (itr == end()) { + Base::insert(value_type(key, opt)); + } else { + delete itr->second; + itr->second = opt; + } +} + +void +OptionHandler::erase(const std::string& key) { + iterator itr = find(key); + + if (itr == end()) + return; + + delete itr->second; + Base::erase(itr); +} + +void +OptionHandler::clear() { + for (iterator itr = begin(), last = end(); itr != last; ++itr) + delete itr->second; + + Base::clear(); +} + +void +OptionHandler::process(const std::string& key, const std::string& arg) const { + const_iterator itr = find(key); + + if (itr == end()) + throw std::runtime_error("Could not find option key matching \"" + key + "\""); + + itr->second->process(key, arg); +} diff --git a/src/option_handler.h b/src/option_handler.h new file mode 100644 index 00000000..d5853a37 --- /dev/null +++ b/src/option_handler.h @@ -0,0 +1,65 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_OPTION_HANDLER_H +#define RTORRENT_OPTION_HANDLER_H + +#include +#include + +struct OptionHandlerBase { + virtual ~OptionHandlerBase(); + + virtual void process(const std::string& key, const std::string& arg) = 0; +}; + +class OptionHandler : private std::map { +public: + typedef std::map Base; + typedef Base::value_type value_type; + typedef Base::size_type size_type; + + typedef Base::iterator iterator; + typedef Base::reverse_iterator reverse_iterator; + typedef Base::const_iterator const_iterator; + typedef Base::const_reverse_iterator const_reverse_iterator; + + using Base::empty; + using Base::size; + + using Base::begin; + using Base::end; + using Base::rbegin; + using Base::rend; + + using Base::find; + + // We take over ownership of opt. + void insert(const std::string& key, OptionHandlerBase* opt); + void erase(const std::string& key); + + void clear(); + + void process(const std::string& key, const std::string& arg) const; +}; + +#endif diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc new file mode 100644 index 00000000..38196c25 --- /dev/null +++ b/src/option_handler_rules.cc @@ -0,0 +1,44 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include + +#include "option_handler_rules.h" + +OptionHandlerDownloadMinPeers::~OptionHandlerDownloadMinPeers() { +} + +void +OptionHandlerDownloadMinPeers::process(const std::string& key, const std::string& arg) { + int a; + + if (std::sscanf(arg.c_str(), "%i", &a) != 1 || + a <= 0 || + a >= (1 << 16)) + throw std::runtime_error("Invalid argument for min peers \"" + arg + "\""); + + (*m_map)[key] = sigc::bind(sigc::ptr_fun(&OptionHandlerDownloadMinPeers::apply), a); +} diff --git a/src/option_handler_rules.h b/src/option_handler_rules.h new file mode 100644 index 00000000..772e7cc7 --- /dev/null +++ b/src/option_handler_rules.h @@ -0,0 +1,48 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_OPTION_HANDLER_RULES_H +#define RTORRENT_OPTION_HANDLER_RULES_H + +#include "core/download_slot_map.h" + +#include "option_handler.h" + +class OptionHandlerDownloadMinPeers : public OptionHandlerBase { +public: + OptionHandlerDownloadMinPeers(core::DownloadSlotMap* m) : m_map(m) {} + ~OptionHandlerDownloadMinPeers(); + + virtual void process(const std::string& key, const std::string& arg); + +private: + // Move these somewhere else? A seperate file with lots of different + // setting appliers. Those would perform the nessesary checks + // themselves. + static void apply(core::Download* d, int arg) { + d->get_download().set_peers_min(arg); + } + + core::DownloadSlotMap* m_map; +}; + +#endif diff --git a/src/option_parser.cc b/src/option_parser.cc index dfdb619f..44604233 100644 --- a/src/option_parser.cc +++ b/src/option_parser.cc @@ -23,25 +23,37 @@ #include "config.h" #include -#include #include #include +#include #include #include "option_parser.h" void -OptionParser::insert_flag(char c, SlotFlag s) { +OptionParser::insert_flag(char c, Slot s) { m_container[c].m_slot = sigc::hide(s); m_container[c].m_useOption = false; } void -OptionParser::insert_option(char c, SlotOption s) { +OptionParser::insert_option(char c, SlotString s) { m_container[c].m_slot = s; m_container[c].m_useOption = true; } +void +OptionParser::insert_option_list(char c, SlotStringPair s) { + m_container[c].m_slot = sigc::bind<0>(sigc::ptr_fun(&OptionParser::call_option_list), s); + m_container[c].m_useOption = true; +} + +void +OptionParser::insert_int_pair(char c, SlotIntPair s) { + m_container[c].m_slot = sigc::bind<0>(sigc::ptr_fun(&OptionParser::call_int_pair), s); + m_container[c].m_useOption = true; +} + int OptionParser::process(int argc, char** argv) { int c; @@ -49,31 +61,15 @@ OptionParser::process(int argc, char** argv) { opterr = 0; - while ((c = getopt(argc, argv, optString.c_str())) != -1) { - if (c == '?') { - std::stringstream s; - s << "Invalid use of option flag -" << (char)optopt << ". Try rtorrent -h for more information."; - - throw std::runtime_error(s.str()); - - } else { - call_flag(c, optarg ? optarg : ""); - } - } + while ((c = getopt(argc, argv, optString.c_str())) != -1) + if (c == '?') + throw std::runtime_error("Invalid/unknown option flag \"-" + std::string(1, (char)optopt) + "\". See rtorrent -h for more information."); + else + call(c, optarg ? optarg : ""); return optind; } -void -OptionParser::call_int_pair(const std::string& str, SlotIntPair slot) { - int a, b; - - if (sscanf(str.c_str(), "%u-%u", &a, &b) != 2) - throw std::runtime_error("Invalid argument \"" + str + "\" should be "); - - slot(a, b); -} - std::string OptionParser::create_optstring() { std::string s; @@ -89,7 +85,7 @@ OptionParser::create_optstring() { } void -OptionParser::call_flag(char c, const std::string& arg) { +OptionParser::call(char c, const std::string& arg) { Container::iterator itr = m_container.find(c); if (itr == m_container.end()) @@ -97,3 +93,33 @@ OptionParser::call_flag(char c, const std::string& arg) { itr->second.m_slot(arg); } + +void +OptionParser::call_option_list(SlotStringPair slot, const std::string& arg) { + std::string::const_iterator itr = arg.begin(); + + while (itr != arg.end()) { + std::string::const_iterator last = std::find(itr, arg.end(), ','); + std::string::const_iterator opt = std::find(itr, last, '='); + + if (opt == itr || opt == last) + throw std::logic_error("Invalid argument, \"" + arg + "\" should be \"key1=opt1,key2=opt2,...\""); + + slot(std::string(itr, opt), std::string(opt + 1, last)); + + if (last == arg.end()) + break; + + itr = ++last; + } +} + +void +OptionParser::call_int_pair(SlotIntPair slot, const std::string& arg) { + int a, b; + + if (std::sscanf(arg.c_str(), "%u-%u", &a, &b) != 2) + throw std::runtime_error("Invalid argument, \"" + arg + "\" should be \"a-b\""); + + slot(a, b); +} diff --git a/src/option_parser.h b/src/option_parser.h index 012a78ad..8d7b5e72 100644 --- a/src/option_parser.h +++ b/src/option_parser.h @@ -31,31 +31,35 @@ class OptionParser { public: - typedef sigc::slot0 SlotFlag; - typedef sigc::slot1 SlotOption; - typedef sigc::slot2 SlotIntPair; + typedef sigc::slot0 Slot; + typedef sigc::slot1 SlotString; + typedef sigc::slot2 SlotStringPair; + typedef sigc::slot2 SlotIntPair; - struct Node { - SlotOption m_slot; - bool m_useOption; - }; - - typedef std::map Container; - - void insert_flag(char c, SlotFlag s); - void insert_option(char c, SlotOption s); + void insert_flag(char c, Slot s); + void insert_option(char c, SlotString s); + void insert_option_list(char c, SlotStringPair s); + void insert_int_pair(char c, SlotIntPair s); // Returns the index of the first non-option argument. - int process(int argc, char** argv); - - static void call_int_pair(const std::string& str, SlotIntPair slot); + int process(int argc, char** argv); private: - std::string create_optstring(); + std::string create_optstring(); - void call_flag(char c, const std::string& arg); + void call(char c, const std::string& arg); + static void call_option_list(SlotStringPair slot, const std::string& arg); + static void call_int_pair(SlotIntPair slot, const std::string& arg); - Container m_container; + // Use pair instead? + struct Node { + SlotString m_slot; + bool m_useOption; + }; + + typedef std::map Container; + + Container m_container; }; #endif