remwharead  0.9.1
Public Member Functions | List of all members
remwharead::Search Class Reference

Search in database entries. More...

#include <remwharead/search.hpp>

Public Member Functions

 Search (list< Database::entry > entries)
 Defines the entries to search. More...
 
list< Database::entrysearch_tags (const string &expression, bool is_re) const
 Search in tags of database entries. More...
 
list< Database::entrysearch_all (const string &expression, bool is_re) const
 Search in full text of database entries. More...
 
list< Database::entrysearch_all_threaded (const string &expression, bool is_re) const
 Spawn threads of search_all(), if it seems sensible. More...
 

Detailed Description

Search in database entries.

Since
0.7.0

Constructor & Destructor Documentation

◆ Search()

remwharead::Search::Search ( list< Database::entry entries)
explicit

Defines the entries to search.

Since
0.7.0
37  :_entries(move(entries))
38 {}

Member Function Documentation

◆ search_all()

list< Database::entry > remwharead::Search::search_all ( const string &  expression,
bool  is_re 
) const

Search in full text of database entries.

Searches in tags, title, description and full text.

Parameters
expressionSearch expression.
is_reIs it a regular expression?
Returns
List of matching Database::entry.
Since
0.7.0
130 {
131  vector<vector<string>> searchlist = parse_expression(expression);
132  list<Database::entry> result = search_tags(expression, is_re);
133 
134  for (const vector<string> &terms_or : searchlist)
135  {
136  for (const Database::entry &entry : _entries)
137  {
138  // Add entry to result if all terms in an OR-slice match title,
139  // description or full text.
140  bool matched_title = true;
141  bool matched_description = true;
142  bool matched_fulltext = true;
143 
144  const auto it = find(result.begin(), result.end(), entry);
145  if (it != result.end())
146  { // Skip if already in result list.
147  continue;
148  }
149 
150  for (const string &term : terms_or)
151  {
152  const string title = to_lowercase(entry.title);
153  const string description = to_lowercase(entry.description);
154  const string fulltext = to_lowercase(entry.fulltext);
155 
156  // Set matched_* to false if term is not found.
157  if (is_re)
158  {
159  const RegEx re(term);
160 
161  if (!(re == title))
162  {
163  matched_title = false;
164  }
165 
166  if (!(re == description))
167  {
168  matched_description = false;
169  }
170 
171  if (!(re == fulltext))
172  {
173  matched_fulltext = false;
174  }
175  }
176  else
177  {
178  if (title.find(term) == string::npos)
179  {
180  matched_title = false;
181  }
182 
183  if (description.find(term) == string::npos)
184  {
185  matched_description = false;
186  }
187 
188  if (fulltext.find(term) == string::npos)
189  {
190  matched_fulltext = false;
191  }
192  }
193  }
194  if (matched_title || matched_description || matched_fulltext)
195  {
196  result.push_back(entry);
197  }
198  }
199  }
200 
201  return result;
202 }
list< Database::entry > search_tags(const string &expression, bool is_re) const
Search in tags of database entries.
Definition: search.cpp:86

◆ search_all_threaded()

list< Database::entry > remwharead::Search::search_all_threaded ( const string &  expression,
bool  is_re 
) const

Spawn threads of search_all(), if it seems sensible.

Figure out if threads could be useful and spawn a sensible amount of them.

Parameters
expressionSearch expression.
is_reIs it a regular expression?
Returns
List of matching Database::entry.
Since
0.7.2
206 {
207  list<Database::entry> entries = _entries;
208 
209  const size_t len = entries.size();
210  constexpr size_t min_len = 100;
211  constexpr size_t min_per_thread = 50;
212  const size_t n_threads = thread::hardware_concurrency() / 3 + 1;
213  size_t cut_at = len;
214  if (len > min_len)
215  { // If there are over `min_len` entries, use `n_threads` threads.
216  cut_at = len / n_threads;
217 
218  // But don't use less than `min_per_thread` entries per thread.
219  if (cut_at < min_per_thread)
220  {
221  cut_at = min_per_thread;
222  }
223  }
224 
225  list<list<Database::entry>> segments;
226 
227  // Use threads if list is big.
228  while (entries.size() > cut_at)
229  {
230  list<Database::entry> segment;
231 
232  auto it = entries.begin();
233  std::advance(it, cut_at);
234 
235  // Move the first `cut_at` entries into `segments`.
236  segment.splice(segment.begin(), entries, entries.begin(), it);
237  segments.push_back(move(segment));
238  }
239  // Move rest of `entries` into `segments`.
240  list<Database::entry> rest;
241  rest.splice(rest.begin(), entries);
242  segments.push_back(move(rest));
243 
244  list<thread> threads;
245  for (auto &segment : segments)
246  {
247  thread t(
248  [&]
249  {
250  Search search(segment);
251  // Replace `segment` with `result`.
252  segment = search.search_all(expression, is_re);
253  });
254  threads.push_back(move(t));
255  }
256 
257  for (thread &t : threads)
258  {
259  t.join();
260  // Move each of `segments` into `entries`.
261  entries.splice(entries.end(), segments.front());
262  segments.pop_front();
263  }
264 
265  return entries;
266 
267 }
Search(list< Database::entry > entries)
Defines the entries to search.
Definition: search.cpp:36

◆ search_tags()

list< Database::entry > remwharead::Search::search_tags ( const string &  expression,
bool  is_re 
) const

Search in tags of database entries.

Only matches whole tags, Pill does not match Pillow.

Parameters
expressionSearch expression.
is_reIs it a regular expression?
Returns
List of matching Database::entry.
Since
0.7.0
88 {
89  vector<vector<string>> searchlist = parse_expression(expression);
90  list<Database::entry> result;
91 
92  for (const vector<string> &tags_or : searchlist)
93  {
94  for (const Database::entry &entry : _entries)
95  { // Add entry to result if all tags in an OR-slice match.
96  bool matched = true;
97 
98  for (const string &tag : tags_or)
99  {
100  const auto it = find_if(
101  entry.tags.begin(), entry.tags.end(),
102  [&, is_re](string s)
103  {
104  s = to_lowercase(s);
105  if (is_re)
106  {
107  const RegEx re("^" + tag + "$");
108  return (re == s);
109  }
110 
111  return (s == tag);
112  });
113  if (it == entry.tags.end())
114  {
115  matched = false;
116  }
117  }
118  if (matched)
119  {
120  result.push_back(entry);
121  }
122  }
123  }
124 
125  return result;
126 }

The documentation for this class was generated from the following files: