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

PatchCollection.cc

/*
 * Wrap a Collection, preserving modifications as patches
 *
 * Copyright (C) 2005  Enrico Zini <enrico@debian.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <tagcoll/PatchCollection.h>

using namespace std;

namespace Tagcoll
{

template<class ITEM, class TAG>
00029 void PatchCollection<ITEM, TAG>::consumeItem(const ITEM& item, const OpSet<TAG>& tags)
{
      if (!tags.empty())
            changes.addPatch(Patch<ITEM, TAG>(item, tags, OpSet<TAG>()));
}

template<class ITEM, class TAG>
00036 OpSet<ITEM> PatchCollection<ITEM, TAG>::getItemsHavingTag(const TAG& tag) const
{
      OpSet<ITEM> items(coll.getItems(tag));
      OpSet<ITEM> res;

      // Check items in coll first
      for (typename OpSet<ITEM>::const_iterator i = items.begin();
                  i != items.end(); i++)
            // If they are unmodified, then we can trust coll.getItems
            if (changes.find(*i) == changes.end())
                  res += *i;

      // Then check items in the patch
      for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
                  i != changes.end(); i++)
            if (changes.patch(i->first, coll.getTags(i->first)).contains(tag))
                  res += i->first;

      return res;
}

template<class ITEM, class TAG>
00058 OpSet<TAG> PatchCollection<ITEM, TAG>::getTagsOfItem(const ITEM& item) const
{
      return changes.patch(item, coll.getTags(item));
}


template<class ITEM, class TAG>
00065 void PatchCollection<ITEM, TAG>::setChanges(const PatchList<ITEM, TAG>& changes)
{
      this->changes.clear();
      
      // Simplify the patch against the contents of `coll' before adding it.
      for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
                  i != changes.end(); i++)
            // Consider only valid items
            if (i->first != ITEM())
            {
                  Patch<ITEM, TAG> newChange(i->second);

                  OpSet<TAG> tags(coll.getTags(i->first));
                  newChange.removeRedundant(tags);

                  // Empty patches are filtered out by PatchList so we don't need to do
                  // it here
                  this->changes.addPatch(newChange);
            }
}

template<class ITEM, class TAG>
00087 bool PatchCollection<ITEM, TAG>::hasTag(const TAG& tag) const
{
      OpSet<ITEM> items(coll.getItems(tag));

      // Check items in coll first
      for (typename OpSet<ITEM>::const_iterator i = items.begin();
                  i != items.end(); i++)
            // If they are unmodified, then we can trust coll.getItems
            if (changes.find(*i) == changes.end())
                  return true;

      // Then check items in the patch
      for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
                  i != changes.end(); i++)
            if (i->second.getAdded().contains(tag))
                  return true;

      return false;
}

template<class ITEM, class TAG>
00108 OpSet<ITEM> PatchCollection<ITEM, TAG>::getTaggedItems() const
{
      OpSet<ITEM> res(coll.getTaggedItems());
      for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
                  i != changes.end(); i++)
            res += i->first;
      return res;
}

template<typename ITEM, typename TAG>
class TagCollector : public Consumer<ITEM, TAG>, public OpSet<TAG>
{
protected:
      virtual void consumeItemUntagged(const ITEM& item) {}
      virtual void consumeItemsUntagged(const OpSet<ITEM>& item) {}

      virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
      {
            *this += tags;
      }
      virtual void consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
      {
            *this += tags;
      }
};

template<class ITEM, class TAG>
00135 OpSet<TAG> PatchCollection<ITEM, TAG>::getAllTags() const
{
      TagCollector<ITEM, TAG> res;

      output(res);

      return res;
}

template<class ITEM, class TAG>
class NoPatched : public Tagcoll::Filter<ITEM, TAG>
{
protected:
      const PatchList<ITEM, TAG>& changes;

      virtual void consumeItem(const ITEM& item, const OpSet<TAG>& tags)
      {
            if (changes.find(item) == changes.end())
                  this->consumer->consume(item, tags);
      }

public:     
      NoPatched(const PatchList<ITEM, TAG>& changes) : changes(changes) {}
      NoPatched(const PatchList<ITEM, TAG>& changes, Tagcoll::Consumer<ITEM, TAG>& cons)
            : Tagcoll::Filter<ITEM, TAG>(cons), changes(changes) {}
};

template<class ITEM, class TAG>
00163 void PatchCollection<ITEM, TAG>::output(Consumer<ITEM, TAG>& consumer) const
{
      // First, only pass the unpatched items
      NoPatched<ITEM, TAG> onlyUnpatched(changes);
      onlyUnpatched.setConsumer(consumer);
      coll.output(onlyUnpatched);

      // Then output the items in the patch
      for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
                  i != changes.end(); i++)
            consumer.consume(i->first,
                        changes.patch(i->first, coll.getTags(i->first)));
}

template<class ITEM, class TAG>
00178 void PatchCollection<ITEM, TAG>::applyChange(const PatchList<ITEM, TAG>& change)
{
      for (typename PatchList<ITEM, TAG>::const_iterator i = change.begin();
                  i != change.end(); i++)
      {
            Patch<ITEM, TAG> newChange(i->second);
            newChange.removeRedundant(getTags(i->first));
            changes.addPatch(newChange);
      }
}

template<class ITEM, class TAG>
00190 int PatchCollection<ITEM, TAG>::getCardinality(const TAG& tag) const
{
      int card = coll.getCardinality(tag);

      for (typename PatchList<ITEM, TAG>::const_iterator i = changes.begin();
                  i != changes.end(); i++)
      {
            if (i->second.getAdded().contains(tag))
                  card++;
            else if (i->second.getRemoved().contains(tag))
                  card--;
      }

      return card;
}


}

#ifndef INSTANTIATING_TEMPLATES
#include <string>

namespace Tagcoll {
template class PatchCollection<std::string, std::string>;
}
#endif

#ifdef COMPILE_TESTSUITE

#include <tests/test-utils.h>
#include <tagcoll/InputMerger.h>

namespace tut {
using namespace tut_tagcoll;

struct tagcoll_patchcollection_shar {
};
TESTGRP(tagcoll_patchcollection);

template<> template<>
void to::test<1>()
{
      // Use an InputMerger as the embedded collection
      InputMerger<string, string> startcoll;

      PatchCollection<string, string> coll(startcoll);

      test_tagged_collection(coll);
}

}

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

Generated by  Doxygen 1.6.0   Back to index