1 #pragma once
2 #ifndef CATA_SRC_ITEM_SEARCH_H
3 #define CATA_SRC_ITEM_SEARCH_H
4 
5 #include <algorithm>
6 #include <cstddef>
7 #include <functional>
8 #include <iosfwd>
9 #include <string>
10 #include <vector>
11 
12 #include "output.h"
13 
14 /**
15  * Get a function that returns true if the value matches the query.
16  */
17 template<typename T>
filter_from_string(std::string filter,std::function<std::function<bool (const T &)> (const std::string &)> basic_filter)18 std::function<bool( const T & )> filter_from_string( std::string filter,
19         std::function<std::function<bool( const T & )>( const std::string & )> basic_filter )
20 {
21     if( filter.empty() ) {
22         // Variable without name prevents unused parameter warning
23         return []( const T & ) {
24             return true;
25         };
26     }
27 
28     // remove curly braces (they only get in the way)
29     if( filter.find( '{' ) != std::string::npos ) {
30         filter.erase( std::remove( filter.begin(), filter.end(), '{' ), filter.end() );
31     }
32     if( filter.find( '}' ) != std::string::npos ) {
33         filter.erase( std::remove( filter.begin(), filter.end(), '}' ), filter.end() );
34     }
35     if( filter.find( ',' ) != std::string::npos ) {
36         // functions which only one of which must return true
37         std::vector<std::function<bool( const T & )> > functions;
38         // Functions that must all return true
39         std::vector<std::function<bool( const T & )> > inv_functions;
40         size_t comma = filter.find( ',' );
41         while( !filter.empty() ) {
42             const auto &current_filter = trim( filter.substr( 0, comma ) );
43             if( !current_filter.empty() ) {
44                 auto current_func = filter_from_string( current_filter, basic_filter );
45                 if( current_filter[0] == '-' ) {
46                     inv_functions.push_back( current_func );
47                 } else {
48                     functions.push_back( current_func );
49                 }
50             }
51             if( comma != std::string::npos ) {
52                 filter = trim( filter.substr( comma + 1 ) );
53                 comma = filter.find( ',' );
54             } else {
55                 break;
56             }
57         }
58 
59         return [functions, inv_functions]( const T & it ) {
60             auto apply = [&]( const std::function<bool( const T & )> &func ) {
61                 return func( it );
62             };
63             const bool p_result = std::any_of( functions.begin(), functions.end(),
64                                                apply );
65             const bool n_result = std::all_of(
66                                       inv_functions.begin(),
67                                       inv_functions.end(),
68                                       apply );
69             if( !functions.empty() && inv_functions.empty() ) {
70                 return p_result;
71             }
72             if( functions.empty() && !inv_functions.empty() ) {
73                 return n_result;
74             }
75             return p_result && n_result;
76         };
77     }
78     const bool exclude = filter[0] == '-';
79     if( exclude ) {
80         return [filter, basic_filter]( const T & i ) {
81             return !filter_from_string( filter.substr( 1 ), basic_filter )( i );
82         };
83     }
84 
85     return basic_filter( filter );
86 }
87 
88 class item;
89 
90 /**
91  * Get a function that returns true if the item matches the query.
92  */
93 std::function<bool( const item & )> item_filter_from_string( const std::string &filter );
94 
95 /**
96  * Get a function that returns true if the value matches the basic query (no commas or minuses).
97  */
98 std::function<bool( const item & )> basic_item_filter( std::string filter );
99 
100 #endif // CATA_SRC_ITEM_SEARCH_H
101