Expression-Filter und logische Operationen


Functions

template<class F>
detail::expr< F > dirstr::op (const F &f)
 Markiert einen Filter als Operand für eine logische Operation.
template<class E1, class E2>
detail::expr< detail::expr_binary_v<
E1, E2, detail::and_op > > 
dirstr::operator && (const detail::expr< E1 > &e1, const detail::expr< E2 > &e2)
 UND-verknüpft die Ausdrücke e1 und e2.
template<class E1, class E2>
detail::expr< detail::expr_binary_v<
E1, E2, detail::or_op > > 
dirstr::operator|| (const detail::expr< E1 > &e1, const detail::expr< E2 > &e2)
 ODER-verknüpft die Ausdrücke e1 und e2.
template<class E1, class E2>
detail::expr< detail::expr_binary_v<
E1, E2, detail::xor_op > > 
dirstr::operator^ (const detail::expr< E1 > &e1, const detail::expr< E2 > &e2)
 XOR-verknüpft die Ausdrücke e1 und e2.
template<class E>
detail::expr< detail::expr_not_v<
E > > 
dirstr::operator! (const detail::expr< E > &e)
 Negiert den Filter der durch den Ausdruck e repräsentiert wird.
template<class T>
filter_base * dirstr::expr_f (const dirstr::detail::expr< T > &e)
 Transformiert einen boole'schen-Filterausdruck in ein filter_base-Objekt.

Detailed Description

Motivation
Häufig lässt sich ein Filterkriterium als Kombination einfacherer Filter ausdrücken, z.B. könnte ein Anwender alle cpp-Dateien die nicht temporäre Dateien sind auswählen wollen. Unter der Annahme, dass der Anwender bereits eine NoTemporaries-Filter-Klasse implementiert hat, könnte er nun folgendes schreiben:
class CppsNotTemporary
{
public:
    CppsNotTemporary()
                : cpp_f_("*.cpp")
        {}
        bool operator()(const std::string& e) const
        {
                return cpp_f_(e) && !notTemp_f_(e);
        }
private:
        pattern_f cpp_f_;
        NoTemporaries notTemp_f_;
};
...
dirstream str(".", pred_f(CppsNotTemporary()));
...
Die Implementation solcher Funktionsobjekte ist zwar einfach, führt aber schnell zu einer explosionsartigen Anhäufung kleiner Prädikate, die sich nur schlecht wiederverwenden lassen. Aus diesem Grund bietet dirstream die Möglichkeit Filter über logische Operationen zu verknüpfen. Intern wird dann automatisch ein Filter-Objekt erzeugt, das den fertigen Ausdruck repräsentiert.
Benutzung
Die Benutzung des Expression-Filter Frameworks ist denkbar einfach. Anstelle eines einfachen Filters übergibt man einen boole'schen Ausdruck an den Konstruktor von dirstream.
dirstream str(".", op(pattern_f("*.cpp")) && !op(NoTemporaries()));
Wie man dem Code entnehmen kann, müssen Filter, die über logische Operationen verknüpft werden sollen, zuvor an die Funktion op übergeben werden. Dieser kleine Umweg ist nötig, damit auch Zeiger auf Filter übergeben werden können (Ein überladener Operator muss mindestens ein Argument vom Typ UDT besitzen).
filter_base* f1 = filterFactory.getFilterA();
filter_base* f2 = filterFactory.getFilterB();
dirstream str(".", op(f1) || op(f2));
delete f2;
delete f1;
Arbeitsweise
Die Kombination von Filtern geschieht intern über Expression-Templates. Das entstehende Expression-Objekt wird dann in ein Filter-Objekt transformiert. Die Implementation des Expression-Frameworks ist relativ kompliziert (im Vergleich zur Komplexität der restlichen Bibliothek), für den Anwender zum Glück aber auch irrelevant.
Anwender des Expression-Frameworks müssen lediglich drei Dinge beachten:
  1. Klassen im Namespace dirstr::detail dürfen nicht direkt verwendet werden. Sie sind Implementationsdetails der Bibliothek.
  2. Das Ergebnis eines boole'schen Ausdrucks darf nur in drei Kontexten verwendet werden
    1. als Argument für die Funktion expr_f
    2. als Argument für einen Filter-Parameter eines dirstream-Konstruktors
    3. als Argument für einen Filter-Parameter einer dirstream::open-Funktion
  3. Bei der Umwandlung eines Expression-Objekts in ein Filter-Objekt werden alle enthaltenen Filter kopiert. D.h konkret:
    • Filter-Objekte, Prädikate und Funktionszeiger werden über ihren Copy-Konstruktor kopiert.
    • Zeiger auf Objekte einer von filter_base abgeleiteten Klasse werden über den Aufruf der Methode clone kopiert.
    • Der Value-Type eines SharedPtrs wird gemäßt der ersten beiden Regeln kopiert.
Attention:
Da Filter-Objekte und Prädikate über ihren Copy-Konstruktor kopiert werden, kann es hier unter Umständen zu Slicing-Problemen kommen, nämlich genau dann, wenn der Anwender ein Objekt einer abgeleiteten Klasse über eine Referenz auf eine konkreten Basisklasse an die Funktion op übergibt.
class FilterA {...};
class FilterB : public FilterA {};
FilterB b;
FilterA& a = b;
op(a) // Ups! Aus FilterB wird ein FilterA
Einschränkungen

Function Documentation

template<class T>
filter_base* dirstr::expr_f ( const dirstr::detail::expr< T > &  e  )  [inline]

Transformiert einen boole'schen-Filterausdruck in ein filter_base-Objekt.

Returns:
Liefert einen filter_base-Pointer auf ein dynamisch alloziertes Objekt einer nicht spezifizierten Klasse.
Note:
Der Aufrufer ist für die Zerstörung des Objekts verantwortlich.

template<class F>
detail::expr<F> dirstr::op ( const F &  f  )  [inline]

Markiert einen Filter als Operand für eine logische Operation.

Parameters:
f Ein filter-kompatibles Objekt.
filter-kompatible ist:
  • ein Objekt einer Klasse die von filter_base erbt
  • ein Zeiger auf ein Objekt einer Klasse die von filter_base erbt.
  • ein Funktionsobjekt das mit einem std::string-Argument aufgerufen werden kann und ein bool-kompatiblen Rückgabewert hat.
  • ein Zeiger auf eine Funktion die mit einem std::string-Argument aufgerufen werden kann und ein bool-kompatiblen Rückgabewert hat.
  • ein SharedPtr-Objekt dessen Value-Type eine der vorherigen Bedingungen erfüllt
Attention:
Argumente die an op übergeben werden, gehen nicht in den Besitz von op über. Das gilt insbesondere auch für Objekte die per Pointer übergeben werden. D.h. Code wie:
        op(new pattern_f("*.cpp"));
lässt sich zwar problemlos kompilieren, führt zur Laufzeit aber zu einem Speicherloch.
Returns:
Ein Objekt einer nicht spezifizierten Klasse das als Argument für einen logische Operator verwendet werden kann.

template<class E1, class E2>
detail::expr<detail::expr_binary_v<E1, E2, detail::and_op> > dirstr::operator && ( const detail::expr< E1 > &  e1,
const detail::expr< E2 > &  e2 
) [inline]

UND-verknüpft die Ausdrücke e1 und e2.

Der resultierende Filter liefert für einen Eintrag e true, gdw: (e1(e) != 0) && (e2(e) != 0)

Beispiel-Benutzung:
 bool filter1(const std::string&); 
 bool filter2(const std::string&);
 ...
 filter_base* f = expr_f( op(&filter1) && op(&filter2) );
 ...
 delete f;

template<class E>
detail::expr<detail::expr_not_v<E> > dirstr::operator! ( const detail::expr< E > &  e  )  [inline]

Negiert den Filter der durch den Ausdruck e repräsentiert wird.

Der resultierende Filter liefert für einen Eintrag entry true, gdw: e(entry) == false

Benutzung:
 bool filter1(const std::string&); 
 ...
 filter_base* f = expr_f( !op(&filter1) );
 delete f;

template<class E1, class E2>
detail::expr<detail::expr_binary_v<E1, E2, detail::xor_op> > dirstr::operator^ ( const detail::expr< E1 > &  e1,
const detail::expr< E2 > &  e2 
) [inline]

XOR-verknüpft die Ausdrücke e1 und e2.

Der resultierende Filter liefert für einen Eintrag e true, gdw: (e1(e) != 0) ^ (e2(e) != 0)

See also:
operator && (const detail::expr<E1>& e1, const detail::expr<E2>& e2)

template<class E1, class E2>
detail::expr<detail::expr_binary_v<E1, E2, detail::or_op> > dirstr::operator|| ( const detail::expr< E1 > &  e1,
const detail::expr< E2 > &  e2 
) [inline]

ODER-verknüpft die Ausdrücke e1 und e2.

Der resultierende Filter liefert für einen Eintrag e true, gdw: (e1(e) != 0) || (e2(e) != 0)

See also:
operator && (const detail::expr<E1>& e1, const detail::expr<E2>& e2)


Generated on Fri Apr 27 13:12:36 2007 for Highlight Code Converter by  doxygen 1.5.2