filter_utils_impl.h

00001 
00002 //      file            :       filter_utils_imp.h
00003 //  copyright   :       (C) 2002-2004 Benjamin Kaufmann
00004 //  email               :       hume@c-plusplus.de
00005 //      internet        :       http://bens.c-plusplus.info/
00006 //
00007 //  Implementation des Filter-Combiner Frameworks
00008 //      Achtung: Sämtliche Klassen die in dieser Datei definiert werden sind
00009 //  als Implementationsdetails anzusehen. Sie sollten niemals explizit
00010 //      verwendet werden.
00012 #ifndef FILTER_UTILS_H_INCLUDED
00013 #error dirstream.filterutils - Do not include this file directly! Include fiter_utils.h instead.
00014 #endif
00015 #ifndef FILTER_UTILS_IMPL_H_INCLUDED
00016 #define FILTER_UTILS_IMPL_H_INCLUDED
00017 #include "../smartpointer.h"
00018 #include "../filter_base.h"
00019 #include "filter_asserter.h"
00020 #include <memory>
00021 namespace dirstr { namespace detail {
00023 // Implementation der konkreten binären Operationen
00025         struct and_op
00026         {
00027                 template <class F1, class F2>
00028                 bool operator()(const F1& f1, const F2& f2, const std::string& str) const
00029                 {
00030                         return (f1(str) != 0) && (f2(str) != 0);
00031                 }
00032         };
00033         struct or_op
00034         {
00035                 template <class F1, class F2>
00036                 bool operator()(const F1& f1, const F2& f2, const std::string& str) const
00037                 {
00038                         return (f1(str) != 0) || (f2(str) != 0);
00039                 }
00040         };
00041         struct xor_op
00042         {
00043                 template <class F1, class F2>
00044                 bool operator()(const F1& f1, const F2& f2, const std::string& str) const
00045                 {
00046                         return (f1(str) != 0) ^ (f2(str) != 0);
00047                 }
00048         };
00049 
00051 // Implementation der expr-Traits
00053 #if defined(_MSC_VER) && _MSC_VER <= 1200
00054         template <class Op1, class Op2>
00055         struct assert_equal_op
00056         {
00057                 template <bool b> struct operation_types_not_equal;
00058                 template <> struct operation_types_not_equal<true> {typedef int type;};
00059                 static char test(const Op1&);
00060                 static char (&test(...))[2];
00061                 enum {result = sizeof(test(Op2()))};
00062                 typedef operation_types_not_equal<result == 1>::type type;
00063         };
00064 #endif
00065         template <class F1, class F2, class Op> struct expr_binary_v;
00066         template <class F1, class F2, class Op> struct expr_binary_s;
00067         template <class F> struct expr_not_v;
00068         template <class F> struct expr_not_s;
00069 
00070 
00071         struct ptr_checker
00072         {
00073         public:
00074                 static char (&test(const volatile dirstr::filter_base*))[2];
00075                 static char (&test(const volatile void*))[6];
00076         };
00077 
00078         template <int> struct expr_traits_impl;
00079         struct expr_traits_types
00080         {
00081                 enum {
00082                         filter                                  = sizeof(char),         // filter_base-Objekte, Prädikate, Funktionszeiger
00083                         ptr_filter_base                 = sizeof(char[2]),      // filter_base*-kompatible Pointer
00084                         shared_ptr_filter_base  = sizeof(char[3]),      // SharedPtr<T> mit T = filter_base*-kompatibel
00085                         shared_ptr_other                = sizeof(char[4]),      // SharedPtr<T>
00086                         expression                              = sizeof(char[5]),      // and, or, xor, not
00087                         ptr_other                               = sizeof(char[6]),      // allgemeine Pointer 
00088                         shared_ptr_select               = sizeof(char[99]),     
00089                         ptr_select                              = sizeof(char[100])
00090                 };
00091         };
00092 
00093         // Traits für Filter-Prädikate oder Filter-Funktionen, z.B. op(EinFilter())
00094         // Filter werden immer im top-level-Ausdruck gebunden, können
00095         // deshalb per Referenz gehalten werden.
00096         // Im endgültigen Filter-Objekt werden solche Filter "by-value" gehalten
00097         // und über ihren Copy-Ctor kopiert.
00098         // ACHTUNG: Im Falle von Filter-Hierarchien droht hier slicing!
00099         // Z.B.
00100         // class FilterA {...};
00101         // class FilterB : public FilterA {};
00102         // FilterB b;
00103         // FilterA& a = b;
00104         // op(a)        -> Slicing. Ein FilterB-Objekt wird zu einem FilterA!
00105         template <>
00106         struct expr_traits_impl<expr_traits_types::filter>
00107         {
00108                 template <class T>
00109                 struct in : assert_is_filter<T>
00110                 {
00111                         typedef T copy_type;
00112                         typedef const T& ref_t;
00113                         static const T& transform(const T& t) {return t;}
00114                         static const T& filter_obj(const T& t)
00115                         {
00116                                 return t;
00117                         }
00118                 };
00119         };
00120 
00121         // Traits für Pointer die nach filter_base* konvertiert werden können.
00122         // Im endgültigen Filter-Objekt wird ein Klon des Objekts per SharedPtr<filter_base>
00123         // gehalten.
00124         template <>
00125         struct expr_traits_impl<expr_traits_types::ptr_filter_base>
00126         {
00127                 template <class T>      // filter_base*
00128                 struct in
00129                 {
00130                         typedef T ref_t;
00131                         typedef SharedPtr<dirstr::filter_base> copy_type;
00132                         static copy_type transform(const T& t)
00133                         {
00134                                 return SharedPtr<dirstr::filter_base>(t->clone());
00135                         }
00136                         static const filter_base& filter_obj(filter_base* t)
00137                         {
00138                                 return *t;
00139                         }
00140                 };
00141                 enum {is_filter = 1};
00142         };
00143 
00144         // Traits für Objekt-Pointer die nicht nach filter_base* konvertiert werden können.
00145         // Da die Unterstützung solcher Pointer auf Compilern ohne partielle Template-
00146         // Spezialisierung einen extra Trick erfordert, dessen Implementation
00147         // einen hohen Aufwand bedeutet, werden allgemeine Zeiger zur Zeit nicht unterstützt.
00148         template <>
00149         struct expr_traits_impl<expr_traits_types::ptr_other>
00150         {
00151                 template <class T>      // T*
00152                 struct in : assert_is_filter<typename T::PLAIN_POINTER_NOT_SUPPORTED>
00153                 {
00154 
00155                 };
00156         };
00157 
00158         // Traits für SharedPtr-Objekte die ein filter_base-Objekt enthalten.
00159         // Kopieren bedeutet klonen des enthaltenen Filter-Objekts.
00160         template <>
00161         struct expr_traits_impl<expr_traits_types::shared_ptr_filter_base>
00162         {
00163                 template <class T>
00164                 struct in
00165                 {
00166                         typedef T ref_t;
00167                         typedef T copy_type;
00168                         static copy_type transform(const T& t)
00169                         {
00170                                 return copy_type(t->clone());
00171                         }
00172                 };
00173         };
00174 
00175         // Traits für alle anderen SharedPtr<T>-Objekte.
00176         // Kopieren bedeutet Allokation eines neuen Heap-Objekts das über den
00177         // Copy-Ctor von T initialisiert wird.
00178         // ACHTUNG: Im Falle von Filter-Hierarchien die nicht filter_base
00179         // als ihre Basisklasse haben, droht hier slicing!
00180         // Z.B.
00181         // class FilterA {...};
00182         // class FilterB : public FilterA {};
00183         // SharedPtr<FilterA> af( new FilterB() );
00184         // op(af)       -> Slicing. Ein FilterB-Objekt wird zu einem FilterA!
00185         template <>
00186         struct expr_traits_impl<expr_traits_types::shared_ptr_other>
00187         {
00188                 template <class T>
00189                 struct in
00190                 {
00191                         typedef T ref_t;
00192                         typedef typename T::VT VT;
00193                         typedef T copy_type;
00194                         static copy_type transform(const T& t)
00195                         {
00196                                 enum {r = assert_is_filter<VT>::T_IS_NOT_A_VALID_FILTER};
00197                                 return copy_type(new VT(*t));
00198                         }
00199                 };
00200         };
00201 
00202         // Selektor für SharedPtr<T>-Objekte.
00203         // Abhängig von T wird entweder nach shared_ptr_filter_base (T ist ein
00204         // von filter_base abgeleiteter Typ) oder shared_ptr_other
00205         // verzweigt.
00206         template <>
00207         struct expr_traits_impl<expr_traits_types::shared_ptr_select>
00208         {
00209                 template <class T>
00210                 struct in
00211                 {
00212                 private:
00213                         typedef typename T::PT PT;
00214                         typedef typename T::VT VT;
00215             enum {temp = sizeof( ptr_checker::test( (PT)0 ) ) };
00216                         enum {result = temp == (unsigned) expr_traits_types::ptr_filter_base ?
00217                                         expr_traits_types::shared_ptr_filter_base
00218                                         : expr_traits_types::shared_ptr_other
00219                         };
00220                 public:
00221                         typedef T copy_type;
00222                         typedef T ref_t;
00223                         static copy_type transform(const T& t)
00224                         {
00225                                 return expr_traits_impl<result>::template in<T>::transform(t);
00226                         }
00227                         static const VT& filter_obj(const T& t)
00228                         {
00229                                 return *t;
00230                         }
00231                 };
00232         };
00233 
00234         // Selektor für Objekt-Ptr.
00235         // Abhängig von T wird entweder nach ptr_filter_base (T ist ein
00236         // von filter_base*-kompatibler Pointer) oder ptr_other
00237         // verzweigt.
00238         template <>
00239         struct expr_traits_impl<expr_traits_types::ptr_select>
00240         {
00241                 template <class T>      // T*
00242                 struct in
00243                 {
00244                 public:
00245                         enum {result = sizeof( ptr_checker::test( (T)0 ) )};
00246                         enum {PLAIN_POINTER_NOT_SUPPORTED = expr_traits_impl<result>::is_filter};
00247                         typedef SharedPtr<dirstr::filter_base> copy_type;
00248                         typedef T ref_t;
00249                         static copy_type transform(const T& t)
00250                         {
00251                                 return expr_traits_impl<result>::template in<T>::transform(t);
00252                         }
00253                         static const filter_base& filter_obj(const T& t)
00254                         {
00255                                 return expr_traits_impl<result>::template in<T>::filter_obj(t);
00256                         }
00257                 };
00258         };
00259 
00260         // Traits für flüchtige Expression-Ausdrücke wie expr_and_v oder expr_or_v.
00261         // Da diese Objekte zum Teil erst in den operator-Funktionen erzeugt werden,
00262         // können sie nicht per Referenz sondern müssen "by value" gehalten werden.
00263         template <>
00264         struct expr_traits_impl<expr_traits_types::expression>
00265         {
00266                 template <class T>      // e.g. exp_and_v
00267                 struct in
00268                 {
00269                         typedef T ref_t;
00270                         typedef typename T::copy_type copy_type;
00271                         static const T& transform(const T& t)
00272                         {
00273                                 return t;
00274                         }
00275                 };
00276         };
00277 
00278 
00279         template <class T>
00280         struct impl_checker
00281         {
00282                 struct A {};
00283                 struct B : public A {};
00284                 template <class E1, class E2, class Op>
00285                 static char (&test(const expr_binary_v<E1, E2, Op>&, B))[5];
00286                 template <class E>
00287                 static char (&test(const expr_not_v<E>&, B))[5];
00288                 template <class V>
00289                 static char (&test(const SharedPtr<V>&, B))[99];
00290 
00291                 template <class Z>
00292                 static char (&test(Z*, B))[100];
00293                 template <class Z>
00294                 static char test(Z z, A);
00295                 template <class R, class A1>
00296                 static char test( R (*)(A1), B);
00297         };
00298         template <class T>
00299         struct expr_traits_selector
00300         {
00301         public:
00302                 enum {result = sizeof( impl_checker<T>::test( maker<T>::make_t(), impl_checker<T>::B() ) )};
00303                 typedef typename expr_traits_impl<result>::template in<T> type;
00304         };
00305         template <class T>
00306         struct expr_traits : expr_traits_selector<T>::type
00307         {
00308                 typedef typename dirstr::detail::expr_traits_selector<T>::type base_t;
00309                 typedef typename base_t::copy_type copy_type;
00310         };
00311 
00313 //      Expression Klassen
00315 // Bei der Konstruktion von Filter-Ausdrücken werden zwei Phasen unterschieden.
00316 // Die erste Phase umfasst die Zusammensetzung des endgültigen Ausdrucks.
00317 // In dieser Phase werden Objekte der Klassen expr und *_v verwendet.
00318 // Diese Klassen halten ihre Filter per Referenz. In dieser Phase
00319 // werden also keinerlei Kopien erzeugt. Das heißt aber auch, dass solche
00320 // Objekte nur innerhalb der vollständigen Ausdrucks gültig sind
00321 // (das _v steht für 'volatile' und soll darauf hinweisen, dass die Objekte 
00322 // "flüchtig", also nur für einen kurzen Zeitraum gültig sind).
00323 //
00324 // In der zweiten Phase wird ein fertiger Ausdruck transformiert und dabei
00325 // in ein Objekt einer von filter_base abgeleiteten Klasse umgewandelt.
00326 // Bei der Transformation werden aus den *_v-Klassen *_s-Klassen. Diese Klassen
00327 // halten ihre Filter "by value". Bei der Transformation von *_v-Objekten in
00328 // *_s-Objekte werden referenzierte Filter kopiert (das _s steht für 'stable' und
00329 // soll darauf hinweisen, dass Objekte dieser Klassen auch außerhalb des erzeugenden
00330 // Ausdrucks gültig sind).
00331 // 
00332 // Beispielablauf:
00333 //
00334 //      A sei ein Filterprädikat, B eine von filter_base abgeleitete Klasse
00335 //
00336 //      B* b = new B;
00337 //  filter_base* f = expr_f( op(A()) && op(b) );
00338 //      delete b;
00339 //
00340 //  Phase 1: Erzeugung des boole'schen Ausdrucks:
00341 //      zu beachten: das temporäre Objekte das durch A() erzeugt wird
00342 //      lebt nur bis zum Ende der "full-expression" (bis zum Semikolon ;)
00343 //      * op(A()) -> expr<A>: referenziert das temporäre A-Objekt
00344 //  * op(b)   -> expr<B*>: kopiert den Pointer b
00345 //      * expr<A> && expr<B*> -> expr<exr_binary_v<A, B*, and_op> >
00346 //      
00347 //  Phase 2: Transformation
00348 //      Die zweite Phase wird durch die Übergabe des endgültigen expr-Objekts
00349 //      an die Funktion expr_f bzw. an einen dirstream-Ctor eingeleitet.
00350 //      * (expr<exr_binary_v<A, B*, and_op> >).clone() -> new expr_f_t< expr_binary_s<A, SharedPtr<B>, and_op> >
00351 //      * exr_binary_v<A, B*, and_op> -> expr_binary_s<A, SharedPtr<B>, and_op>
00352 //              * Das A-Objekt wird über seinen Copy-Ctor kopiert.
00353 //              * Das SharedPtr<B>-Objekt wird über b->clone() initialisiert
00354 //      
00355 
00356 
00357         // Repräsentiert eine binäre-Operation im temporären Ausdruck.
00358         // Element-Filter werden in der Regel nur referenziert!
00359         template <class F1, class F2, class Op>
00360         struct expr_binary_v
00361         {
00362                 expr_binary_v(const F1& f1, const F2& f2)
00363         : f1_(f1)
00364         , f2_(f2)
00365                 {}
00366 
00367                 typedef F1 left_type;
00368                 typedef F2 right_type;
00369                 typedef Op op_type;
00370                 typedef typename expr_traits<F1>::copy_type copy_type_e1;
00371                 typedef typename expr_traits<F2>::copy_type copy_type_e2;
00372                 typedef expr_binary_s<copy_type_e1, copy_type_e2, Op> copy_type;
00373                 typename expr_traits<F1>::ref_t f1_;
00374                 typename expr_traits<F2>::ref_t f2_;
00375         };
00376 
00377         // Repräsentiert eine not-Operation im temporären Ausdruck
00378         template <class F>
00379         struct expr_not_v
00380         {
00381                 expr_not_v(const F& f1)
00382         : f_(f1)
00383                 {}
00384                 typedef F inner_type;
00385                 typedef typename expr_traits<F>::copy_type copy_type_e;
00386                 typedef expr_not_s<copy_type_e> copy_type;
00387                 typename expr_traits<F>::ref_t f_;
00388         };
00389 
00390         // Repräsentiert eine binäre Operation im endgültigen Filter
00391         // expr_binary_s besitzt nur einen Copy-Ctor (wird für das Klonen von
00392         // Filtern benötigt) und einen Initialisierungskonstruktor der ein
00393         // expr_binary_s aus einem expr_binary_v-Objekt erzeugt.
00394         // Bei der Konstruktion eines expr_binary_s-Objekts aus einem 
00395         // expr_binary_v-Objekt werden beide Teilausdrücke des
00396         // expr_binary_v-Objekts zuvor transformiert.
00397         // Transformation bedeutet kopieren der Element-Filter 
00398         // siehe expr_traits
00399         template <class F1, class F2, class Op>
00400         struct expr_binary_s
00401         {
00402 #if defined(_MSC_VER) && _MSC_VER <= 1200
00403                 
00404                 // Workaround für den VC 6.0
00405                 // Dieser Workaround ist nötig, da der VC 6.0 in Anwesenheit eines
00406                 // Template-Ctors der Form expr_binary_s(const expr_binary_v<OF1, OF2, Op>& o)
00407                 // es versäumt Code für den Copy-Ctor zu generieren.
00408                 template <class Exp>
00409                 expr_binary_s(const Exp& e)
00410                         : f1_(expr_traits<Exp::left_type>::transform(e.f1_))
00411                         , f2_(expr_traits<Exp::right_type>::transform(e.f2_))
00412                 {
00413                         assert_equal_op<Op, Exp::op_type>::result;
00414                 }
00415 #else
00416                 template <class OF1, class OF2>
00417                 expr_binary_s(const expr_binary_v<OF1, OF2, Op>& o)
00418                         : f1_(expr_traits<OF1>::transform(o.f1_))
00419                         , f2_(expr_traits<OF2>::transform(o.f2_))
00420                 {}
00421 #endif
00422                 expr_binary_s(const expr_binary_s& o)
00423                         : f1_(expr_traits<F1>::transform(o.f1_))
00424                         , f2_(expr_traits<F2>::transform(o.f2_))
00425                 {}
00426 
00427                 bool operator()(const std::string& str) const
00428                 {
00429                         return Op()(expr_traits<F1>::filter_obj(f1_),
00430                                                 expr_traits<F2>::filter_obj(f2_),
00431                                                 str);
00432                 }
00433         private:
00434                 F1 f1_; // im endgültigen Filter-Objekt werden die beiden Teilausdrücke
00435                 F2 f2_; // immer "by value" gehalten.
00436         };
00437 
00438         // Repräsentiert eine not-Operation im endgültigen Filter.
00439         // siehe expr_binary_s
00440         template <class F>
00441         struct expr_not_s
00442         {
00443 #if defined(_MSC_VER) && _MSC_VER <= 1200
00444                 template <class Exp>
00445                 expr_not_s(const Exp& e)
00446                         : f_(expr_traits<Exp::inner_type>::transform(e.f_))
00447                 {}
00448 #else
00449                 template <class OF>
00450                 expr_not_s(const expr_not_v<OF>& o)
00451                         : f_(expr_traits<OF>::transform(o.f_))
00452                 {}
00453 #endif
00454                 expr_not_s(const expr_not_s& o)
00455                         : f_(expr_traits<F>::transform(o.f_))
00456                 {}
00457 
00458                 bool operator()(const std::string& str) const
00459                 {
00460                         return  !expr_traits<F>::filter_obj(f_)(str);
00461                 }
00462         private:
00463                 F f_;
00464         };
00465 
00466         template <class F> 
00467         struct expr;
00468 
00469         // Endgültige Filter-Klasse für Filter-Ausdrücke.
00470         // Objekte dieser Klassen halten *Kopien* der Element-Filter.
00471         template <class Exp>
00472         class expr_f_t : public filter_base
00473         {
00474                         // template <class T> friend class expr;
00475         public: // sollte private: sein, aber zuviele Compiler haben Probleme mit Template-Friends
00476                 template <class OExp>
00477                 expr_f_t(const detail::expr<OExp>& other)
00478                         : exp_(detail::expr_traits<OExp>::transform(other.f_))
00479                 {}
00480         public:
00481                 expr_f_t(const expr_f_t& other)
00482                         : exp_(detail::expr_traits<Exp>::transform(other.exp_))
00483                 {}
00484                 
00485                 bool operator()(const std::string& str) const
00486                 {
00487                         return detail::expr_traits<Exp>::filter_obj(exp_)(str);
00488                 }
00489                 filter_base* clone() const
00490                 {
00491                         return new expr_f_t(*this);
00492                 }
00493         private:
00494                 Exp exp_;
00495         };
00496 
00497         
00498         // Objekte dieser Klasse werden beim Zusammenbau von boole'schen Ausdrücken
00499         // erzeugt. Das Endergebnis eines boole'schen Ausdrucks ist
00500         // ebenfalls ein (temporäres) Objekt dieser Klasse.
00501         // Achtung: 
00502         //      Element-Filter werden von expr<T>-Objekten nur per Referenz gehalten.
00503         //      Diese Referenzen sind in der Regel nur bis zum Ende des
00504         //      vollständigen Ausdrucks in dem das expr<T>-Objekt erzeugt wurde gültig.
00505         //      expr<T>-Objekte sollten *niemals* explizit verwendet oder kopiert werden.
00506         //      expr<T>-Objekte sollten nur als anonyme temporäre Objekte verwendet werden und
00507         //      das auch nur in drei Situationen:
00508         //      a) Als Operand für einen logischen Operator
00509         //      Bsp: op(a) && op(b) && op(c) 
00510         //
00511         //      b) Als Argument für einen dirstream-Ctor bzw. einer dirstream::open-Funktion
00512         //      Bsp: dirstream str(".", op(a) && op(b));
00513         //
00514         //      c) Als Argument für die Funktion expr_f
00515         //
00516         // Insbesondere ist die mögliche Konvertierung nach filter_base nur 
00517         // ein Implementationsdetail von der niemals explizit gebrauch gemacht
00518         // werden soll (Ausnahme siehe b) ).
00519         // Code wie:
00520         // const filter_base& f = op(a) && op(b);
00521         // ...
00522         // führt garantiert früher oder später zu einer Katastrophe.
00523         template <class F> 
00524         struct expr : public filter_base
00525         {
00526         public:
00527                 expr(const F& f)
00528                         : f_(f)
00529                 {}
00530                 // Transformiert den Filter-Ausdruck in ein reguläres filter_base-Objekt
00531                 dirstr::filter_base* clone() const
00532                 {
00533                         typedef typename detail::expr_traits<F>::copy_type copy_type;
00534                         return new dirstr::detail::expr_f_t<copy_type>(*this);                  
00535                 }
00536                 
00537                 // Sollte *niemals* aufgerufen werden.
00538                 bool operator()(const std::string& str) const
00539                 {
00540                         std::auto_ptr<filter_base> f(this->clone());
00541                         return (*f)(str);
00542                 }
00543                 typename detail::expr_traits<F>::ref_t f_;
00544         };
00545         
00546 
00547 }       } // namespace dirstr::detail
00548 
00549 #endif

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