xapian-core  2.0.0
keymaker.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2007,2009,2011,2015,2019 Olly Betts
5  * Copyright (C) 2010 Richard Boulton
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include "xapian/keymaker.h"
25 
26 #include "xapian/document.h"
27 #include "xapian/error.h"
28 
29 #include "pack.h"
30 
31 #include <memory>
32 #include <string>
33 
34 using namespace std;
35 
36 namespace Xapian {
37 
38 KeyMaker::~KeyMaker() { }
39 
40 [[noreturn]]
41 static void
42 throw_unimplemented(const char* message)
43 {
44  throw Xapian::UnimplementedError(message);
45 }
46 
47 string
49 {
50  throw_unimplemented("KeyMaker subclass not suitable for use with remote "
51  "searches - name() method not implemented");
52 }
53 
54 string
55 KeyMaker::serialise() const
56 {
57  throw_unimplemented("KeyMaker subclass not suitable for use with remote"
58  "searches - serialise() method not implemented");
59 }
60 
61 KeyMaker*
62 KeyMaker::unserialise(const string&, const Registry&) const
63 {
64  throw_unimplemented("KeyMaker subclass not suitable for use with remote"
65  "searches - unserialise() method not implemented");
66 }
67 
68 string
69 MultiValueKeyMaker::operator()(const Xapian::Document & doc) const
70 {
71  string result;
72 
73  auto i = slots.begin();
74  // Don't crash if slots is empty.
75  if (rare(i == slots.end())) return result;
76 
77  size_t last_not_empty_forwards = 0;
78  while (true) {
79  // All values (except for the last if it's sorted forwards) need to
80  // be adjusted.
81  //
82  // FIXME: allow Xapian::BAD_VALUENO to mean "relevance?"
83  string v = doc.get_value(i->slot);
84  bool reverse_sort = i->reverse;
85 
86  if (v.empty()) {
87  v = i->defvalue;
88  }
89 
90  if (reverse_sort || !v.empty())
91  last_not_empty_forwards = result.size();
92 
93  if (++i == slots.end() && !reverse_sort) {
94  if (v.empty()) {
95  // Trim off all the trailing empty forwards values.
96  result.resize(last_not_empty_forwards);
97  } else {
98  // No need to adjust the last value if it's sorted forwards.
99  result += v;
100  }
101  break;
102  }
103 
104  if (reverse_sort) {
105  // For a reverse ordered value, we subtract each byte from '\xff',
106  // except for '\0' which we convert to "\xff\0". We insert
107  // "\xff\xff" after the encoded value.
108  for (string::const_iterator j = v.begin(); j != v.end(); ++j) {
109  unsigned char ch = static_cast<unsigned char>(*j);
110  result += char(255 - ch);
111  if (ch == 0) result += '\0';
112  }
113  result.append("\xff\xff", 2);
114  if (i == slots.end()) break;
115  last_not_empty_forwards = result.size();
116  } else {
117  // For a forward ordered value (unless it's the last value), we
118  // convert any '\0' to "\0\xff". We insert "\0\0" after the
119  // encoded value.
120  string::size_type j = 0, nul;
121  while ((nul = v.find('\0', j)) != string::npos) {
122  ++nul;
123  result.append(v, j, nul - j);
124  result += '\xff';
125  j = nul;
126  }
127  result.append(v, j, string::npos);
128  if (!v.empty())
129  last_not_empty_forwards = result.size();
130  result.append("\0", 2);
131  }
132  }
133  return result;
134 }
135 
136 string
138 {
139  return "Xapian::MultiValueKeyMaker";
140 }
141 
142 static constexpr unsigned char KEYSPEC_REVERSE = 1;
143 static constexpr unsigned char KEYSPEC_DEFVALUE = 2;
144 
145 string
146 MultiValueKeyMaker::serialise() const
147 {
148  string result;
149  for (auto& keyspec : slots) {
150  pack_uint(result, keyspec.slot);
151  if (keyspec.defvalue.empty()) {
152  result += char((keyspec.reverse ? KEYSPEC_REVERSE : 0));
153  } else {
154  result += char((keyspec.reverse ? KEYSPEC_REVERSE : 0) |
156  pack_string(result, keyspec.defvalue);
157  }
158  }
159  return result;
160 }
161 
162 KeyMaker*
163 MultiValueKeyMaker::unserialise(const string& serialised,
164  const Registry&) const
165 {
166  const char* p = serialised.data();
167  const char* end = p + serialised.size();
168  unique_ptr<MultiValueKeyMaker> result(new MultiValueKeyMaker());
169  while (p != end) {
170  Xapian::valueno slot;
171  bool reverse;
172  if (!unpack_uint(&p, end, &slot) || p == end) {
174  }
175  unsigned char bits = *p++;
176  reverse = (bits & KEYSPEC_REVERSE);
177  if (bits & KEYSPEC_DEFVALUE) {
178  string defvalue;
179  if (!unpack_string(&p, end, defvalue)) {
181  }
182  result->add_value(slot, reverse, defvalue);
183  } else {
184  result->add_value(slot, reverse);
185  }
186  }
187  return result.release();
188 }
189 
190 }
char name[9]
Definition: dbcheck.cc:57
Class representing a document.
Definition: document.h:64
std::string get_value(Xapian::valueno slot) const
Read a value slot in this document.
Definition: document.cc:185
Virtual base class for key making functors.
Definition: keymaker.h:44
KeyMaker subclass which combines several values.
Definition: keymaker.h:156
Registry for user subclasses.
Definition: registry.h:47
UnimplementedError indicates an attempt to use an unimplemented feature.
Definition: error.h:313
#define rare(COND)
Definition: config.h:607
PositionList * p
Class representing a document.
Hierarchy of classes which Xapian can throw as exceptions.
Build key strings for MSet ordering or collapsing.
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:82
unsigned valueno
The number for a value slot in a document.
Definition: types.h:90
static constexpr unsigned char KEYSPEC_REVERSE
Definition: keymaker.cc:142
static void throw_unimplemented(const char *message)
Definition: keymaker.cc:42
static constexpr unsigned char KEYSPEC_DEFVALUE
Definition: keymaker.cc:143
void unpack_throw_serialisation_error(const char *p)
Throw appropriate SerialisationError.
Definition: pack.cc:29
Pack types into strings and unpack them again.
bool unpack_string(const char **p, const char *end, std::string &result)
Decode a std::string from a string.
Definition: pack.h:468
bool unpack_uint(const char **p, const char *end, U *result)
Decode an unsigned integer from a string.
Definition: pack.h:346
void pack_uint(std::string &s, U value)
Append an encoded unsigned integer to a string.
Definition: pack.h:315
void pack_string(std::string &s, std::string_view value)
Append an encoded std::string to a string.
Definition: pack.h:442