The Middleware Writer takes two kinds of input and writes C++
    code which can be used as part of a distributed application.

    Input:

    The two kinds of input are C++ include files and "Middle"
    files.  A Middle file is required as input; include files 
    are optional.  The Middle language is something we made up 
    and is used to specify what gets written and how.  Here is 
    an example of Middle code:

    MessageManager
       (vector<vector<double> >, map<string, double>)
       (list<Account>, string [10]) 
       //(vector<Account>, string [10]) 
    }

    The name you give, in this case, MessageManager, is used as the 
    name of the generated class.  
     
    After the name, you specify one or more lines as needed.  The 
    program will write one or two methods based on each line.  The 
    lines have the following general form:

     (T1 [@AS @HI], T2 [@AS @HI], .... Tn [@AS @HI]) [@OUT @IN @MSGID.*]
    
    Each line begins with a left paren.  T1 through Tn are types and 
    should follow C++ syntax.  The braces indicate that what is 
    contained in them is optional.  Here are some more examples:                       
    MessageManager
       (double, string)
       (long, long)
    } 

    This will produce a class called MessageManager.  Methods called  
    Send and Receive are written.  The method prototypes would be:

      int Send(Buffer*, const double, const string&);
      int Receive(Buffer*, double&, string&);

      int Send(Buffer*, const long, const long);
      int Receive(Buffer*, long&, long&);
 

    If instead you wrote:

    MessageManager
       (double, string) @OUT
       (long, long)  @OUT
    } 

    only the Send methods will be written.  By default both Send and
    Receive methods are written.  If you only want one of them, use @IN
    or @OUT to tailor the output.

    
    Sometimes one only needs to send a subset of a container.  The
    adaptive send option, @AS, is helpful in such circumstances.  
    This option is only applicable with container classes and makes 
    the most sense with a container that is sorted:

    Message
       (set<string> @AS, double) 
    }


    In this example, the generated Send function would take a 
    set<string>::const_iterator and an integer count of how many 
    items to send.  This is handy because it helps to avoid copying 
    a subset of the set into another container and then passing that 
    object to the generated code.  @AS may only be used at the top 
    most level.  In other words, this won't work:

    Message
       (vector<set<int> @AS >)
    }

The @HI option stands for hinted insert. The sorted container classes: (multi)set, (multi)map and rb_tree have insert functions that take a hint. If you specify @HI, the generated code will use the insert function that takes a hint. This option can be easily misused. There are several things to consider:

  1. The data that is being received must be in the same order that the container will place it.
  2. The container used in the Receive call should be empty or almost empty.
  3. The container used in the Receive call should use the less<> function object. So don't do this:
             Message
               (set<int, greater<int> > @HI)
             }
    
The code that needs to be executed is slightly different between less<> and greater<>, and we don't support greater<>. Here is a valid example:
    MsgManager
       (set<int> @AS @HI)
    }
And another:
    MsgManager
       (set<int, greater<int> >)  
    }

    It is ok to use greater<> with containers, but you can't mix it
    with @HI.  For the time being @HI is only supported at the 
    top most level.  So this won't work:
     
    Nope
       (vector<set<int> @HI >)
    }

This option is strictly performance related. The tests we've done indicate using the hinted insert function cuts the elapsed time by 50%. (Those tests aren't comparing two versions of Receive(). They just time how long it takes to insert into a container with and without hinted insert.)

The options have to be in upper case. // or /* ... */ comments are acceptable in Middle code. A lone } is used to indicate the end of the construct.

The other kind of input is C++ include files. There are some restrictions in this area. We don't support:

   We accept namespace definitions, but we don't organize types with 
   respect to namespaces.  If you have two types with the same name 
   in different namespaces, we will flag that as an error.   Template
   support is coming along, but isn't finished.  We don't support
   template template arguments at this time.
    

   Here is an example of an include file that is acceptable to 
   the program:

    #ifndef MENU
    #define MENU

    #include <string>
    #include <vector>
    #include <iostream>

    class Buffer;

    namespace llama {

    struct Base
    {
      Base() {}
      int Send(Buffer*, int = 0) const;    // These prototypes have to 
      int Receive(Buffer*);                // be added to your code.

      std::vector<std::string> baseFileNames;
    };

    short const INSERT = 301;
    short const DELETE = 302;

    class Derived : public Base
    {
     public:
      Derived() {}
      int Send(Buffer*, int = 0) const;  
      int Receive(Buffer*);              
  
     private:
      short op[12];
      unsigned int offset;
    };

   
    class FileInfo
    {
     public:
      FileInfo() 
      {}  
      
      ~FileInfo()
      {}
      
      friend struct FWKey;
      int Send(Buffer*, int = 0) const;
      int Receive(Buffer*);
      void Reset();
  
     private:
    #ifdef  SERVER_SIDE
      short isnew;
      long modTime;
    #endif

      std::string introducedFileName;
      Derived  parts;
    };


    struct FWKey
    {
      const std::string& operator() (const FileInfo* inst)
      {
        return inst->introducedFileName;
      }
    };

    }
    #endif

 

    Given the above definitions we can write Middle code that uses
    the types:

    Messages
       (rb_tree<FileInfo*, string, FWKey>) 
       (vector<Base*>, short)
    }

Don't let the rb_tree throw you. We prefer using the red-black tree that underpins map<> to map<>. And so the program is able to work with it. Note that the Value precedes the Key argument.

There is one option that is invoked from include files. The #ifdef SERVER_SIDE line above is interpreted by the generator in a special way. This option requires some explaining.

Output:

A C++ class definition is returned as text on the screen.

Setup Instructions:

  1. Modification to user defined types.
           Two function prototypes have to be added to types that may
           have instances sent/received:
    
           int Send(Buffer*, int = 0) const;
           int Receive(Buffer*);
    
           It is your responsibility to add these to your code.  The 
           function definitions will be produced by the Writer.
           
           Depending on the type and how it is used, a method called 
           Reset may also be written.  In that case the following 
           prototype is also needed.
          
           void Reset();
    
    
  2. Return Codes
           The Send/Receive functions return 1 if successful or 
           0 if not.
    

     

  3. Building

    If you sent header files as input, make sure those files are included prior to a generated file.

     

 

    Warnings: 

    If you intend to use the generated output in a heterogenous 
    environment, you should take care with the sizeof's for the various 
    basic types.  There is ongoing work among hardware companies and
    C++ compiler vendors to reduce the difficulties in this area.

    We don't address little/big endian differences.

    Be careful when it comes to pointers.  The Send functions don't 
    check that pointers are non null.  

    We support Boost::multi_index_container, but with some 
    limitations:  
         1.   At most one sequenced index.
         2.   If a sequenced index is part of the class makeup, it 
              must be the first index listed in the "IndexSpecifierList." 
         3.   Transmission of a multi_index_container will probably not
              preserve the relative order of elements that are 
              considered equal under an ordered_non_unique index.
 
    These limitations permit the transmission of a 
    multi_index_container to a "single index container" such as vector 
    or list if desired.

    Tips:

    Make sure any header files you send as input compile before you 
    send them. 


    Dealing with Stragglers:

    Often a new version of a server is required to support multiple
    versions of ambassadors(clients).  The following is an idea of 
    how to go about that.


                                 release 
                     1.1     1.2        1.3         1.4 
    --------------------------------------------------------- 
    class name    Account  Account   Account_13  Account_13 

    The class name incorporates the release in which it was last 
    changed.  Let's say that the 1.3 version of the server is 
    required to support 1.1 clients.  To do this the server is 
    built with both the Account and Account_13 definitions.

    When only additions to Account are needed between releases,
    the software might be structured like this

            AccountBase 
                | 
             Account 
                | 
            Account_13 

    If members need to be relocated out of Account in 1.3, the 
    hierarchy might be 

          AccountBase 
            /     \ 
        Account Account_13 


    In either case, the 1.3 server may use polymorphism and 
    accomplish what is needed pretty simply. When working
    with a 1.1 ambassador, it produces 1.1 data by executing 
    what originally was 1.1 code.  


    Protocol:

     There are a few simple rules that are followed:

       When a container or string is sent, the size/length of
       the container is sent ahead of the elements/characters.

       When an object is sent via a base class pointer, an
       integer identifier, produced by the Writer, is sent 
       ahead of the object data.  The identifier is used on
       the receiving end to construct the correct object.

    Project Goals:
   
     The interfaces should be easy to learn.
     The code should build and run correctly. 
     The code should be thread safe. 
     The code should execute efficiently.

    Advantages:

    We don't impose a language mapping or a second type system on 
    users.  Therefore, users don't waste time copying data between 
    objects of the two type systems.  That sort of copying requires 
    both programming effort and runtime cycles.  It is also 
    possible to maintain data in different ways on the two sides of 
    the application.  For example, a client may send a set<int> 
    and a server could receive the data as a vector<int>.

    Other approaches to marshalling C++ objects often use a library
    that defines templates.  While templates are often helpful, 
    there are difficulties with using them in this context.
    For one thing having a variable number of arguments isn't 
    accomplished satisfactorily with the existing template mechanism.  
    This leads to a performance penalty when a message is made up of 
    multiple objects.  A second problem stems from the fact that C++
    compilers don't output the C++ code they generate from templates.
    This makes it difficult for users of an open source application
    that has used a marshalling library to build the application.
    They have to obtain a correct version of the library used by the 
    developer of the open source program in order to build the soft-
    ware.  With our approach, you publish both hand written files
    and one or more generated files.  This simplifies things for 
    users, and programs built with this approach are generally smaller
    than those built with a library that defines C++ templates.
 
    Competing approaches often require changes to a program to support 
    marshalling.  We don't introduce macros and we don't require
    duplication of information to support marshalling.
    
    We don't know of other middleware frameworks that support 
    hinted insert.  

    Other approaches use buffers, but to our knowledge they use 
    buffering internally and do not permit the rest of the application 
    to access the buffers.  In our approach, you pass a buffer to the 
    generated middleware when you want a function to use it and you may 
    use the buffer for other purposes in other parts of the application.  

    Other:

    We use C and a library called CGIC to support the forms on the 
    site.  The author of CGIC requires the following paragraph be 
    included here.  It has no bearing on our ability to offer this
    service freely.  C++ source code obtained via this site, 
    whether written by a person or a computer, is free.  In the 
    spirit of days gone by, the C++ code is not copyrighted.

    CGIC, copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 by Thomas Boutell 
    and Boutell.Com, Inc.. Permission is granted to use CGIC in any 
    application, commercial or noncommercial, at no cost. HOWEVER,
    this copyright paragraph must appear on a "credits" page accessible 
    in the public online and offline documentation of the program. 
    Modified versions of the CGIC library should not be distributed without 
    the attachment of a clear statement regarding the author of the 
    modifications, and this notice may in no case be removed. 
    Modifications may also be submitted to the author for inclusion 
    in the main CGIC distribution. 

    The above does not impinge on our freedom to offer code generation 
    services free of copyrights.  C++ source code obtained through this 
    website is not copyrighted.

C++ in a Nutshell

By Ray Lischner.
First Edition May 2003
Pages: 808


C++ in a Nutshell packs an enormous amount of information on C++ (and the many libraries used with it) in an indispensable quick reference for those who live in a deadline-driven world and need the facts but not the frills. Cross-references link related methods, classes, and other key features. This is an ideal resource for students as well as professional programmers.
read more