mqtt_cpp
topic_alias_send.hpp
Go to the documentation of this file.
1 // Copyright Takatoshi Kondo 2020
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(MQTT_TOPIC_ALIAS_SEND_HPP)
8 #define MQTT_TOPIC_ALIAS_SEND_HPP
9 
10 #include <string>
11 #include <unordered_map>
12 #include <array>
13 
14 #include <boost/multi_index_container.hpp>
15 #include <boost/multi_index/ordered_index.hpp>
16 #include <boost/multi_index/member.hpp>
17 #include <boost/multi_index/mem_fun.hpp>
18 
19 #include <mqtt/namespace.hpp>
20 #include <mqtt/string_view.hpp>
21 #include <mqtt/constant.hpp>
22 #include <mqtt/type.hpp>
23 #include <mqtt/move.hpp>
24 #include <mqtt/log.hpp>
25 #include <mqtt/time_point_t.hpp>
26 #include <mqtt/optional.hpp>
27 #include <mqtt/value_allocator.hpp>
28 
29 namespace MQTT_NS {
30 
31 namespace mi = boost::multi_index;
32 
34 public:
36  :max_{max}, va_{min_, max_} {}
37 
39  MQTT_LOG("mqtt_impl", trace)
40  << MQTT_ADD_VALUE(address, this)
41  << "topic_alias_send insert"
42  << " topic:" << topic
43  << " alias:" << alias;
44  BOOST_ASSERT(!topic.empty() && alias >= min_ && alias <= max_);
45  va_.use(alias);
46  auto& idx = aliases_.get<tag_alias>();
47  auto it = idx.lower_bound(alias);
48  if (it == idx.end() || it->alias != alias) {
49  idx.emplace_hint(it, std::string(topic), alias, std::chrono::steady_clock::now());
50  }
51  else {
52  idx.modify(
53  it,
54  [&](entry& e) {
55  e.topic = std::string{topic};
56  e.tp = std::chrono::steady_clock::now();
57  },
58  [](auto&) { BOOST_ASSERT(false); }
59  );
60 
61  }
62  }
63 
64  std::string find(topic_alias_t alias) {
65  MQTT_LOG("mqtt_impl", trace)
66  << MQTT_ADD_VALUE(address, this)
67  << "find_topic_by_alias"
68  << " alias:" << alias;
69 
70  BOOST_ASSERT(alias >= min_ && alias <= max_);
71  auto& idx = aliases_.get<tag_alias>();
72  auto it = idx.find(alias);
73  if (it == idx.end()) return std::string();
74 
75  idx.modify(
76  it,
77  [&](entry& e) {
78  e.tp = std::chrono::steady_clock::now();
79  },
80  [](auto&) { BOOST_ASSERT(false); }
81  );
82  return it->topic;
83  }
84 
85  optional<topic_alias_t> find(string_view topic) const {
86  MQTT_LOG("mqtt_impl", trace)
87  << MQTT_ADD_VALUE(address, this)
88  << "find_alias_by_topic"
89  << " topic:" << topic;
90 
91  auto& idx = aliases_.get<tag_topic_name>();
92  auto it = idx.find(topic);
93  if (it == idx.end()) return nullopt;
94  return it->alias;
95  }
96 
97  void clear() {
98  MQTT_LOG("mqtt_impl", info)
99  << MQTT_ADD_VALUE(address, this)
100  << "clear_topic_alias";
101  aliases_.clear();
102  va_.clear();
103  }
104 
106  BOOST_ASSERT(max_ > 0);
107  if (auto alias_opt = va_.first_vacant()) {
108  return alias_opt.value();
109  }
110  auto& idx = aliases_.get<tag_tp>();
111  return idx.begin()->alias;
112  }
113 
114  topic_alias_t max() const { return max_; }
115 
116 private:
117  static constexpr topic_alias_t min_ = 1;
118  topic_alias_t max_;
119 
120  struct entry {
121  entry(std::string topic, topic_alias_t alias, time_point_t tp)
122  : topic{force_move(topic)}, alias{alias}, tp{force_move(tp)} {}
123 
124  string_view get_topic_as_view() const {
125  return topic;
126  }
127 
128  std::string topic;
129  topic_alias_t alias;
130  time_point_t tp;
131  };
132  struct tag_tp {};
133  struct tag_alias {};
134  struct tag_topic_name {};
135  using mi_topic_alias = mi::multi_index_container<
136  entry,
137  mi::indexed_by<
138  mi::ordered_unique<
139  mi::tag<tag_alias>,
140  BOOST_MULTI_INDEX_MEMBER(entry, topic_alias_t, alias)
141  >,
142  mi::ordered_unique<
143  mi::tag<tag_topic_name>,
144  BOOST_MULTI_INDEX_CONST_MEM_FUN(entry, string_view, get_topic_as_view)
145  >,
146  mi::ordered_non_unique<
147  mi::tag<tag_tp>,
148  BOOST_MULTI_INDEX_MEMBER(entry, time_point_t, tp)
149  >
150  >
151  >;
152 
153  mi_topic_alias aliases_;
154  value_allocator<topic_alias_t> va_;
155 };
156 
157 } // namespace MQTT_NS
158 
159 #endif // MQTT_TOPIC_ALIAS_SEND_HPP
std::chrono::time_point< std::chrono::steady_clock > time_point_t
Definition: time_point_t.hpp:18
Definition: topic_alias_send.hpp:33
topic_alias_send(topic_alias_t max)
Definition: topic_alias_send.hpp:35
void insert_or_update(string_view topic, topic_alias_t alias)
Definition: topic_alias_send.hpp:38
optional< topic_alias_t > find(string_view topic) const
Definition: topic_alias_send.hpp:85
std::string find(topic_alias_t alias)
Definition: topic_alias_send.hpp:64
topic_alias_t get_lru_alias() const
Definition: topic_alias_send.hpp:105
topic_alias_t max() const
Definition: topic_alias_send.hpp:114
void clear()
Definition: topic_alias_send.hpp:97
optional< value_type > first_vacant() const
Get the first vacant value.
Definition: value_allocator.hpp:126
void clear()
Clear all allocated or used values.
Definition: value_allocator.hpp:255
bool use(value_type value)
Declare the value as used.
Definition: value_allocator.hpp:237
#define MQTT_LOG(chan, sev)
Definition: log.hpp:135
#define MQTT_ADD_VALUE(name, val)
Definition: log.hpp:136
Definition: any.hpp:27
boost::string_ref string_view
Definition: string_view.hpp:64
constexpr std::remove_reference_t< T > && force_move(T &&t)
Definition: move.hpp:20
std::uint16_t topic_alias_t
Definition: type.hpp:17
std::chrono::time_point< std::chrono::steady_clock > time_point_t
Definition: time_point_t.hpp:16