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

Patches.cc

/*
 * Classes handling tag patches
 *
 * Copyright (C) 2003  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/Patches.h>

#include <stdio.h>

#include <tagcoll/stringf.h>

using namespace std;

namespace Tagcoll {

template <class ITEM, class TAG>
class PatchGenerator: public Consumer<ITEM, TAG>
{
protected:
      PatchList<ITEM, TAG>& target;
      const Collection<ITEM, TAG>& second;

      // Process an untagged item
      virtual void consumeItemUntagged(const ITEM& item)
      {
            OpSet<TAG> ts2 = second.getTags(item);
            if (!ts2.empty())
                  target.addPatch(Patch<ITEM, TAG>(item, ts2, OpSet<TAG>()));
      }

      // Process a tagged item, with its tags
      virtual void consumeItem(const ITEM& item, const OpSet<TAG>& ts1)
      {
            OpSet<TAG> ts2 = second.getTags(item);
            OpSet<TAG> added = ts2 - ts1;
            OpSet<TAG> removed = ts1 - ts2;
            if (!added.empty() || !removed.empty())
                  target.addPatch(Patch<ITEM, TAG>(item, added, removed));
      }
public:
      PatchGenerator(PatchList<ITEM, TAG>& target, const Collection<ITEM, TAG>& second) throw ()
            : target(target), second(second) {}
};

template <class ITEM, class TAG>
00061 void PatchList<ITEM, TAG>::addPatch(const Patch<ITEM, TAG>& patch) throw ()
{
      // Filter out empty patches
      if (patch.getAdded().empty() && patch.getRemoved().empty())
            return;

      iterator i = find(patch.getItem());
      if (i == this->end())
            insert(make_pair<ITEM, Patch<ITEM, TAG> >(patch.getItem(), patch));
      else
            i->second.mergeWith(patch);
}

template <class ITEM, class TAG>
00075 void PatchList<ITEM, TAG>::addPatch(const PatchList<ITEM, TAG>& patches) throw ()
{
      for (typename PatchList<ITEM, TAG>::const_iterator i = patches.begin();
                  i != patches.end(); i++)
            addPatch(i->second);
}

template <class ITEM, class TAG>
00083 void PatchList<ITEM, TAG>::addPatch(
            const Collection<ITEM, TAG>& im1, const Collection<ITEM, TAG>& im2) throw ()
{
      PatchGenerator<ITEM, TAG> patchgen(*this, im2);
      im1.output(patchgen);
}

template <class ITEM, class TAG>
00091 OpSet<TAG> PatchList<ITEM, TAG>::patch(const ITEM& item, const OpSet<TAG>& tagset) const throw ()
{
      // Find the patch record for this item
      const_iterator p = find(item);
      if (p == this->end())
            // If there are no patches, return the tagset unchanged
            return tagset;

      // There are patches: apply them:
      return p->second.apply(tagset);
}

template <class ITEM, class TAG>
PatchList<ITEM, TAG> PatchList<ITEM, TAG>::getReverse() const throw ()
{
      PatchList<ITEM, TAG> res;
      for (typename PatchList<ITEM, TAG>::const_iterator i = this->begin();
                  i != this->end(); i++)
            res.addPatch(i->second.getReverse());
      return res;
}


/*
template <class ITEM>
void PatchList<ITEM>::consume(const ITEM& item, const OpSet<string>& tags) throw ()
{
      patches.insert(make_pair(item, tags));
}

// Output the patch list to a TagcollConsumer
template <class ITEM>
void PatchList<ITEM>::output(TagcollConsumer<ITEM, std::string>& consumer) const throw ()
{
      for (typename map< ITEM, OpSet<string> >::const_iterator i = patches.begin();
                  i != patches.end(); i++)
            if (i->second.size() == 0)
                  consumer.consume(i->first);
            else
                  consumer.consume(i->first, i->second);
}
*/

template <class ITEM, class TAG>
00135 void PatchList<ITEM, TAG>::consumeItemUntagged(const ITEM& item)
{
      OpSet<TAG> patched = patch(item, OpSet<TAG>());

      if (patched.size())
            this->consumer->consume(item, patched);
      else
            this->consumer->consume(item);
}

template <class ITEM, class TAG>
00146 void PatchList<ITEM, TAG>::consumeItem(const ITEM& item, const OpSet<TAG>& tags)
{
      OpSet<TAG> patched = patch(item, tags);

      if (patched.size())
            this->consumer->consume(item, patched);
      else
            this->consumer->consume(item);
}

}

#ifndef INSTANTIATING_TEMPLATES
namespace Tagcoll {
template class Patch<std::string, std::string>;
template class PatchList<std::string, std::string>;
}
#endif


#ifdef COMPILE_TESTSUITE

#include <tests/test-utils.h>

#include <tagcoll/TextFormat.h>
#include <tagcoll/StringParserInput.h>

namespace tut {
using namespace tut_tagcoll;

struct tagcoll_patches_shar {
};
TESTGRP(tagcoll_patches);

template<> template<>
void to::test<1>()
{
      StringParserInput input_coll(
                  "a: b, c\n"
                  "b:\n"
                  "c: \n"
                  "d:  c::D, e::F,    f::g\n"
                  );
      TestConsumer<string, string> cons;
      PatchList<string, string> patches(cons);

      OpSet<string> added;
      OpSet<string> removed;

      added += "b";
      removed += "c"; removed += "d";
      patches.addPatch(Patch<string, string>("a", added, removed));

      added.clear(); added += "b", added += "c", added += "b";
      removed.clear(); removed += "a";
      patches.addPatch(Patch<string, string>("b", added, removed));

      added.clear(); added += "c::D", added += "c::d";
      removed.clear(); removed += "f::g";
      patches.addPatch(Patch<string, string>("d", added, removed));

      Converter<string, string> a;
      TextFormat<string, string>::parse(a, a, input_coll, patches);

      ensure(cons.items == 4);
      ensure(cons.tags == 5);

}

}

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

Generated by  Doxygen 1.6.0   Back to index