Fcitx
rawconfig.cpp
1 /*
2  * SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #include "rawconfig.h"
8 #include <cstddef>
9 #include <functional>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 #include "fcitx-utils/log.h"
15 #include "fcitx-utils/macros.h"
16 #include "fcitx-utils/misc_p.h"
17 
18 namespace fcitx {
19 
20 class RawConfigPrivate : public QPtrHolder<RawConfig> {
21 public:
22  RawConfigPrivate(RawConfig *q, std::string _name)
23  : QPtrHolder(q), name_(std::move(_name)), lineNumber_(0) {}
25  : QPtrHolder(q), value_(other.value_), comment_(other.comment_),
26  lineNumber_(other.lineNumber_) {}
27 
28  RawConfigPrivate &operator=(const RawConfigPrivate &other) {
29  if (&other == this) {
30  return *this;
31  }
32  // There is no need to copy "name_", because name refers to its parent.
33  // Make a copy of value, comment, and lineNumber, because this "other"
34  // might be our parent.
35  auto value = other.value_;
36  auto comment = other.comment_;
37  auto lineNumber = other.lineNumber_;
38  OrderedMap<std::string, std::shared_ptr<RawConfig>> newSubItems;
39  for (const auto &item : other.subItems_) {
40  auto result = newSubItems[item.first] =
41  q_func()->createSub(item.second->name());
42  *result = *item.second;
43  }
44  value_ = std::move(value);
45  comment_ = std::move(comment);
46  lineNumber_ = lineNumber;
47  detachSubItems();
48  subItems_ = std::move(newSubItems);
49  return *this;
50  }
51 
52  std::shared_ptr<RawConfig> getNonexistentRawConfig(RawConfig *q,
53  const std::string &key) {
54  auto result = subItems_[key] = q->createSub(key);
55  return result;
56  }
57 
58  static std::shared_ptr<const RawConfig>
59  getNonexistentRawConfig(const RawConfig * /*unused*/,
60  const std::string & /*unused*/) {
61  return nullptr;
62  }
63 
64  template <typename T, typename U>
65  static std::shared_ptr<T>
66  getRawConfigHelper(T &that, const std::string &path, U callback) {
67  auto *cur = &that;
68  std::shared_ptr<T> result;
69  for (std::string::size_type pos = 0, new_pos = path.find('/', pos);
70  pos != std::string::npos && cur;
71  pos = ((std::string::npos == new_pos) ? new_pos : (new_pos + 1)),
72  new_pos = path.find('/', pos)) {
73  auto key = path.substr(pos, (std::string::npos == new_pos)
74  ? new_pos
75  : (new_pos - pos));
76  auto iter = cur->d_func()->subItems_.find(key);
77  if (iter == cur->d_func()->subItems_.end()) {
78  result = cur->d_func()->getNonexistentRawConfig(cur, key);
79  } else {
80  result = iter->second;
81  }
82  cur = result.get();
83 
84  if (cur) {
85  callback(*cur, path.substr(0, new_pos));
86  }
87  }
88  return result;
89  }
90 
91  template <typename T>
92  static bool
93  visitHelper(T &that,
94  std::function<bool(T &, const std::string &path)> callback,
95  bool recursive, const std::string &pathPrefix) {
96  auto d = that.d_func();
97  for (const auto &pair : d->subItems_) {
98  std::shared_ptr<T> item = pair.second;
99  auto newPathPrefix = pathPrefix.empty()
100  ? item->name()
101  : pathPrefix + "/" + item->name();
102  if (!callback(*item, newPathPrefix)) {
103  return false;
104  }
105  if (recursive) {
106  if (!visitHelper(*item, callback, recursive, newPathPrefix)) {
107  return false;
108  }
109  }
110  }
111  return true;
112  }
113 
114  void detachSubItems() {
115  for (const auto &pair : subItems_) {
116  pair.second->d_func()->parent_ = nullptr;
117  }
118  }
119 
120  RawConfig *parent_ = nullptr;
121  const std::string name_;
122  std::string value_;
123  std::string comment_;
124  OrderedMap<std::string, std::shared_ptr<RawConfig>> subItems_;
125  unsigned int lineNumber_;
126 };
127 
128 RawConfig::RawConfig() : RawConfig("") {}
129 
130 RawConfig::RawConfig(std::string name)
131  : d_ptr(std::make_unique<RawConfigPrivate>(this, std::move(name))) {}
132 
133 RawConfig::~RawConfig() {
134  FCITX_D();
135  d->detachSubItems();
136 }
137 
138 RawConfig::RawConfig(const RawConfig &other)
139  : d_ptr(std::make_unique<RawConfigPrivate>(this, *other.d_ptr)) {
140  for (const auto &item : other.d_func()->subItems_) {
141  *get(item.first, true) = *item.second;
142  }
143 }
144 RawConfig &RawConfig::operator=(const RawConfig &other) {
145  *d_ptr = *other.d_ptr;
146  return *this;
147 }
148 
149 std::shared_ptr<RawConfig> RawConfig::get(const std::string &path,
150  bool create) {
151  auto dummy = [](const RawConfig &, const std::string &) {};
152  if (create) {
153  return RawConfigPrivate::getRawConfigHelper(*this, path, dummy);
154  }
155  return std::const_pointer_cast<RawConfig>(
156  RawConfigPrivate::getRawConfigHelper<const RawConfig>(*this, path,
157  dummy));
158 }
159 
160 std::shared_ptr<const RawConfig> RawConfig::get(const std::string &path) const {
161  auto dummy = [](const RawConfig &, const std::string &) {};
162  return RawConfigPrivate::getRawConfigHelper(*this, path, dummy);
163 }
164 
165 bool RawConfig::remove(const std::string &path) {
166  auto pos = path.rfind('/');
167  auto *root = this;
168  if (pos == 0 || pos + 1 == path.size()) {
169  return false;
170  }
171 
172  if (pos != std::string::npos) {
173  root = get(path.substr(0, pos)).get();
174  }
175  return root->d_func()->subItems_.erase(path.substr(pos + 1)) > 0;
176 }
177 
178 void RawConfig::removeAll() {
179  FCITX_D();
180  d->subItems_.clear();
181 }
182 
183 void RawConfig::setValue(std::string value) {
184  FCITX_D();
185  d->value_ = std::move(value);
186 }
187 
188 void RawConfig::setComment(std::string comment) {
189  FCITX_D();
190  d->comment_ = std::move(comment);
191 }
192 
193 void RawConfig::setLineNumber(unsigned int lineNumber) {
194  FCITX_D();
195  d->lineNumber_ = lineNumber;
196 }
197 
198 const std::string &RawConfig::name() const {
199  FCITX_D();
200  return d->name_;
201 }
202 
203 const std::string &RawConfig::comment() const {
204  FCITX_D();
205  return d->comment_;
206 }
207 
208 const std::string &RawConfig::value() const {
209  FCITX_D();
210  return d->value_;
211 }
212 
213 unsigned int RawConfig::lineNumber() const {
214  FCITX_D();
215  return d->lineNumber_;
216 }
217 
218 bool RawConfig::hasSubItems() const {
219  FCITX_D();
220  return !d->subItems_.empty();
221 }
222 
223 size_t RawConfig::subItemsSize() const {
224  FCITX_D();
225  return d->subItems_.size();
226 }
227 
228 std::vector<std::string> RawConfig::subItems() const {
229  FCITX_D();
230  std::vector<std::string> result;
231  result.reserve(d->subItems_.size());
232  for (const auto &pair : d->subItems_) {
233  result.push_back(pair.first);
234  }
235  return result;
236 }
237 
238 RawConfig *RawConfig::parent() const {
239  FCITX_D();
240  return d->parent_;
241 }
242 
243 std::shared_ptr<RawConfig> RawConfig::detach() {
244  FCITX_D();
245  if (!d->parent_) {
246  return {};
247  }
248  auto ref = d->parent_->get(d->name_);
249  d->parent_->d_func()->subItems_.erase(d->name_);
250  d->parent_ = nullptr;
251  return ref;
252 }
253 
254 bool RawConfig::visitSubItems(
255  std::function<bool(RawConfig &, const std::string &path)> callback,
256  const std::string &path, bool recursive, const std::string &pathPrefix) {
257  auto *root = this;
258  std::shared_ptr<RawConfig> subItem;
259  if (!path.empty()) {
260  subItem = get(path);
261  root = subItem.get();
262  }
263 
264  if (!root) {
265  return true;
266  }
267 
268  return RawConfigPrivate::visitHelper(*root, std::move(callback), recursive,
269  pathPrefix);
270 }
271 
272 bool RawConfig::visitSubItems(
273  std::function<bool(const RawConfig &, const std::string &path)> callback,
274  const std::string &path, bool recursive,
275  const std::string &pathPrefix) const {
276  const auto *root = this;
277  std::shared_ptr<const RawConfig> subItem;
278  if (!path.empty()) {
279  subItem = get(path);
280  root = subItem.get();
281  }
282 
283  if (!root) {
284  return true;
285  }
286 
287  return RawConfigPrivate::visitHelper(*root, std::move(callback), recursive,
288  pathPrefix);
289 }
290 
291 void RawConfig::visitItemsOnPath(
292  std::function<void(RawConfig &, const std::string &path)> callback,
293  const std::string &path) {
294  RawConfigPrivate::getRawConfigHelper(*this, path, std::move(callback));
295 }
296 void RawConfig::visitItemsOnPath(
297  std::function<void(const RawConfig &, const std::string &path)> callback,
298  const std::string &path) const {
299  RawConfigPrivate::getRawConfigHelper(*this, path, std::move(callback));
300 }
301 
302 std::shared_ptr<RawConfig> RawConfig::createSub(std::string name) {
303  struct RawSubConfig : public RawConfig {
304  RawSubConfig(RawConfig *parent, std::string name)
305  : RawConfig(std::move(name)) {
306  FCITX_D();
307  d->parent_ = parent;
308  }
309  };
310  return std::make_shared<RawSubConfig>(this, std::move(name));
311 }
312 
313 LogMessageBuilder &operator<<(LogMessageBuilder &log, const RawConfig &config) {
314  log << "RawConfig(=" << config.value();
315  config.visitSubItems(
316  [&log](const RawConfig &subConfig, const std::string &path) {
317  log << ", " << path << "=" << subConfig.value();
318  return true;
319  },
320  "", true);
321  log << ")";
322  return log;
323 }
324 } // namespace fcitx
Definition: action.cpp:17
Log utilities.