Logo Search packages:      
Sourcecode: tagcoll version File versions  Download package

Collection.h

Go to the documentation of this file.
#ifndef TAGCOLL_COLLECTION_H
#define TAGCOLL_COLLECTION_H

/** \file
 * Interface for all tagged collections
 */

/*
 * Copyright (C) 2003,2004,2005  Enrico Zini <enrico@debian.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

#include <tagcoll/Consumer.h>

namespace Tagcoll
{
template<typename T1, typename T2> class PatchList;

/**
 * Interface for all collections of tagged items.
 *
 * \note The point of a collection is to track the tags attached to items, and
 * not to store the items themselves.  This means that collections are not
 * required to keep track of items with no tags.
 */
template<typename ITEM, typename TAG>
00040 class Collection : public Consumer<ITEM, TAG>
{
protected:
      /*
       * Implementation note: to avoid problems with classes implementing only
       * some of the virtual methods, they are given different names.  The common
       * 'comsume' methods are just inlined calls to the right virtual functions,
       * and are a way of keeping the unoverridden methods from being hidden.
       */

00050       void consumeItemUntagged(const ITEM&) {}
00051       void consumeItemsUntagged(const OpSet<ITEM>&) {}

      /**
       * Get the items which are tagged with at least the tag `tag'
       *
       * \return
       *   The items found, or an empty set if no items have that tag
       */
      virtual OpSet<ITEM> getItemsHavingTag(const TAG& tag) const = 0;

      /**
       * Get the items which are tagged with at least the tags `tags'
       *
       * \return
       *   The items found, or an empty set if no items have that tag
       */
00067       virtual OpSet<ITEM> getItemsHavingTags(const OpSet<TAG>& tags) const
      {
            if (tags.empty())
                  return OpSet<ITEM>();

            typename OpSet<TAG>::const_iterator i = tags.begin();
            OpSet<ITEM> res = getItemsHavingTag(*i);

            for ( ; i != tags.end(); i++)
                  res ^= getItemsHavingTag(*i);

            return res;

      }

      /**
       * Get the tags attached to an item.
       *
       * \param item
       *   The item to query
       * \return 
       *   The set of tags, or an empty set if the item has no tags or it does
       *   not exist.
       */
      virtual OpSet<TAG> getTagsOfItem(const ITEM& item) const = 0;

      /**
       * Get all the tags attached to the items in a set.
       *
       * \param items
       *   The items to query
       * \return 
       *   The set of tags, or an empty set if the items have no tags or do not
       *   exist.
       */
00102       virtual OpSet<TAG> getTagsOfItems(const OpSet<ITEM>& items) const
      {
            OpSet<TAG> res;
            for (typename OpSet<ITEM>::const_iterator i = items.begin();
                        i != items.end(); i++)
                  res += getTagsOfItem(*i);
            return res;
      }

public:
      virtual ~Collection() {}
      
      /**
       * Check if the collection contains a tag
       *
       * \param tag
       *   The tag to look for
       * \return 
       *   true if the collection contains tag, false otherwise
       */
00122       virtual bool hasTag(const TAG& tag) const
      {
            return !getItems(tag).empty();
      }

      /**
       * Get the tags of item `item'.  Return an empty set if `item' does not exist
       */
00130       OpSet<TAG> getTags(const ITEM& item) const { return getTagsOfItem(item); }

      /**
       * Get all the tags of items `items'.  Return an empty set if all of `item' do not exist
       */
00135       OpSet<TAG> getTags(const OpSet<ITEM>& items) const { return getTagsOfItems(items); }

      /**
       * Get the items with tag `tag'.  Return an empty set if `tag' does not exist
       */
00140       OpSet<ITEM> getItems(const TAG& tag) const { return getItemsHavingTag(tag); }

      /**
       * Get the items with tag `tag'.  Return an empty set if `tag' does not exist
       */
00145       OpSet<ITEM> getItems(const OpSet<TAG>& tags) const { return getItemsHavingTags(tags); }

      /**
       * Apply a patch to the collection
       *
       * Example:
       * \code
       * void perform(const PatchList<ITEM, TAG>& change)
       * {
       *    collection.applyChange(change);
       *    undo.push_back(change.getReverse());
       * }
       * \endcode
       */
      virtual void applyChange(const PatchList<ITEM, TAG>& change) = 0;

      /**
       * Get the set of all the items that have tags according to this collection
       */
      virtual OpSet<ITEM> getTaggedItems() const = 0;

      /**
       * Get the set of all the tags in this collection
       */
      virtual OpSet<TAG> getAllTags() const = 0;

      /**
       * Get the cardinality of tag `tag' (that is, the number of items who have it)
       */
00174       virtual int getCardinality(const TAG& tag) const
      {
            return getItemsHavingTag(tag).size();
      }

      /**
       * Get the set of all tags in this collection that appear in tagsets
       * containing `tags'
       *
       * Example:
       * \code
       * void refineSelection(const OpSet<Tag>& selection)
       * {
       *    OpSet<Tag> extraTags = collection.getCompanionTags(selection);
       *    tagMenu.setAvailableOptions(extraTags);
       * }
       * \endcode
       */
00192       virtual OpSet<TAG> getCompanionTags(const OpSet<TAG>& tags) const
      {
            return getTagsOfItems(getItemsHavingTags(tags)) - tags;
      }

      /**
       * Get the related items at the given maximum distance
       *
       * Examples:
       * \code
       * // Get the items related to a given one, at the given distance
       * OpSet<Item> getRelated(const Item& item, int distance)
       * {
       *    OpSet<Item> res = collection.getRelatedItems(collection.getTags(item), distance);
       *    return res - item;
       * }
       *
       * // Get the items related to the given ones, at the given distance
       * OpSet<Item> getRelated(const OpSet<Item>& items, int distance)
       * {
       *    OpSet<Item> res = collection.getRelatedItems(collection.getTags(items), distance);
       *    return res - items;
       * }
       *
       * // Get the related items, increasing the distance until it finds at
       * // least 'minimum' items
       * OpSet<Item> getRelated(const Item& item, int minimum)
       * {
       *    OpSet<Tag> tags = collection.getTags(item);
       *    OpSet<Item> res;
       *    for (int i = 0; i < tags.size() && res.size() < minimum; i++)
       *           res += collection.getRelatedItems(tags, i);
       *      return res - item;
       * }
       * \endcode
       */
00228       virtual OpSet<ITEM> getRelatedItems(const OpSet<TAG>& tags, int maxdistance = 1) const
      {
            OpSet<ITEM> packages;
            OpSet<ITEM> res;

            // First get a list of packages that have a non-empty intersection with `tags'
            for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++)
                  packages += getItemsHavingTag(*i);

            // Then keep only those within the given distance
            for (typename OpSet<ITEM>::const_iterator i = packages.begin(); i != packages.end(); i++)
            {
                  int dist = tags.distance(getTagsOfItem(*i));
                  if (dist >= 0 && dist <= maxdistance)
                        res += *i;
            }

            return res;
      }

      /**
       * Output all the contents of the collection to a Consumer
       */
      virtual void output(Consumer<ITEM, TAG>& consumer) const = 0;

      /**
       * Send to a consumer all the items which are tagged with at least the
       * given tags
       */
00257       virtual void outputHavingTags(const OpSet<TAG>& tags, Consumer<ITEM, TAG>& consumer) const
      {
            OpSet<ITEM> items = getItemsHavingTags(tags);
            for (typename OpSet<ITEM>::const_iterator i = items.begin();
                        i != items.end(); i++)
                  consumer.consume(*i, getTagsOfItem(*i));
      }
};

};

// vim:set ts=4 sw=4:
#endif

Generated by  Doxygen 1.6.0   Back to index