Datenstruktur für ein Menu



  • Hi,

    in welcher Datenstruktur würdet ihr ein Menu ablegen?



  • Ich hab mal eins gebaut, weils mir aufn senkel ging, immer wieder das gleiche tippen zu müssen - und weil ich msvc eh gerad auf hab:

    #ifndef H_MY_MENU_20100406012317
    #define H_MY_MENU_20100406012317
    
    #include <cassert>
    #include <iomanip>
    #include <iostream>
    #include <sstream>
    #include <utility>
    #include <vector>
    
    #include <boost/function.hpp>
    #include <boost/shared_ptr.hpp>
    
    namespace my
    {
    	namespace detail
    	{
    		unsigned count_digits(unsigned int value)
    		{
    			if(value > 1000000000)  return 10;
    			if(value > 100000000)   return 9;
    			if(value > 10000000)    return 8;
    			if(value > 1000000)     return 7;
    			if(value > 100000)      return 6;
    			if(value > 10000)       return 5;
    			if(value > 1000)        return 4;
    			if(value > 100)         return 3;
    			if(value > 10)          return 2;
    			return 1;
    		}
    	}
    
    	struct menu
    	{
    		struct function_t
    		{
    			function_t()
    			{}
    			function_t(boost::function0<void> to_call)
    			: to_call(new boost::function0<void>(to_call))
    			{}
    
    			void operator() () const
    			{
    				assert(to_call && "cannot dereference a nullptr");
    				boost::function0<void>& x = *to_call;
    				x();
    			}
    			friend bool operator== (function_t lhs, function_t rhs)
    			{
    				return lhs.to_call == rhs.to_call;
    			}
    		private:
    			boost::shared_ptr< boost::function0<void> > to_call;
    		};
    
    		typedef std::string text_t;
    		typedef std::pair<text_t, function_t> pair_t;
    		typedef std::vector<pair_t> container_t;
    		typedef container_t::size_type size_t;
    
    		void add(const text_t& title, function_t function)
    		{
    			items.push_back( pair_t(title, function) );
    		}
    		void skip_nr()
    		{
    			items.push_back( pair_t() );
    		}
    		void skip_till(size_t next_number)
    		{
    			while(items.size() < next_number-1)
    			{
    				skip_nr();
    			};
    		}
    
    		void print(std::ostream& stream) const
    		{
    			const size_t size = items.size();
    			const unsigned length = detail::count_digits(size);
    
    			size_t nr = 1;
    			bool skipped_last = false;
    			for(container_t::const_iterator i(items.begin()), e(items.end()); i != e; ++i, ++nr)
    			{
    				if(!i->first.empty())
    				{
    					stream << '[' << std::setw( static_cast<std::streamsize>(length) ) << nr << ']'
    						<< '\t' << i->first;
    					skipped_last = false;
    				}
    				if(!skipped_last)
    				{
    					stream << std::endl;
    					skipped_last = true;
    				}
    			}
    
    			stream << std::endl;
    		}
    
    		function_t operator() (std::istream& in, std::ostream& out)
    		{
    			for(;;)
    			{
    				size_t nr;
    				in >> nr;
    				--nr;
    
    				if(nr < items.size())
    				{
    					pair_t& choice = items[nr];
    					if(!choice.first.empty())
    						return choice.second;
    				}
    				out << "wrong number - again" << std::endl;
    
    				std::string rubbish;
    				std::getline(in, rubbish);
    				in.clear();
    			}
    		}
    
    	private:
    		container_t items;
    	};
    
    }
    
    #endif //#ifndef H_MY_MENU_20100406012317
    

    benutzung:

    my::menu::function_t put_in_store        = boost::bind(hwp::source::features::put_in_store, the_user, &store_house, boost::ref(logger));
    		my::menu::function_t remove_from_store   = boost::bind(hwp::source::features::remove_from_store, the_user, &store_house, boost::ref(logger));
    		my::menu::function_t save_to_db          = boost::bind(hwp::source::features::save_to_db, the_user, &store_house, boost::ref(logger));
    		my::menu::function_t show_store_house    = boost::bind(hwp::source::features::show_store_house, the_user, &store_house, boost::ref(logger));
    		my::menu::function_t show_single_storing = boost::bind(hwp::source::features::show_single_storing, the_user, &store_house, boost::ref(logger));
    		my::menu::function_t add_user            = boost::bind(hwp::source::features::add_user, the_user, boost::ref(std::cin), boost::ref(std::cout), boost::ref(logger));
    		my::menu::function_t abort               = boost::bind(hwp::source::features::abort, the_user, boost::ref(logger));
    
    		my::menu menu;
    		menu.add("Waren einlagern", put_in_store);
    		menu.add("Waren auslagern", remove_from_store);
    		menu.add("Speichern des Lagerzustands", save_to_db);
    		menu.skip_till(5);
    		menu.add("Etwas ueber einen bestimmten Lagerplatz erfahren", show_store_house);
    		menu.add("Einlager-Priorität eines Produktes herausfinden", show_single_storing);
    		menu.skip_till(7);
    		if(the_user->is_admin())
    			menu.add("Nutzer hinzufügen", add_user);
    		menu.skip_till(9);
    		menu.add("Beenden", abort);
    
    		menu.print(std::cout);
    		my::menu::function_t to_do = menu(std::cin, std::cout);
    		to_do();
    
    		if(to_do == abort) /*beenden, vll noch mal speichern etc.*/
     /*...*/
    

    bb



  • vielen lieben dank, da habe ich erstmal was zu verdauen. witzig, ich habe auch gerade vc auf und probiere mit vectoren rum 🙂



  • Schau dir mal das Composite Design Pattern an. Die verwendete Datenstruktur ist ein Implementierungsdetail, das hängt von weiteren Anforderungen (welche Operationen wie oft benötigt, Validität der Iteratoren, Performance) ab.


Anmelden zum Antworten