remwharead  0.8.5
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
131 {
132  vector<vector<string>> searchlist = parse_expression(expression);
133  list<Database::entry> result = search_tags(expression, is_re);
134 
135  for (const vector<string> &terms_or : searchlist)
136  {
137  for (const Database::entry &entry : _entries)
138  {
139  // Add entry to result if all terms in an OR-slice match title,
140  // description or full text.
141  bool matched_title = true;
142  bool matched_description = true;
143  bool matched_fulltext = true;
144 
145  const auto it = find(result.begin(), result.end(), entry);
146  if (it != result.end())
147  { // Skip if already in result list.
148  continue;
149  }
150 
151  for (const string &term : terms_or)
152  {
153  const string title = to_lowercase(entry.title);
154  const string description = to_lowercase(entry.description);
155  const string fulltext = to_lowercase(entry.fulltext);
156 
157  // Set matched_* to false if term is not found.
158  if (is_re)
159  {
160  const RegEx re(term);
161 
162  if (!(re == title))
163  {
164  matched_title = false;
165  }
166 
167  if (!(re == description))
168  {
169  matched_description = false;
170  }
171 
172  if (!(re == fulltext))
173  {
174  matched_fulltext = false;
175  }
176  }
177  else
178  {
179  if (title.find(term) == string::npos)
180  {
181  matched_title = false;
182  }
183 
184  if (description.find(term) == string::npos)
185  {
186  matched_description = false;
187  }
188 
189  if (fulltext.find(term) == string::npos)
190  {
191  matched_fulltext = false;
192  }
193  }
194  }
195  if (matched_title || matched_description || matched_fulltext)
196  {
197  result.push_back(entry);
198  }
199  }
200  }
201 
202  return result;
203 }
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
207 {
208  list<Database::entry> entries = _entries;
209 
210  const size_t len = entries.size();
211  constexpr size_t min_len = 100;
212  constexpr size_t min_per_thread = 50;
213  const size_t n_threads = thread::hardware_concurrency() / 3 + 1;
214  size_t cut_at = len;
215  if (len > min_len)
216  { // If there are over `min_len` entries, use `n_threads` threads.
217  cut_at = len / n_threads;
218 
219  // But don't use less than `min_per_thread` entries per thread.
220  if (cut_at < min_per_thread)
221  {
222  cut_at = min_per_thread;
223  }
224  }
225 
226  list<list<Database::entry>> segments;
227 
228  // Use threads if list is big.
229  while (entries.size() > cut_at)
230  {
231  list<Database::entry> segment;
232 
233  auto it = entries.begin();
234  std::advance(it, cut_at);
235 
236  // Move the first `cut_at` entries into `segments`.
237  segment.splice(segment.begin(), entries, entries.begin(), it);
238  segments.push_back(move(segment));
239  }
240  // Move rest of `entries` into `segments`.
241  list<Database::entry> rest;
242  rest.splice(rest.begin(), entries);
243  segments.push_back(move(rest));
244 
245  list<thread> threads;
246  for (auto &segment : segments)
247  {
248  thread t(
249  [&]
250  {
251  Search search(segment);
252  // Replace `segment` with `result`.
253  segment = search.search_all(expression, is_re);
254  });
255  threads.push_back(move(t));
256  }
257 
258  for (thread &t : threads)
259  {
260  t.join();
261  // Move each of `segments` into `entries`.
262  entries.splice(entries.end(), segments.front());
263  segments.pop_front();
264  }
265 
266  return entries;
267 
268 }
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
89 {
90  vector<vector<string>> searchlist = parse_expression(expression);
91  list<Database::entry> result;
92 
93  for (const vector<string> &tags_or : searchlist)
94  {
95  for (const Database::entry &entry : _entries)
96  { // Add entry to result if all tags in an OR-slice match.
97  bool matched = true;
98 
99  for (const string &tag : tags_or)
100  {
101  const auto it = find_if(
102  entry.tags.begin(), entry.tags.end(),
103  [&, is_re](string s)
104  {
105  s = to_lowercase(s);
106  if (is_re)
107  {
108  const RegEx re("^" + tag + "$");
109  return (re == s);
110  }
111 
112  return (s == tag);
113  });
114  if (it == entry.tags.end())
115  {
116  matched = false;
117  }
118  }
119  if (matched)
120  {
121  result.push_back(entry);
122  }
123  }
124  }
125 
126  return result;
127 }

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