#line 1 "/user/cvsspst/ees1cg/RAVL/RAVL-0.7/Math/Sequence/CombinationIter.hh"
// This file is part of RAVL, Recognition And Vision Library
// Copyright (C) 2001, University of Surrey
// This code may be redistributed under the terms of the GNU Lesser
// General Public License (LGPL). See the lgpl.licence file for details or
// see http://www.gnu.org/copyleft/lesser.html
// file-header-ends-here
#ifndef RAVLCOMBINATIONITER_HEADER
#define RAVLCOMBINATIONITER_HEADER 1
/////////////////////////////////////////////////////
//! userlevel=Normal
//! author="Charles Galambos"
//! rcsid="$Id: CombinationIter.hh,v 1.2 2002/01/31 14:55:43 craftit Exp $"
//! file="Ravl/Math/Sequence/CombinationIter.hh"
//! docentry="Ravl.Math.Sequences"
//! date="24/08/98"
//! lib=RavlMath
#include "Ravl/DList.hh"
#include "Ravl/DLIter.hh"
namespace RavlN {
//: Combination iterator.
// This iterator works from shorter to longer combinations
// progressively.
// SMALL OBJECT
template
class CombinationIterC {
public:
CombinationIterC(IntT nStartLen = 1);
//: Default constructor.
CombinationIterC(const DListC &items,IntT nStartLen = 1);
//: Constructor.
CombinationIterC(const CombinationIterC &oth);
//: Copy constructor.
// This is a medium depth copy, it only
// copies enough to get an independant iteration
// of combination. The items list is NOT copied,
// so modifying it will affect the iterator.
const CombinationIterC &operator=(const DListC &items);
//: Assign to new list.
// Does an implicit First().
inline bool IsElm() const
{ return !data.IsEmpty(); }
//: Is there a valid combination remaining ?
operator bool() const
{ return IsElm(); }
//: Is there a valid combination remaining ?
inline DListC &Data()
{ return data; }
//: Current combination.
inline IntT Terms() const
{ return combSize; }
//: Get number of items in current combination.
bool First();
//: Goto first combination.
// Returns false if none.
bool Next();
//: Goto next combination.
// Returns false if none.
void operator++(int)
{ Next(); }
//: Goto next combination.
private:
bool IncrComb(DLIterC > lst);
//: Increment combination.
IntT combSize; // Number of items in combination.
IntT startLen; // Start length.
DListC > cIter; // List of combination iters.
DListC items; // List of all items.
DListC data; // Current combination.
};
/////////////////////////////////////////////////////////////
template
CombinationIterC::CombinationIterC(IntT nStartLen)
: combSize(0),
startLen(nStartLen)
{}
template
CombinationIterC::CombinationIterC(const DListC &nitems,IntT nStartLen)
: combSize(1),
startLen(nStartLen),
items(nitems)
{ First(); }
template
CombinationIterC::CombinationIterC(const CombinationIterC &oth)
: combSize(oth.combSize),
cIter(oth.cIter.Copy()),
items(oth.items),
data(oth.data.Copy())
{}
template
const CombinationIterC &
CombinationIterC::operator=(const DListC &nItems) {
items = nItems;
First();
return *this;
}
template
bool CombinationIterC::First() {
combSize = startLen;
cIter.Empty();
if(combSize != 1)
return Next();
DLIterC sIt(items);
if(!sIt.IsElm())
return false;
cIter.InsFirst(sIt);
data.Empty();
data.InsLast(sIt.Data());
return true;
}
template
bool CombinationIterC::Next() {
data.Empty();
while(1) {
if(cIter.IsEmpty()) {
DLIterC sIt(items);
// Setup iteration of new combination length.
for(int j = 0;j < combSize;j++) {
if(!sIt.IsElm())
return false;
cIter.InsFirst(sIt);
sIt.Next();
}
} else {
// Generate combinations.
DLIterC > cIt(cIter);
if(!IncrComb(cIt)) {
// Out of combination length 'combSize'.
combSize++;
cIter.Empty();
continue;
}
}
break;
}
// Setup data.
for(DLIterC > cIt(cIter);cIt.IsElm();cIt.Next())
data.InsFirst(cIt.Data().Data());
return true;
}
template
bool CombinationIterC::IncrComb(DLIterC > lst) {
// I'm sure this is NOT the best way of iterating combinations.
// but it works.
lst.Data().Next(); // Inc LSB of remaining lst.
if(lst.Data().IsElm()) // Off the end ?
return true; // No, so done.
lst.Next(); // Have to increment next.
if(!lst.IsElm())
return false; // No higher index !
if(!IncrComb(lst))
return false; // Incrementing next failed.
DLIterC newPos;
do {
newPos = lst.Data();
newPos.Next();
if(!newPos.IsElm()) {
if(!IncrComb(lst))
return false;
} else
break;
} while(1);
lst.Prev();
lst.Data() = newPos;
return true;
}
}
#endif