1 // File Description
2 /// \file PbiFilter.h
3 /// \brief Defines the PbiFilter class & helper 'concept'.
4 //
5 // Author: Derek Barnett
6 
7 #ifndef PBIFILTER_H
8 #define PBIFILTER_H
9 
10 #include <boost/concept_check.hpp>
11 #include <cstddef>
12 #include <memory>
13 #include <string>
14 #include <tuple>
15 #include "pbbam/DataSet.h"
16 #include "pbbam/PbiBasicTypes.h"
17 #include "pbbam/PbiRawData.h"
18 #include "pbbam/Unused.h"
19 
20 namespace PacBio {
21 namespace BAM {
22 
23 namespace internal {
24 struct PbiFilterPrivate;
25 }
26 
27 /// \brief The PbiFilterConcept class provides compile-time enforcement of the
28 ///        required interface for PbiFilter's child filters.
29 ///
30 template <typename T>
31 struct PbiFilterConcept
32 {
BOOST_CONCEPT_USAGEPbiFilterConcept33     BOOST_CONCEPT_USAGE(PbiFilterConcept)
34     {
35         // All PBI filters (built-in or client-define) need only provide this
36         // interface:
37         //
38         //    bool Accepts(const PbiRawData& index, const size_t row) const;
39         //
40         PbiRawData index;
41         auto result = filter.Accepts(index, 0);
42         UNUSED(result);
43     }
44 
45 private:
46     T filter;
47     //    PbiRawData index;
48 };
49 
50 /// \brief The PbiFilter class provides a mechanism for performing PBI-enabled
51 ///        lookups.
52 ///
53 /// The PbiFilter API is designed to be flexible, both built-in and for
54 /// client-side customization. Built-in filters are provided for common queries,
55 /// and client code can define and use custom filters as well. More complex
56 /// filtering rules can be constructed via composition of simpler child filters.
57 ///
58 /// Filter objects used as children of PbiFilter need only provide a method that
59 /// matches this signature:
60 ///
61 /// \include code/PbiFilter_Interface.txt
62 ///
63 /// This requirement is enforced internally, using the PbiFilterConcept to
64 /// require a compatible interface without requiring inheritance. This approach
65 /// allows composition of heterogeneous filter types without worrying about a
66 /// class hierarchy, pointer ownership across library/client boundaries, etc.
67 ///
68 /// Thus a client application can define a custom filter if the built-in filters
69 /// do not quite meet requirements. This filter may then be used in further
70 /// PbiFilter composition, or directly to PbiFilterQuery
71 ///
72 /// \include code/PbiFilter_CustomFilter.txt
73 ///
74 /// As mentioned above, complex filters can be built up using multiple "child"
75 /// filters. These complex filters are constructed by using either
76 /// PbiFilter::Union (logical-OR over all direct children) or
77 /// PbiFilter::Intersection (logical-AND over direct children).
78 ///
79 /// \include code/PbiFilter_Composition.txt
80 ///
81 class PBBAM_EXPORT PbiFilter
82 {
83 public:
84     enum CompositionType
85     {
86         INTERSECT,
87         UNION
88     };
89 
90 public:
91     /// \name Set Operations
92     /// \{
93 
94     /// \brief Creates a PbiFilter that acts as an intersection of the input
95     ///        filters.
96     ///
97     /// A record must satisfy \b all of this filter's direct "child" filters.
98     ///
99     /// \param[in] filters  vector of child filters
100     /// \returns composite filter
101     ///
102     static PbiFilter Intersection(std::vector<PbiFilter> filters);
103 
104     /// \brief Creates a PbiFilter that acts as a union of the input filters.
105     ///
106     /// A record must satisfy \b any of this filter's direct "child" filters.
107     ///
108     /// \param[in] filters  vector of child filters
109     /// \returns composite filter
110     ///
111     static PbiFilter Union(std::vector<PbiFilter> filters);
112 
113     /// \}
114 
115 public:
116     /// \name Constructors & Related Methods
117     /// \{
118 
119     /// \brief Creates a PbiFilter from a %DataSet's described filters.
120     ///
121     /// A DataSet may contain a Filters element, itself a list of Filter
122     /// elements. Each Filter element will contain a Properties element, itself
123     /// a list of Property elements.
124     ///
125     /// The Filters hierarchy looks like this (in its XML output):
126     /// \verbinclude examples/plaintext/PbiFilter_DataSetXmlFilters.txt
127     ///
128     /// The resulting PbiFilter represents a union over all Filter elements,
129     /// with each Filter element requiring an intersection of all of its
130     /// Property criteria. These Property elements are mapped to built-in PBI
131     /// filter types. To use the labels in the example XML above, the filter
132     /// created here is equivalent to:
133     ///
134     /// (A && B) || (C && D)
135     ///
136     /// If a DataSet lacks any Filters, then an empty PbiFilter will be created
137     /// - corresponding to the dataset's entire contents.
138     ///
139     /// \param[in] dataset  maybe containing filters
140     /// \returns composite filter
141     ///
142     static PbiFilter FromDataSet(const DataSet& dataset);
143 
144 public:
145     /// \brief Creates an empty filter.
146     ///
147     /// \note An empty filter will result in all records being returned, e.g.
148     ///       for query iteration.
149     ///
150     /// \param[in] type composition type. Any additional child filters added to
151     ///                 this composite will be treated according to this type.
152     ///                 If INTERSECT, a record must match all child filters. If
153     ///                 UNION, a record must match any child filter.
154     ///
155     PbiFilter(const CompositionType type = INTERSECT);
156 
157     /// \brief Creates a composite filter (of INTERSECT type) with an initial
158     ///        child filter.
159     ///
160     /// \note T must satisfy PbiFilterConcept
161     ///
162     /// \param[in] filter initial child filter
163     ///
164     template <typename T>
165     PbiFilter(T filter);
166 
167     /// \brief Creates composite filter (of INTERSECT type) with a list of
168     ///        initial child filters.
169     ///
170     /// \param[in] filters initial child filters
171     ///
172     PbiFilter(std::vector<PbiFilter> filters);
173 
174     PbiFilter(const PbiFilter&);
175     PbiFilter(PbiFilter&&) noexcept = default;
176     PbiFilter& operator=(const PbiFilter&);
177     PbiFilter& operator=(PbiFilter&&) noexcept = default;
178     ~PbiFilter() = default;
179 
180     /// \}
181 
182 public:
183     /// \name Composition
184     /// \{
185 
186     /// \brief Adds a new child filter of type T.
187     ///
188     /// \param[in] filter   additional child filter. Type T must satisfy
189     ///                     PbiFilterConcept.
190     /// \returns reference to this filter
191     ///
192     template <typename T>
193     PbiFilter& Add(T filter);
194 
195     /// \brief Adds a new child filter.
196     ///
197     /// \param[in] filter   additional child filter
198     /// \returns reference to this filter
199     ///
200     PbiFilter& Add(PbiFilter filter);
201 
202     /// \brief Add child filters.
203     ///
204     /// \param[in] filters  additional child filters
205     /// \returns reference to this filter
206     ///
207     PbiFilter& Add(std::vector<PbiFilter> filters);
208 
209     /// \returns true if this filter has no child filters.
210     bool IsEmpty() const;
211 
212     /// \returns number of child filters
213     size_t NumChildren() const;
214 
215     /// \returns filter type (intersect, union)
216     CompositionType Type() const;
217 
218     /// \}
219 
220 public:
221     /// \name Lookup
222     /// \{
223 
224     /// \brief Performs the PBI index lookup, combining child results a
225     ///        composite filter.
226     ///
227     /// \param[in] idx  PBI (raw) index object
228     /// \param[in] row  record number in %BAM/PBI files
229     ///
230     /// \returns true if record at \p row passes this filter criteria,
231     ///          including children (if any)
232     ///
233     bool Accepts(const BAM::PbiRawData& idx, const size_t row) const;
234 
235     /// \}
236 
237 private:
238     std::unique_ptr<internal::PbiFilterPrivate> d_;
239 };
240 
241 }  // namespace BAM
242 }  // namespace PacBio
243 
244 #include "pbbam/PbiFilterTypes.h"
245 #include "pbbam/internal/PbiFilter.inl"
246 
247 #endif  // PBIFILTER_H
248