Boost logo

Boost :

From: Andy Glew (glew_at_[hidden])
Date: 1999-10-08 01:52:00


While we're at it, I'd like to solicit advice as to
the interfaces for a family of such consistent structures.

To begin with, the basic groups:

        reln_1_to_1
        reln_1_to_N
        reln_N_to_N

    These are the basic components. It then seems to me that you
    might want to extend this, for example, to variously transitively closed
    operations:

            reln_equivalence
                    if (A,B) and (B,C) , then (A,C)
                    i.e. A,B, and C are all linked equally.

            I am tempted to include total orders here,
            but I think that is too expensive, much more so than
            equivalence groups.

    Similarly, you may want to build N-tuples

            reln_many_to_1_to_many // a 3-tuple
    
                I have some hope of defining constructors
                for these in terms of the binary relations.

The innards for reln_1_to_1

        class reln_1_to_1 {
            // base class
            template<class From> class reverse_ptr {
                From* value;
                // not directly assignable, is dereferenceable, etc.
            }
            template<class To> class forward_ptr {
                From* value;
            }
        }

        template<class From, Class To>
        class reln_1_to_1 {
        public:
                void link( From f, To t );
        public:
                class forward_map {
                    // defines reln[From] = To
                }
                class reverse_map { ... };
        public:
                class iterator {
                    // the usual iterator stuff, sto scan a whole relation
                }
        public:
                // find(f,t)
                // erase(iterator)
        }

        template<class From, Class To, &From::ForwardLink, &To::BackwardLink >
        class reln_1_to_1 {
            // as above, but also keeps the member pointers consistent
        }

i.e. the basic approach is to define forward_map and reverse_map member classes,
and to use these to encapsulate particular queries.

reln_1_to_N is similar, but instead of having simple pointers, has lists or maps
in the reverse direction

        class reln_1_to_N {
            // base class
            template<class From> class reverse_list {
                list<From*> value;
                // not directly assignable, is dereferenceable, etc.
            }
            template<class To> class forward_ptr {
                From* value;
            }
        }

        template<class From, Class To>
        class reln_1_to_N {
        public:
                void link( From f, To t );
        public:
                class forward_map {
                    // defines To operator[] ( From& f)
                }
                class reverse_map {
                   // defines const list<From> operator[] ( To& t)
                };
        public:
                class iterator {
                    // the usual iterator stuff, so scan a whole relation
                }
        public:
                // find(f,t)
                // erase(iterator)
        }

        template<class From, Class To, &From::ForwardLink, &To::BackwardLink >
        class reln_1_to_N {
            // as above, but also keeps the member pointers consistent
        }

The complexity of reln_1_to_N is that the reverse map is a container.
It is not clear to me whether that container should itself be a parameter,
and, if so, how to parametrize it. I.e. it is straightforward to have the reverse
data structure always be a list, but sometimes you want it to be a map
sorted on a key, sometimes a hash_map, etc.

reln_M_to_N is similar. Once we figure out what the proper way to
represent 1:many relations is - or, more likely, what the proper way
to handle multiple different desired representations - the rest follows.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk