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