Design of Associative Name Space, Id and Id_Trait


There are 2 stimulis for the design of associative name space:
Many shells (e.g. rc, bash) support the following control flow structure:
          case expression in
                pattern1 )
                      statements ;;
                pattern2 )
                      statements ;;
                ......
          esac
          In shells, patterns are created by using wildcard characters (*,?...). Ruby provides a stronger "case" structure using regex to define patterns.
In a brief summary, in a Linda system, distributed processes communicate thru shared associative "address space" - tuple space which consist of tuples. Each tuple consists of fields. Tuples are written ("out") to tuple space, read and taken ("in", "read") from tuple space. Tuples are identified thru associative lookup: two tuples match if all their corresponding fields match while two fields match if they are of the same type and either of the same value or one of them is wildcard.

Channel supports message passing and name-matching based on regex pattern matching and Linda associative lookup. Regex name-matching is implemented using Boost.Regex and the code is relative straightforward. Please refer to sample 9 for the usage of regex based name-matching. Here we focus on the detailed implemenation of names-matching using Linda lookup. Please refer to sample 10 for the usage of associative lookup based name-matching.

In Linda style associative name space, a message names/ids is "a tuple" consisting of a set of fields. We use Boost.Tuple  for defining these ids and names. To support associative lookup, we define field_trait template classes for each data type of the tuple fields. Each field_trait class will define wildcard and match operation for its data type. The following is a sample:
    template <>
    class BOOST_CHANNEL_DECL field_trait<int> {
    public:
      typedef int field_type;
      static int wildcard;
      static bool wildcard_field(int f) {
        if (f == wildcard)
          return true;
        return false;
      }
      static bool match(int f1, int f2) {
        if (f1 == wildcard || f2 == wildcard)
          return true;
        return f1 == f2;
      }
    };
In assoc_id_trait.hpp, we define the field_trait template classes for all the primitive data types. If user defined types (classes or structs) are to be used as tuple field type, user code should provide field_trait classes for these types.

We define the following template class as associative name space id:
    template <typename Tuple_Type>
    class tuple_id {
        ......
   
We need define copy constructor and standard relational operators for tuple_id to work with std::map container.
        tuple_id(const tuple_id &id) : type_(id.type_), tuple_(id.tuple_) {}
        bool operator< (const tuple_id &id) const {......}
        bool operator== (const tuple_id &id) const {......}
        bool operator!= (const tuple_id &id) const {......}
        ......
   
Then we define serialize() method to marshal/demarshal tuple_id using Boost.Serialization
        template<class Archive>
          void serialize(Archive & ar, const unsigned int version) {......}
    };

Next, we define id_trait class for tuple_id:

    template<typename Tuple_Type>
    class BOOST_CHANNEL_DECL id_trait<tuple_id<Tuple_Type> > {
    public:
    we define some associated types.
      typedef Tuple_Type tuple_type;
      typedef tuple_id<tuple_type> id_type;
    and define system internal messages
      static id_type channel_conn_msg;
      static id_type channel_disconn_msg;
      static id_type init_subscription_info_msg;
      static id_type connection_ready_msg;
      static id_type subscription_info_msg;
      static id_type unsubscription_info_msg;
      static id_type publication_info_msg;
      static id_type unpublication_info_msg;
   
Since internally Boost.Tuple is represented as recursive cons list, the following match operation is defined as recursive methods:
      static bool match_tuple(const boost::tuples::null_type&, const boost::tuples::null_type&)

      {
        return true;
      }

      template <typename H, typename T>
      static bool match_tuple(const boost::tuples::cons<H,T> &t1, const boost::tuples::cons<H,T> &t2)
      {
        if(!field_trait<H>::match(t1.get_head(), t2.get_head()))
          return false;
        return match_tuple(t1.get_tail(), t2.get_tail());
      }

      static bool match(id_type id1, id_type id2)
      {
        if (id1.type_ != id2.type_)
          return false;
        if (id1.type_ == id_type::app_type) {
          if (wildcard_tuple(id1.tuple_) && wildcard_tuple(id2.tuple_) && (id1.tuple_ != id2.tuple_))
            return false;
          if (id1.tuple_ == id2.tuple_)
            return true;
          return match_tuple(id1.tuple_, id2.tuple_);
        }
        return true;
      }
Similarly, we define recursive methods to find if a tuple_id contains wildcard:
      static bool wildcard_tuple(const boost::tuples::null_type&)
      {
        return false;
      }

      template <typename H, typename T>
      static bool wildcard_tuple(const boost::tuples::cons<H,T> &t1)
      {
        if(field_trait<H>::wildcard_field(t1.get_head()))
          return true;
        return wildcard_tuple(t1.get_tail());
      }

      static bool wildcard_name(const id_type &id) {
        if (id.type_ != id_type::app_type)
          return false;
        return wildcard_tuple(id.tuple_);
      }
Finally we define a method to display id content as string for debugging purpose:
      static std::string id_to_string(const id_type &id) {
        std::ostringstream os;
        os << "tuple_id : type[" << id.type_ << "] tuple[" << id.tuple_ << "]";
        return os.str();
      }     
    };

Since the type of tuple (how many fields and what fields types) are decided by application code of Channel and can be different for different applications, the pre-defined system internal messages can only be defined thru the following macro. Application code should include this macro somewhere so that its system internal messages are defined:
#define DEFINE_ASSOC_SYS_IDS( tuple_type ) \
template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::channel_conn_msg(boost::channel::tuple_id<tuple_type>::channel_conn_type); \
......