Advertisement
AlexDanilin

Урок 3 Идиома Pimpl

Jul 22nd, 2024 (edited)
430
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.41 KB | None | 0 0
  1. /*--------------bimap.h------------------*/
  2. #pragma once
  3.  
  4. #include <optional>
  5. #include <string_view>
  6. #include <memory>
  7.  
  8. class BiMap {
  9. public:
  10.     /**
  11.      * Добавляет в словарь пару "ключ-значение".
  12.      * В случае успеха возвращает true.
  13.      * Возвращает false, если ключ или значение были ранее добавлены.
  14.      *
  15.      * Метод обеспечивает строгую гарантию безопасности исключений
  16.      */
  17.     BiMap();
  18.     BiMap(const BiMap& other);
  19.     BiMap(BiMap&& other) noexcept;
  20.     BiMap& operator=(const BiMap& other);
  21.     BiMap& operator=(BiMap&& other) noexcept;
  22.     bool Add(std::string_view key, std::string_view value);
  23.  
  24.     /**
  25.      * Возвращает значение, связанное с ключом, либо nullopt, если такого ключа нет
  26.      */
  27.     std::optional<std::string_view> FindValue(std::string_view key) const noexcept;
  28.  
  29.     /**
  30.      * Возвращает ключ, связанный с value, либо nullopt, если такого значения нет
  31.      */
  32.     std::optional<std::string_view> FindKey(std::string_view value) const noexcept;
  33.        
  34.     ~BiMap();
  35.  
  36. private:
  37.     /* Класс должен использовать идиому Pimpl, поддерживать копирование и перемещение */
  38.      struct Impl;
  39.     std::unique_ptr<Impl> impl_;
  40. };
  41.  
  42.  
  43. /*--------------bimap.cpp------------------------------------------------------------------------------------------------------*/
  44. #include "bimap.h"
  45. #include <unordered_map>
  46. #include <deque>
  47. #include <stdexcept>
  48.  
  49. // Определение структуры KeyVal
  50. struct KeyVal
  51. {
  52.     std::string key;
  53.     std::string value;
  54. };
  55.  
  56. // Определение структуры BiMap::Impl
  57. struct BiMap::Impl {
  58.     std::unordered_map<std::string_view, std::string_view> key_to_value;
  59.     std::unordered_map<std::string_view, std::string_view> value_to_key;
  60.     std::deque<KeyVal> storage;
  61.  
  62.     Impl() = default;
  63.  
  64.     Impl(const Impl& other) {
  65.        
  66.         key_to_value = other.key_to_value;
  67.         value_to_key = other.value_to_key;
  68.         storage = other.storage;
  69.     }
  70.  
  71.     Impl& operator=(const Impl& other) {
  72.         if (this != &other) {
  73.          
  74.             key_to_value = other.key_to_value;
  75.             value_to_key = other.value_to_key;
  76.             storage = other.storage;
  77.         }
  78.         return *this;
  79.     }
  80.    
  81.  
  82.  
  83.    bool Add(std::string_view key, std::string_view value) {
  84.         try {
  85.  
  86.             if (key_to_value.count(key) > 0 || value_to_key.count(value) > 0) {
  87.                 return false;
  88.             }
  89.  
  90.             storage.push_back({ std::string(key), std::string(value) });
  91.             auto &[storage_key, storage_value] = storage.back();
  92.             key_to_value[storage_key] = storage_value;
  93.             value_to_key[storage_value] = storage_key;
  94.            
  95.             return true;
  96.         }
  97.         catch (const std::bad_alloc&) {
  98.             // частично внесенные изменения
  99.             key_to_value.clear();
  100.             value_to_key.clear();
  101.             storage.clear();
  102.             throw;
  103.         }
  104.     }
  105.                                                              
  106.    
  107.     std::optional<std::string_view> FindValue(std::string_view key) const noexcept {
  108.         auto it = key_to_value.find(key);
  109.         if (it != key_to_value.end()) {
  110.             return it->second;
  111.         }
  112.         return std::nullopt;
  113.     }
  114.  
  115.     std::optional<std::string_view> FindKey(std::string_view value) const noexcept {
  116.         auto it = value_to_key.find(value);
  117.         if (it != value_to_key.end()) {
  118.             return it->second;
  119.         }
  120.         return std::nullopt;
  121.     }
  122. };
  123.  
  124. // Реализация методов BiMap
  125.  
  126. BiMap::BiMap() : impl_(std::make_unique<Impl>()) {}
  127.  
  128. BiMap::BiMap(const BiMap& other) : impl_(std::make_unique<Impl>(*other.impl_)) {}
  129.  
  130. BiMap& BiMap::operator=(const BiMap& other) {
  131.     if (this != &other) {
  132.         *impl_ = *other.impl_;
  133.     }
  134.     return *this;
  135. }
  136.  
  137. BiMap::BiMap(BiMap&& other) noexcept = default;
  138.  
  139. BiMap& BiMap::operator=(BiMap&& other) noexcept = default;
  140.  
  141. BiMap::~BiMap() = default;
  142.  
  143. bool BiMap::Add(std::string_view key, std::string_view value) {
  144.     return impl_->Add(key, value);
  145. }
  146.  
  147. std::optional<std::string_view> BiMap::FindValue(std::string_view key) const noexcept {
  148.     return impl_->FindValue(key);
  149. }
  150.  
  151. std::optional<std::string_view> BiMap::FindKey(std::string_view value) const noexcept {
  152.     return impl_->FindKey(value);
  153. }
  154.  
  155. /*--------------main.cpp----------------------------------------------------------------------для теста из пачки----*/
  156. #include <cassert>
  157. #include <experimental/random>
  158. #include "bimap.h"
  159.  
  160. void TestBenchmarkMove()
  161. {
  162.     BiMap bimap;
  163.     int N = 3e5;
  164.     for (auto i = 0; i < N; i++) {
  165.         auto key = "key-" + std::to_string(i);
  166.         auto val = "value-" + std::to_string(i);
  167.         bimap.Add(std::string_view(key), std::string_view(val));
  168.     }
  169.  
  170.     BiMap moved_bimap(std::move(bimap));
  171.  
  172.     for (auto i = 0; i < N / 1000; i++) {
  173.         int index = std::experimental::randint(0, N);
  174.         auto key = "key-" + std::to_string(index);
  175.         auto val = "value-" + std::to_string(index);
  176.         assert(moved_bimap.FindKey(val) == key);
  177.         assert(moved_bimap.FindValue(key) == val);
  178.     }
  179.  
  180.     BiMap move_assigned_bimap;
  181.     move_assigned_bimap = std::move(moved_bimap);
  182.  
  183.     for (auto i = 0; i < N / 1000; i++) {
  184.         int index = std::experimental::randint(0, N);
  185.         auto key = "key-" + std::to_string(index);
  186.         auto val = "value-" + std::to_string(index);
  187.         assert(move_assigned_bimap.FindKey(val) == key);
  188.         assert(move_assigned_bimap.FindValue(key) == val);
  189.     }
  190. }
  191. /*--------------main.cpp------------------*/
  192. #include <cassert>
  193.  
  194. #include "bimap.h"
  195.  
  196. int main() {
  197.     using namespace std::literals;
  198.  
  199.     BiMap bimap;
  200.     {
  201.         const bool cat_added = bimap.Add("Cat"sv, "Koshka"sv);
  202.  
  203.         assert(cat_added);
  204.  
  205.         assert(bimap.FindValue("Cat"sv) == "Koshka"sv);
  206.         assert(bimap.FindKey("Koshka"sv) == "Cat"sv);
  207.         assert(!bimap.FindKey("Cat"sv));
  208.         assert(!bimap.FindValue("Koshka"sv));
  209.  
  210.         const bool kitty_added = bimap.Add("Cat"sv, "Kitty"sv);
  211.  
  212.         assert(!kitty_added);
  213.         assert(bimap.FindValue("Cat"sv) == "Koshka"sv);
  214.         assert(!bimap.FindValue("Kitty"sv));
  215.     }
  216.  
  217.     BiMap bimap_copy(bimap);
  218.     assert(bimap_copy.FindValue("Cat"sv) == "Koshka"sv);
  219.     assert(bimap_copy.FindKey("Koshka"sv) == "Cat"sv);
  220.  
  221.     bimap_copy.Add("Dog"sv, "Sobaka"sv);
  222.     assert(bimap_copy.FindValue("Dog"sv) == "Sobaka"sv);
  223.     assert(bimap_copy.FindKey("Sobaka"sv) == "Dog"sv);
  224.     assert(!bimap.FindKey("Sobaka"sv));
  225.     assert(!bimap.FindValue("Dog"sv));
  226.  
  227.     bimap = std::move(bimap_copy);
  228.     assert(bimap.FindValue("Dog"sv) == "Sobaka"sv);
  229.     assert(bimap.FindKey("Sobaka"sv) == "Dog"sv);
  230.  
  231.     BiMap moved_bimap(std::move(bimap));
  232.     assert(moved_bimap.FindValue("Dog"sv) == "Sobaka"sv);
  233.     assert(moved_bimap.FindKey("Sobaka"sv) == "Dog"sv);
  234.  
  235.     BiMap bimap_to_assign;
  236.     bimap_to_assign = moved_bimap;
  237.     assert(bimap_to_assign.FindValue("Dog"sv) == "Sobaka"sv);
  238.     assert(bimap_to_assign.FindKey("Sobaka"sv) == "Dog"sv);
  239. }
  240.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement