Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Extending the Standard Template Library with Association Classes


September 2001/Extending the Standard Template Library with Association Classes/Listing 1

Listing 1: Partial listing of Relations.h — association class definitions

//Relations.h
#ifndef _RELATIONS_H
#define _RELATIONS_H

#include <map>
#include <vector>
#include <algorithm>

using namespace std;

// OneOne relationship template class
template < class First, class Second, 
           class CompareFirst = less<First>,
           class CompareSecond = less<Second> >
class OneOne
{

   typedef map <First,  Second, CompareFirst> FirstSecond;
   typedef map <Second, First, CompareSecond>SecondFirst;

   FirstSecond _FirstSecond;
   SecondFirst _SecondFirst;

public:

   // Insert a pair of elements
   bool insert(const First& f, const Second& s);

   // Remove a pair with this First if it was inserted
   bool removeByFirst(const First& f);

   // Remove a pair with this Second if it was inserted
   bool removeBySecond(const Second& s);

   // Return the Second item for this First
   // or NULL if it doesn't exist
   Second * getSecond(const First& f);

   // Return the First item for this Second
   // or NULL if it doesn't exist
   First * getFirst(const Second& s);

   void clear(); // Clear this relationship

   // Define iterator for this relationship
   typedef FirstSecond::iterator iterator;

   iterator begin() { return _FirstSecond.begin(); }
   iterator end() { return _FirstSecond.end(); }
};

//--------------------------------------------------------------

// OneMany relationship template class
template <class One, class Many,
          class CompareOne = less<One>,
          class CompareMany= less<Many> >

class OneMany
{

   //maps One to several Many
   typedef multimap <One, Many, CompareOne> OneManyMap;
   OneManyMap _OneManyMap;

   //maps each Many to its One
   typedef map <Many, One, CompareMany> ManyOneMap;
   ManyOneMap _ManyOneMap;

public:
   // Insert this One Many pair to this relationship
   // if it is not already there
   bool insert(const One& o, const Many& m);

   // Remove this Many if it was inserted
   bool removeByMany(const Many& m);
        
   // Remove this One if it was inserted
   bool removeByOne(const One& o);

   // Return the One for this Many
   // or NULL if it doesn't exist
   One* getOne(const Many& m){

   // Nested iterator class for Many 
   class ManysIterator{...omitted...};

   typedef ManysIterator <One, Many> iterator;

   // Nest const iterator class for Many
   class ConstManysIterator 
      : public ManysIterator{...omitted...};

   typedef ConstManysIterator <One, Many> const_iterator;

   // The begin and end iterators for this One
   iterator begin(const One& o);
   iterator end(const One& o);

   // The const begin and end iterators for this One
   const_iterator begin(const One& o) const;
   const_iterator end(const One& o) const;

   void clear(); // Clear this relationship
};

//--------------------------------------------------------------

// triple struct used by ManyMany relationship
template <class T1, class T2, class T3>
struct triple : public pair<T1, T2>{

   triple(const T1& x, const T2& y, const T3& z) 
   : pair<T1, T2>(x, y), third(z){} 

   T3 third;
};

template <class T1, class T2, class T3>
inline triple<T1, T2, T3> 
make_triple(const T1& x, const T2& y, const T3& z){
   return triple<T1, T2, T3>(x, y, z);
}

// ValToType struct to determine type; used at compile time
template <class T1, class T2, class T3>
struct ValToType{ typedef triple <T1, T2, T3> type; };

// Partial template specialization of ValToType class
template <class T1, class T2>
struct ValToType<T1, T2, void>{ typedef pair <T1, T2> type; };

ManyMany relationship template class
template <class Many1, class Many2,
          class CompareMany1 = less<Many1>,
          class CompareMany2 = less<Many2>,
          class Rel          = void>
class ManyMany{

   typedef ValToType< Many1, Many2, Rel >::type  Relation;
   typedef vector<Relation> Relations;
   Relations _Relations;

   typedef multimap <Many1, Relation, CompareMany1> One1Many2Map;
   One1Many2Map _One1Many2Map;

   typedef multimap <Many2, Relation, CompareMany2> One2Many1Map;
   One2Many1Map _One2Many1Map;

public:

   // Insert this Many1 Many2 pair to the relationship
   bool insert(const Many1& m1, const Many2& m2){

      Relation rel(m1, m2);
      _Relations.push_back(rel);

      _One1Many2Map.insert( make_pair (m1, rel) );
      _One2Many1Map.insert( make_pair (m2, rel) );

      return true;
   }

   // Insert this Many1 Many2 Rel triple to the relationship
   bool insert(const Many1& m1, const Many2& m2, const Rel& r);

   // Remove this Many1
   bool removeByMany1(const Many1& m1);

   // Remove this Many2
   bool removeByMany2(const Many2& m2);

   Nested functor struct used to find relations
   struct eqRel{...omitted...};

   // Remove this Many1 Many2 pair
   bool remove(const Many1& m1, const Many2& m2);
  
   // Return the Link Attribute for this pair of Many1 Many2
   // or NULL if not found
   const Rel* getAttribute(const Many1& m1, const Many2& m2);

   //--------------------------------------------------
   // Nested iterator class for iterating over Many1s
   class Manys1Iterator{

   protected:
      typedef One2Many1Map::iterator OMI;
      OMI _mi;

      typedef bidirectional_iterator_tag iterator_category;
      typedef Manys1Iterator<Many1, Many2> self;

   public:

      Manys1Iterator(OMI mi = OMI()) : _mi(mi){}
      ...
      self& operator++() {
         _mi++;
         return *this;
      }
      ...
   };
   //--------------------------------------------------

   class Manys2Iterator{...omitted...};

   // Iterator types to iterate through Many1's and Many2's
   // respectively
   typedef Manys1Iterator <Many1, Many2> iterator1;
   typedef Manys2Iterator <Many1, Many2> iterator2;

   // The begin and end iterators for this Many2
   iterator1 begin(const Many2 & m2)
   { return iterator1(_One2Many1Map.lower_bound(m2)); }
   iterator1 end(const Many2 & m2)  
   { return iterator1(_One2Many1Map.upper_bound(m2)); }

   // The begin and end iterators for this Many1
   iterator2 begin(const Many1 & m1)
   { return iterator2(_One1Many2Map.lower_bound(m1)); }
   iterator2 end(const Many1 & m1)  
   { return iterator2(_One1Many2Map.upper_bound(m1)); }

   void clear(){ // Clear this relationship

      _One1Many2Map.clear();
      _One2Many1Map.clear();
      _Relations.clear();
   }
};


#endif
— End of Listing —

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.