CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    [RESOLVED] Scalability issue

    Hey. I've got a class called Screen that is an abstraction of graphical elements (that can be drawn to the screen). The class calls this function in it's constructor:
    Code:
    void Screen::Load_Elements(const std::string& directory)
    {  
      std::ifstream image_file;
      IO::open_read_file(image_file, directory + IMAGES_FN);
      IO::read_data_clone<XImage, std::vector<Base_XImage*> >(elements, image_file);
      image_file.close();
    
      std::ifstream button_file;
      IO::open_read_file(button_file, directory + BUTTONS_FN);
      IO::read_data_clone<XButton, std::vector<Base_XImage*> >(elements, button_file);
      button_file.close();
    
      std::ifstream audible_button_file;
      IO::open_read_file(audible_button_file, directory + AUDIBLE_BUTTONS_FN);
      IO::read_data_clone<Audible_XButton, std::vector<Base_XImage*> >(elements, audible_button_file);
      audible_button_file.close();
    
      std::ifstream draggable_button_file;
      IO::open_read_file(draggable_button_file, directory + DRAGGABLE_BUTTONS_FN);
      IO::read_data_clone<Draggable_XButton, std::vector<Base_XImage*> >(elements, draggable_button_file);
      draggable_button_file.close();
    
      std::ifstream dialog_box_file;
      IO::open_read_file(dialog_box_file, directory + DIALOG_BOXES_FN);
      IO::read_data_clone<XDialog_Box, std::vector<Base_XImage*> >(elements, dialog_box_file);
      dialog_box_file.close();
    
      std::ifstream input_box_file;
      IO::open_read_file(input_box_file, directory + INPUT_BOXES_FN);
      IO::read_data_clone<XInput_Box, std::vector<Base_XImage*> >(elements, input_box_file);
      input_box_file.close();
    }
    This is the member that stores all the elements.
    Code:
    std::vector<Base_XImage*> elements;
    The obvious problem here is that the Load_Elements function is huge... and will only get huger each time I create a new class like Slider or something. Also, I have a folder structure that looks like this:
    Code:
                         <screen_name>
               images.txt buttons.txt    etc....
               <name x y> <name x y>   <...>
    Where screen_name is a folder and images.txt and buttons.txt are text files and <name x y> is each individual respective element to load. Doing it this way means that each time I add a new class (e.g Slider), I have to add a corresponding text file in every "Screen" folder to every project that uses Screen, even if it's empty, otherwise open_read_file throws an exception to tell me the file wasn't found! I could fix this particular issue by putting try/catch around each paragraph of code in Load_Elements, but that is just dodgy...

    I thought about something like this:
    Code:
    template<typename T>
    void Load_Elements_Of_Type(std::vector<Base_XImage*>& elements,
    const std::string& directory, const std::string& file_name)
    {
      try
      {
      std::ifstream element_file;
      open_read_file(element_file, directory + file_name);
      read_data_clone<T, std::vector<Base_XImage*> >(elements, element_file);
      element_file.close();
      }
      catch(...)
      { // Don't want to load this type.
      }
    }
    
    // Inside Load_Elements:
    Load_Elements_Of_Type<XButton>(elements, "directory/", "file.txt");
    Load_Elements_Of_Type<XSlider>(elements, "directory/", "file.txt");
    // Load every possible type.
    But I don't know what happens when T doesn't derive from Base_XImage... and it's still gonna be non-scalable.

    I really need to sort these problems out now before they get worse... Any suggestions?

    Cheers.
    Last edited by Mybowlcut; March 6th, 2008 at 10:06 AM.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

  2. #2
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    Re: Scalability issue

    This is is rather advanced, but you can use typelists and template functions to read different objects from different files.

    Code:
    #include <string>
    #include <vector>
    #include <iostream>
    
    using namespace std;
    
    // this type is used to mark the end of a typelist
    struct NullType
    {
    };
    
    // The typelist. For nested typelists type U is a typelist again, so one can
    // build typelists of any length
    template<typename T, typename U>
    struct TypeList
    {
       typedef T head; 
       typedef U tail; 
    };
    
    // convenience macros for building typelists (up to 3 types)
    #define TL1(T1)             TypeList<T1, NullType>
    #define TL2(T1,T2)        TypeList<T1, TL1( T2 ) >
    #define TL3(T1,T2,T3)   TypeList<T1, TL2( T2,T3 ) >
    
    // template function to specify the path/file for a given type. 
    template<typename T>
    string get_file_name()
    {
    	string strMessage = string( "Unregistered type " ) += typeid( T ).name();
    	cout << strMessage << endl;
    	throw exception( strMessage.c_str()  );
    }
    
    // specialized template function to specify the path/file for int types
    template<>
    string get_file_name<int>()
    {
       return "/int/data.txt";
    }
    
    // specialized template function to specify the path/file for bool types
    template<>
    string get_file_name<bool>()
    {
       return "/bool/data.txt";
    }
    
    // specialized template function to specify the path/file for short types
    template<>
    string get_file_name<short>()
    {
       return "/short/data.txt";
    }
    
    /* The load function. Its template parameter is a typelist which is traversed
     * from head to tail. A specialized template function for NullType ends the 
     * recursion.
    */
    template<typename TypeList>
    void load_files( const string& strBasePath, vector<Base*>& Elements )
    {
       // load typelist´s head object type
       load_objects<TypeList::head>( strBasePath, Elements );
    
       // proceed to next type 
       load_files<TypeList::tail>( strBasePath, Elements );
    }
    
    // Specialized template function to end typelist traversion
    template<>
    void load_files<NullType>( const string& strBasePath, vector<Base*>& Elements )
    {
       // used to end recursion
       cout << "Typelist end" << endl;
    }
    
    // The loader function itself. It uses specialized template functions to
    // obtain additional path information, based on the object type to load.
    template<typename Type>
    void load_objects( const string& strBasePath, vector<Base*>& Elements )
    {
       // concatenate path    
       string strPath = strBasePath + get_file_name<Type>();
       cout << "Loading objects of type " << typeid( Type ).name() << " from file " << strPath << endl;
    }
    
    // define a typelist of desired types. This one consists of  
    // int, bool, short, and NullType (implicitely created by the TL1 macro)
    #define ObjectTypes TL3( int,bool,short )
    
    int main()
    {
       vector<Base*> Elements;
    
       // load all typelist´s object types from c:/base
       load_files<ObjectTypes>( "c:/base", Elements );
    }
    Last edited by GNiewerth; March 6th, 2008 at 11:09 AM.
    - Guido

  3. #3
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    Re: Scalability issue

    Quote Originally Posted by GNiewerth
    This is is rather advanced
    That would be an understatement and a half!

    Before I start asking questions (you knew it was bound to happen ), could I just have one get_file_name function that returns the typeid's name concatenated with ".txt"? I'd have to change a few files around but it would make it a lot neater. I'd never thought to use/never used typeid so that's why I haven't done it already haha. This works:
    Code:
     template<typename T>
        string Get_Element_File_Name()
        {
            return Remove_Class_Prefix(string(typeid(T).name()) + "s.txt");
        }
    
    string Screen::Remove_Class_Prefix(std::string s)
    {
        const int PREFIX_LENGTH = 6;
        if(s.size() <= PREFIX_LENGTH)
        { // Too small.
            throw runtime_error("Missing class prefix in Remove_Class_Prefix: " + s);
        }
    
        s.erase(s.begin(), s.begin() + 6);
        return s;
    }
    Ok... first of all the TypeList struct... all it has are two typedefs, right? And the extent of my C++ knowledge tells me that typedefs aren't variable declarations, just a way to rename a type? So how does TypeList store anything in it? That's the part that I really don't understand.

    The next thing:
    Code:
    // load typelist´s head object type
       load_objects<TypeList::head>( strBasePath, Elements );
    I get that this is recursive...(Very clever way to end the recursion, btw!)
    Code:
    // proceed to next type 
       load_files<TypeList::tail>( strBasePath, Elements );
    But I still don't get how it works due to the fact that I don't understand the TypeList part..

    Cheers.

    Edit: Btw, your suggestion works perfectly! Only a very minimal amount of code needed to be changed as well... I never use this word but... marvelous! Haha.
    Last edited by Mybowlcut; March 6th, 2008 at 11:09 PM.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

  4. #4
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    Re: Scalability issue

    Typelists carry type information only, they don´t have a value. They´re like a collection of types.

    Let´s have a look at this simple typelist:

    Code:
    #define Types TL2( int,bool)
    This macro expands to TypeList<int, TypeList<bool, NullType> > and defines the following type:

    Code:
    Types
       +-- head             // int type
       +-- tail                // a typelist again
              +-- head      // bool type
              +-- NullType // termination type created by TL1
    Given this type you can recursively walk the hierachy by using template functions. You need one generic template function for "real" types stored in the typelist and one specialized template function for handling the NullType (that means you have reached the end of the typelist).

    Code:
    template<typename TypeList>
    void load_files( const string& strBasePath, vector<Base*>& Elements )
    {
       // load typelist´s head object type
       load_objects<TypeList::head>( strBasePath, Elements );
    
       // proceed to next type 
       load_files<TypeList::tail>( strBasePath, Elements );
    }
    This is the call stack for the load_files function:
    Code:
    load_files<TypeList<int, TypeList<bool, NullType> > >(...)
       - load_objects<int>(...) // TypeList::head is an int
       - load_files<TypeList<bool,NullType> >(...) // TypeList::tail is a typelist
          - load_objects<bool>(...) // TypeList::head is a bool
          - load_files<NullType>(...) // TypeList::tail is a NullType
    Hope this helped a bit, feel free to ask if you have more questions.
    Last edited by GNiewerth; March 7th, 2008 at 04:22 AM.
    - Guido

  5. #5
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    Re: Scalability issue

    Quote Originally Posted by GNiewerth
    Typelists carry type information only, they don´t have a value. They´re like a collection of types.
    Surprisingly enough I understood the recursion part haha. Thanks for the explanation of that though I understand it now... it's a very strange concept. Does it get used in commercial code often?

    Cheers.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

  6. #6
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    Re: Scalability issue

    To be honest: I was quite puzzled after reading the typelist chapter in Modern C++ Design and wondered if it has any real world purpose. It took me about one year to find a reasonable use for it, and it was only because the framework I used had some very strange restrictions.
    Your Load_Elements_Of_Type function does nearly the same, without being that complex and difficult to understand. In my opinion it makes no practical difference if you add a new Load_Elements_Of_Type function call or append a new type to an existing type list. The first approach requires one new line of code, the latter one word only. I was probably too excited about typelists
    However, it´s always interesting to toy around with the language and discover new ways of using it.
    - Guido

  7. #7
    Join Date
    Nov 2006
    Location
    Australia
    Posts
    1,569

    Re: Scalability issue

    Quote Originally Posted by GNiewerth
    To be honest: I was quite puzzled after reading the typelist chapter in Modern C++ Design and wondered if it has any real world purpose. It took me about one year to find a reasonable use for it, and it was only because the framework I used had some very strange restrictions.
    Your Load_Elements_Of_Type function does nearly the same, without being that complex and difficult to understand. In my opinion it makes no practical difference if you add a new Load_Elements_Of_Type function call or append a new type to an existing type list. The first approach requires one new line of code, the latter one word only. I was probably too excited about typelists
    However, it´s always interesting to toy around with the language and discover new ways of using it.
    Ahhh I see...

    Well I prefer your idea since it's just cool! One word does beat one line! Haha.

    Thanks again.
    Good judgment is gained from experience. Experience is gained from bad judgment.
    Cosy Little Game | SDL | GM script | VLD | Syntax Hlt | Can you help me with my homework assignment?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured