topic_alias_send.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. #if !defined(MQTT_TOPIC_ALIAS_SEND_HPP)
  7. #define MQTT_TOPIC_ALIAS_SEND_HPP
  8. #include <string>
  9. #include <unordered_map>
  10. #include <array>
  11. #include <boost/multi_index_container.hpp>
  12. #include <boost/multi_index/ordered_index.hpp>
  13. #include <boost/multi_index/member.hpp>
  14. #include <boost/multi_index/mem_fun.hpp>
  15. #include <mqtt/namespace.hpp>
  16. #include <mqtt/string_view.hpp>
  17. #include <mqtt/constant.hpp>
  18. #include <mqtt/type.hpp>
  19. #include <mqtt/move.hpp>
  20. #include <mqtt/log.hpp>
  21. #include <mqtt/time_point_t.hpp>
  22. #include <mqtt/optional.hpp>
  23. #include <mqtt/value_allocator.hpp>
  24. namespace MQTT_NS {
  25. namespace mi = boost::multi_index;
  26. class topic_alias_send {
  27. public:
  28. topic_alias_send(topic_alias_t max)
  29. :max_{max}, va_{min_, max_} {}
  30. void insert_or_update(string_view topic, topic_alias_t alias) {
  31. MQTT_LOG("mqtt_impl", trace)
  32. << MQTT_ADD_VALUE(address, this)
  33. << "topic_alias_send insert"
  34. << " topic:" << topic
  35. << " alias:" << alias;
  36. BOOST_ASSERT(!topic.empty() && alias >= min_ && alias <= max_);
  37. va_.use(alias);
  38. auto& idx = aliases_.get<tag_alias>();
  39. auto it = idx.lower_bound(alias);
  40. if (it == idx.end() || it->alias != alias) {
  41. idx.emplace_hint(it, std::string(topic), alias, std::chrono::steady_clock::now());
  42. }
  43. else {
  44. idx.modify(
  45. it,
  46. [&](entry& e) {
  47. e.topic = std::string{topic};
  48. e.tp = std::chrono::steady_clock::now();
  49. },
  50. [](auto&) { BOOST_ASSERT(false); }
  51. );
  52. }
  53. }
  54. std::string find(topic_alias_t alias) {
  55. MQTT_LOG("mqtt_impl", trace)
  56. << MQTT_ADD_VALUE(address, this)
  57. << "find_topic_by_alias"
  58. << " alias:" << alias;
  59. BOOST_ASSERT(alias >= min_ && alias <= max_);
  60. auto& idx = aliases_.get<tag_alias>();
  61. auto it = idx.find(alias);
  62. if (it == idx.end()) return std::string();
  63. idx.modify(
  64. it,
  65. [&](entry& e) {
  66. e.tp = std::chrono::steady_clock::now();
  67. },
  68. [](auto&) { BOOST_ASSERT(false); }
  69. );
  70. return it->topic;
  71. }
  72. optional<topic_alias_t> find(string_view topic) const {
  73. MQTT_LOG("mqtt_impl", trace)
  74. << MQTT_ADD_VALUE(address, this)
  75. << "find_alias_by_topic"
  76. << " topic:" << topic;
  77. auto& idx = aliases_.get<tag_topic_name>();
  78. auto it = idx.find(topic);
  79. if (it == idx.end()) return nullopt;
  80. return it->alias;
  81. }
  82. void clear() {
  83. MQTT_LOG("mqtt_impl", info)
  84. << MQTT_ADD_VALUE(address, this)
  85. << "clear_topic_alias";
  86. aliases_.clear();
  87. va_.clear();
  88. }
  89. topic_alias_t get_lru_alias() const {
  90. BOOST_ASSERT(max_ > 0);
  91. if (auto alias_opt = va_.first_vacant()) {
  92. return alias_opt.value();
  93. }
  94. auto& idx = aliases_.get<tag_tp>();
  95. return idx.begin()->alias;
  96. }
  97. topic_alias_t max() const { return max_; }
  98. private:
  99. static constexpr topic_alias_t min_ = 1;
  100. topic_alias_t max_;
  101. struct entry {
  102. entry(std::string topic, topic_alias_t alias, time_point_t tp)
  103. : topic{force_move(topic)}, alias{alias}, tp{force_move(tp)} {}
  104. string_view get_topic_as_view() const {
  105. return topic;
  106. }
  107. std::string topic;
  108. topic_alias_t alias;
  109. time_point_t tp;
  110. };
  111. struct tag_tp {};
  112. struct tag_alias {};
  113. struct tag_topic_name {};
  114. using mi_topic_alias = mi::multi_index_container<
  115. entry,
  116. mi::indexed_by<
  117. mi::ordered_unique<
  118. mi::tag<tag_alias>,
  119. BOOST_MULTI_INDEX_MEMBER(entry, topic_alias_t, alias)
  120. >,
  121. mi::ordered_unique<
  122. mi::tag<tag_topic_name>,
  123. BOOST_MULTI_INDEX_CONST_MEM_FUN(entry, string_view, get_topic_as_view)
  124. >,
  125. mi::ordered_non_unique<
  126. mi::tag<tag_tp>,
  127. BOOST_MULTI_INDEX_MEMBER(entry, time_point_t, tp)
  128. >
  129. >
  130. >;
  131. mi_topic_alias aliases_;
  132. value_allocator<topic_alias_t> va_;
  133. };
  134. } // namespace MQTT_NS
  135. #endif // MQTT_TOPIC_ALIAS_SEND_HPP