libime
autophrasedict.cpp
1 /*
2  * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  */
6 #include "autophrasedict.h"
7 #include <cstddef>
8 #include <cstdint>
9 #include <functional>
10 #include <istream>
11 #include <memory>
12 #include <ostream>
13 #include <ranges>
14 #include <string>
15 #include <string_view>
16 #include <utility>
17 #include <boost/multi_index/indexed_by.hpp>
18 #include <boost/multi_index/mem_fun.hpp>
19 #include <boost/multi_index/ordered_index.hpp>
20 #include <boost/multi_index/sequenced_index.hpp>
21 #include <boost/multi_index_container.hpp>
22 #include <fcitx-utils/macros.h>
23 #include "libime/core/utils_p.h"
24 
25 namespace libime {
26 
27 struct AutoPhrase {
28  AutoPhrase(std::string entry, uint32_t hit)
29  : entry_(std::move(entry)), hit_(hit) {}
30 
31  std::string_view entry() const { return entry_; }
32 
33  std::string entry_;
34  uint32_t hit_ = 0;
35 };
36 
38  using item_list = boost::multi_index_container<
39  AutoPhrase,
40  boost::multi_index::indexed_by<
41  boost::multi_index::sequenced<>,
42  boost::multi_index::ordered_unique<
43  boost::multi_index::const_mem_fun<AutoPhrase, std::string_view,
44  &AutoPhrase::entry>>>>;
45 
46 public:
47  using iterator = item_list::iterator;
48 
49  AutoPhraseDictPrivate(size_t maxItem) : maxItems_(maxItem) {}
50  FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_COPY(AutoPhraseDictPrivate);
51 
52  item_list il_;
53  std::size_t maxItems_;
54 };
55 
56 AutoPhraseDict::AutoPhraseDict(size_t maxItems)
57  : d_ptr(std::make_unique<AutoPhraseDictPrivate>(maxItems)) {}
58 
59 AutoPhraseDict::AutoPhraseDict(size_t maxItems, std::istream &in)
60  : AutoPhraseDict(maxItems) {
61  load(in);
62 }
63 
64 FCITX_DEFINE_DPTR_COPY_AND_DEFAULT_DTOR_AND_MOVE(AutoPhraseDict)
65 
66 void AutoPhraseDict::insert(const std::string &entry, uint32_t value) {
67  FCITX_D();
68  auto &il = d->il_;
69  auto p = il.push_front(AutoPhrase{entry, value});
70 
71  auto iter = p.first;
72  if (!p.second) {
73  il.relocate(il.begin(), p.first);
74  iter = il.begin();
75  }
76  if (value == 0) {
77  il.modify(iter, [](AutoPhrase &phrase) { phrase.hit_ += 1; });
78  }
79  if (il.size() > d->maxItems_) {
80  il.pop_back();
81  }
82 }
83 
85  std::string_view s,
86  const std::function<bool(std::string_view, uint32_t)> &callback) const {
87  FCITX_D();
88  const auto &idx = d->il_.get<1>();
89  auto iter = idx.lower_bound(s);
90  while (iter != idx.end() && iter->entry().starts_with(s)) {
91  if (!callback(iter->entry(), iter->hit_)) {
92  return false;
93  }
94  ++iter;
95  }
96  return true;
97 }
98 
99 uint32_t AutoPhraseDict::exactSearch(std::string_view s) const {
100  FCITX_D();
101  const auto &idx = d->il_.get<1>();
102  auto iter = idx.find(s);
103  if (iter == idx.end()) {
104  return 0;
105  }
106  return iter->hit_;
107 }
108 
109 void AutoPhraseDict::erase(std::string_view s) {
110  FCITX_D();
111  auto &idx = d->il_.get<1>();
112  idx.erase(s);
113 }
114 
115 void AutoPhraseDict::clear() {
116  FCITX_D();
117  d->il_.clear();
118 }
119 
120 bool AutoPhraseDict::empty() const {
121  FCITX_D();
122  return d->il_.empty();
123 }
124 
125 void AutoPhraseDict::load(std::istream &in) {
126  uint32_t size = 0;
127  throw_if_io_fail(unmarshall(in, size));
128  while (size--) {
129  std::string text;
130  uint32_t hit = 0;
131  throw_if_io_fail(unmarshallString(in, text));
132  throw_if_io_fail(unmarshall(in, hit));
133  insert(text, hit);
134  }
135 }
136 
137 void AutoPhraseDict::save(std::ostream &out) {
138  FCITX_D();
139  uint32_t size = d->il_.size();
140  throw_if_io_fail(marshall(out, size));
141  for (const auto &phrase : d->il_ | std::views::reverse) {
142  throw_if_io_fail(marshallString(out, phrase.entry_));
143  throw_if_io_fail(marshall(out, phrase.hit_));
144  }
145 }
146 } // namespace libime
uint32_t exactSearch(std::string_view s) const
Returns 0 if there is no such word.
A simple MRU based dictionary.
bool search(std::string_view s, const std::function< bool(std::string_view, uint32_t)> &callback) const
Check if any word starting with s exists in the dictionary.