<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      UVW源碼漫談(二)

        前一篇發布出來之后,我看著閱讀量還是挺多的,就是評論和給意見的一個都沒有,或許各位看官就跟我一樣,看帖子從不回復,只管看就行了。畢竟大家都有公務在身,沒太多時間,可以理解。不過沒關系,我是不是可以直接想象為我寫的東西還挺不錯的,KeKe~~。

        

        這一篇介紹一下源代碼 ./src/uvw/emitter.hpp 里的東東。由于代碼量實在比較大,我就折疊起來了,不然各位看官手指頭滾上滾下的,太累了。之后我就寫到哪兒貼哪兒的代碼,注個大概源代碼的位置,有興趣自己打開源代碼對照看看,是不是看的就比較舒服點了。

      #pragma once
      
      
      #include <type_traits>
      #include <functional>
      #include <algorithm>
      #include <utility>
      #include <cstddef>
      #include <vector>
      #include <memory>
      #include <list>
      #include <uv.h>
      
      
      namespace uvw {
      
      
      /**
       * @brief The ErrorEvent event.
       *
       * Custom wrapper around error constants of `libuv`.
       */
      struct ErrorEvent {
          template<typename U, typename = std::enable_if_t<std::is_integral<U>::value>>
          explicit ErrorEvent(U val) noexcept
              : ec{static_cast<int>(val)}
          {}
      
          /**
           * @brief Returns the `libuv` error code equivalent to the given platform dependent error code.
           *
           * It returns:
           * * POSIX error codes on Unix (the ones stored in errno).
           * * Win32 error codes on Windows (those returned by GetLastError() or WSAGetLastError()).
           *
           * If `sys` is already a `libuv` error code, it is simply returned.
           *
           * @param sys A platform dependent error code.
           * @return The `libuv` error code equivalent to the given platform dependent error code.
           */
          static int translate(int sys) noexcept {
              return uv_translate_sys_error(sys);
          }
      
          /**
           * @brief Returns the error message for the given error code.
           *
           * Leaks a few bytes of memory when you call it with an unknown error code.
           *
           * @return The error message for the given error code.
           */
          const char * what() const noexcept { return uv_strerror(ec); }
      
          /**
           * @brief Returns the error name for the given error code.
           *
           * Leaks a few bytes of memory when you call it with an unknown error code.
           *
           * @return The error name for the given error code.
           */
          const char * name() const noexcept { return uv_err_name(ec); }
      
          /**
           * @brief Gets the underlying error code, that is an error constant of `libuv`.
           * @return The underlying error code.
           */
          int code() const noexcept { return ec; }
      
          /**
           * @brief Checks if the event contains a valid error code.
           * @return True in case of success, false otherwise.
           */
          explicit operator bool() const noexcept { return ec < 0; }
      
      private:
          const int ec;
      };
      
      
      /**
       * @brief Event emitter base class.
       *
       * Almost everything in `uvw` is an event emitter.<br/>
       * This is the base class from which resources and loops inherit.
       */
      template<typename T>
      class Emitter {
          struct BaseHandler {
              virtual ~BaseHandler() noexcept = default;
              virtual bool empty() const noexcept = 0;
              virtual void clear() noexcept = 0;
          };
      
          template<typename E>
          struct Handler final: BaseHandler {
              using Listener = std::function<void(E &, T &)>;
              using Element = std::pair<bool, Listener>;
              using ListenerList = std::list<Element>;
              using Connection = typename ListenerList::iterator;
      
              bool empty() const noexcept override {
                  auto pred = [](auto &&element){ return element.first; };
      
                  return std::all_of(onceL.cbegin(), onceL.cend(), pred) &&
                          std::all_of(onL.cbegin(), onL.cend(), pred);
              }
      
              void clear() noexcept override {
                  if(publishing) {
                      auto func = [](auto &&element){ element.first = true; };
                      std::for_each(onceL.begin(), onceL.end(), func);
                      std::for_each(onL.begin(), onL.end(), func);
                  } else {
                      onceL.clear();
                      onL.clear();
                  }
              }
      
              Connection once(Listener f) {
                  return onceL.emplace(onceL.cend(), false, std::move(f));
              }
      
              Connection on(Listener f) {
                  return onL.emplace(onL.cend(), false, std::move(f));
              }
      
              void erase(Connection conn) noexcept {
                  conn->first = true;
      
                  if(!publishing) {
                      auto pred = [](auto &&element){ return element.first; };
                      onceL.remove_if(pred);
                      onL.remove_if(pred);
                  }
              }
      
              void publish(E event, T &ref) {
                  ListenerList currentL;
                  onceL.swap(currentL);
      
                  auto func = [&event, &ref](auto &&element) {
                      return element.first ? void() : element.second(event, ref);
                  };
      
                  publishing = true;
      
                  std::for_each(onL.rbegin(), onL.rend(), func);
                  std::for_each(currentL.rbegin(), currentL.rend(), func);
      
                  publishing = false;
      
                  onL.remove_if([](auto &&element){ return element.first; });
              }
      
          private:
              bool publishing{false};
              ListenerList onceL{};
              ListenerList onL{};
          };
      
          static std::size_t next_type() noexcept {
              static std::size_t counter = 0;
              return counter++;
          }
      
          template<typename>
          static std::size_t event_type() noexcept {
              static std::size_t value = next_type();
              return value;
          }
      
          template<typename E>
          Handler<E> & handler() noexcept {
              std::size_t type = event_type<E>();
      
              if(!(type < handlers.size())) {
                  handlers.resize(type+1);
              }
      
              if(!handlers[type]) {
                 handlers[type] = std::make_unique<Handler<E>>();
              }
      
              return static_cast<Handler<E>&>(*handlers[type]);
          }
      
      protected:
          template<typename E>
          void publish(E event) {
              handler<E>().publish(std::move(event), *static_cast<T*>(this));
          }
      
      public:
          template<typename E>
          using Listener = typename Handler<E>::Listener;
      
          /**
           * @brief Connection type for a given event type.
           *
           * Given an event type `E`, `Connection<E>` is the type of the connection
           * object returned by the event emitter whenever a listener for the given
           * type is registered.
           */
          template<typename E>
          struct Connection: private Handler<E>::Connection {
              template<typename> friend class Emitter;
      
              Connection() = default;
              Connection(const Connection &) = default;
              Connection(Connection &&) = default;
      
              Connection(typename Handler<E>::Connection conn)
                  : Handler<E>::Connection{std::move(conn)}
              {}
      
              Connection & operator=(const Connection &) = default;
              Connection & operator=(Connection &&) = default;
          };
      
          virtual ~Emitter() noexcept {
              static_assert(std::is_base_of<Emitter<T>, T>::value, "!");
          }
      
          /**
           * @brief Registers a long-lived listener with the event emitter.
           *
           * This method can be used to register a listener that is meant to be
           * invoked more than once for the given event type.<br/>
           * The Connection object returned by the method can be freely discarded. It
           * can be used later to disconnect the listener, if needed.
           *
           * Listener is usually defined as a callable object assignable to a
           * `std::function<void(const E &, T &)`, where `E` is the type of the event
           * and `T` is the type of the resource.
           *
           * @param f A valid listener to be registered.
           * @return Connection object to be used later to disconnect the listener.
           */
          template<typename E>
          Connection<E> on(Listener<E> f) {
              return handler<E>().on(std::move(f));
          }
      
          /**
           * @brief Registers a short-lived listener with the event emitter.
           *
           * This method can be used to register a listener that is meant to be
           * invoked only once for the given event type.<br/>
           * The Connection object returned by the method can be freely discarded. It
           * can be used later to disconnect the listener, if needed.
           *
           * Listener is usually defined as a callable object assignable to a
           * `std::function<void(const E &, T &)`, where `E` is the type of the event
           * and `T` is the type of the resource.
           *
           * @param f Avalid listener to be registered.
           * @return Connection object to be used later to disconnect the listener.
           */
          template<typename E>
          Connection<E> once(Listener<E> f) {
              return handler<E>().once(std::move(f));
          }
      
          /**
           * @brief Disconnects a listener from the event emitter.
           * @param conn A valid Connection object
           */
          template<typename E>
          void erase(Connection<E> conn) noexcept {
              handler<E>().erase(std::move(conn));
          }
      
          /**
           * @brief Disconnects all the listeners for the given event type.
           */
          template<typename E>
          void clear() noexcept {
              handler<E>().clear();
          }
      
          /**
           * @brief Disconnects all the listeners.
           */
          void clear() noexcept {
              std::for_each(handlers.begin(), handlers.end(),
                            [](auto &&hdlr){ if(hdlr) { hdlr->clear(); } });
          }
      
          /**
           * @brief Checks if there are listeners registered for the specific event.
           * @return True if there are no listeners registered for the specific event,
           * false otherwise.
           */
          template<typename E>
          bool empty() const noexcept {
              std::size_t type = event_type<E>();
      
              return (!(type < handlers.size()) ||
                      !handlers[type] ||
                      static_cast<Handler<E>&>(*handlers[type]).empty());
          }
      
          /**
           * @brief Checks if there are listeners registered with the event emitter.
           * @return True if there are no listeners registered with the event emitter,
           * false otherwise.
           */
          bool empty() const noexcept {
              return std::all_of(handlers.cbegin(), handlers.cend(),
                                 [](auto &&hdlr){ return !hdlr || hdlr->empty(); });
          }
      
      private:
          std::vector<std::unique_ptr<BaseHandler>> handlers{};
      };
      
      
      }
      emitter

       

      一、語言層面的一些好玩的東東

        1、(源文件大概 第161行 —— 第185行)

       1     static std::size_t next_type() noexcept {
       2         static std::size_t counter = 0;
       3         return counter++;
       4     }
       5 
       6     template<typename>
       7     static std::size_t event_type() noexcept {
       8         static std::size_t value = next_type();
       9         return value;
      10     }
      11 
      12     template<typename E>
      13     Handler<E> & handler() noexcept {
      14         std::size_t type = event_type<E>();
      15 
      16         if(!(type < handlers.size())) {
      17             handlers.resize(type+1);
      18         }
      19 
      20         if(!handlers[type]) {
      21            handlers[type] = std::make_unique<Handler<E>>();
      22         }
      23 
      24         return static_cast<Handler<E>&>(*handlers[type]);
      25     }

        1.1、static

          其實說到static,大家看到這里的人應該都不會陌生,比如static函數,static變量等等。也都知道他們的特性,我就不過多說了。

          在這里,大家請看第1行——第10行,有一個是靜態函數,第二個則是一個函數模板,函數體里分別聲明定義了兩個靜態變量,我們討論的就是函數模板里的靜態變量??聪旅娴睦樱?/p>

       1 template<typename>
       2 static std::size_t event_type() noexcept {
       3     static std::size_t value = 0;
       4     return value++;
       5 } 
       6 
       7 int mian(int argc, char* argv[])
       8 {
       9     std::cout << event_type<int>() << std::endl;    //0
      10     std::cout << event_type<int>() << std::endl;      //1
      11     std::cout << event_type<int>() << std::endl;    //2
      12  
      13     std::cout << event_type<double>() << std::endl;  //0
      14     std::cout << event_type<double>() << std::endl;   //1
      15     std::cout << event_type<double>() << std::endl;  //2
      16 }  

          這里的輸出結果我已經在代碼里注出來了,對于函數模板中的靜態局部變量的初始化規則:

              1、函數模板會根據不同的模板參數生成不同的模板函數

              2、每一個模板函數中的靜態局部變量只被初始化一次

          也就是說,對于不同的類型,會生成新的模板函數,函數中會重新定義一個靜態變量,并初始化。就相當于兩個不同的函數里定義了名字一樣的靜態局部變量,由于作用域關系,這兩個靜態局部變量是不相干的。上面的例子,大家切記切記。

        1.2、這段代碼的意圖 

          了解了前面這段,各位看官跟隨我的眼珠子,再來看看第12行——第25行。大體上可以判斷,這段代碼是要創建并返回一個Handle,這個Handle是怎么創建的呢?

          根據模板類型來創建,使用上面提到的模板函數局部靜態變量的技巧,可以獲得每個模板類型在handles中的索引,如果索引不存在,則創建;如果存在,則返回對應的Handle。如果有看官不理解這其中的奧妙,可以再仔細看看代碼揣摩一下(語言表達能力不夠,莫怪莫怪)。

          而這兒的模板類型實際上就是上一篇說的事件類型,大家從函數名上也可以看出來。這樣做最直接的好處就是,不需要用enum為每個事件打上索引,索引是內建的,而事件本身就是一個struct類型,這樣不管是調用還是以后擴展都非常靈活。為了方便理解,貼一段上一篇提到的事件注冊代碼:

      1 tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::TcpHandle &) {
      2         std::cout << "error " << std::endl;
      3 });

          在此不得不佩服作者的套路之深。吾輩豈有不學之理。

        

        2、std::move() 和 std::forward()

          這兩個東西真的是非常頭疼。當時也看了很多文章,但是要真的自己寫卻很難表達出意思。不過今天,找到一篇非常好的文章:http://www.rzrgm.cn/catch/p/3507883.html

          仔細看完,應該就知道為什么會有move和forward,以及它們是在什么時候起到什么樣的作用。

       

        3、using

          using不就是使用命名空間嗎,這有什么好說的??聪旅娴拇a(源文件第96行——第99行):

      1         using Listener = std::function<void(E &, T &)>;
      2         using Element = std::pair<bool, Listener>;
      3         using ListenerList = std::list<Element>;
      4         using Connection = typename ListenerList::iterator;

          是不是顛覆了一些看官的三觀。其實這已經是C++11中就有的語法,功能和typedef差不多,但是typedef不能用于模板,比如上面的第一行。而using是可以的。舉個例子:

      1 typedef int MT1;    //和下面一行等價
      2 using MT1 = int;
      3 
      4 template<typename T>
      5 typedef std::vector<T> MT3;    //錯誤
      6 
      7 template<typename T>
      8 using MT4 = std::vector<T>;    //正確

          再看剛剛第4行:using Connection = typename ListenerList::iterator;  這里怎么會有一個typename? 以往在我們在寫模板時會用到typename 和 class,比如上面的例子,typename是可以換成class的。而這里是用來告訴編譯器,ListenerList::iterator 是一個類型。

          這里說一些其他的,相信大家很多都在公司上班吧,除非有自由職業編碼者?其實在公司里,很多都是歷史遺留下來的代碼,而且這些代碼也經過了時間的驗證,經歷過很多工程師的優化修改,所以這些代碼除非確認出現問題,否則基本不會修改。以后來到公司的,為了適應以前的編碼方式和編譯器版本,這些語法基本就很難見到了。所以即使有新的標準出來,很多人也不會去關心,去學習。比如公司指定編碼環境為WIN7+VS2010,你說2010的編譯器怎么可能包含C++11的標準呢?有需求在原來代碼上修改,增加就行了?;蛟S這也就導致很多程序員就算是不去學新東西也能憑借經驗繼續工作。本來C++98就已經包含了C++作為一種面向對象的計算機語言所需要包含的必須的特性了,所謂封裝,多態,繼承再加上一些標準庫,確實對于大多數需要效率的程序已經夠用了,這可能也是C++設計的初衷吧。何必再多此一舉,學這學那,說到底C++也只是個工具而已,說不定以后就被淘汰了呢!

          這種現象也不能說對與錯,另外C++17標準也已經出來了,很多人抱怨C++11還沒搞明白呢,C++17就來了。知乎百度上對新標準的討論也是一浪高過一浪,基本可以總結出一點:不管是大牛還是菜鳥,大家還都是對C++很有感情的。所以對于咱們天天用C++的人來說,不用管以后C++發展的怎么樣,只要自己用著舒服就行了,但是前提是得先學,學了才有選擇的余地,才游刃有余。

          說了一堆廢話,咱們繼續。KeKe~~

       

        4、其他零碎的東東

           #pragma once :很明顯,在windows編程中,處理頭文件相互包含時,就用這個,而在C標準中則是用 #ifndef ... #define ... #endif 。其實C++標準是支持這個東西的,但在Linux環境下很少有人用,大家都比較推崇那種預編譯指令。還有一些原因就是有些編譯器不支持,大家可以查看 http://zh.cppreference.com/w/cpp/preprocessor/impl 的說明和編譯器支持列表,現在大部分編譯器都會支持,所以大膽用就是了,如果恰巧不能用那就換過來唄,也不麻煩。

          noexcept:指定該函數不拋出異常,比如 int* p = new (std::nothrow) int;  則指定new失敗后不拋出異常,而是返回NULL。(這貌似和noexcept不相干,想到什么寫什么嘍)

          override:指定派生類中需要被重寫的虛函數。

          explicit:阻止類的隱式類型轉換。

       

      二、Emitter類  

         這個類的功能,就是用于事件注冊和發送,uvw中很多類都會繼承Emitter,用來響應事件。

        基本流程就是,調用on()或once()保存注冊事件函數,當libuv有回調時,將數據打包為事件結構體,直接調用publish(),在publish()中再調用注冊的相應的事件函數。

        很多東西都已經在上面說過了,我就僅介紹一下Handle,Handle是定義在Emitter中的內嵌類。幾乎實現了Emitter的所有功能,下面上代碼:

       1     template<typename E>
       2     struct Handler final: BaseHandler {
       3         using Listener = std::function<void(E &, T &)>;    //上面已經說過
       4         using Element = std::pair<bool, Listener>;        //這里的pair中的bool是用來標記,該Element是否要刪除,false為不刪除
       5         using ListenerList = std::list<Element>;
       6         using Connection = typename ListenerList::iterator;
       7 
       8         bool empty() const noexcept override {
       9             auto pred = [](auto &&element){ return element.first; };
      10 
      11             return std::all_of(onceL.cbegin(), onceL.cend(), pred) &&
      12                     std::all_of(onL.cbegin(), onL.cend(), pred);
      13         }
      14 
      15         void clear() noexcept override {             //清空注冊列表,publishing用來標志,是否正在處理事件,如果正在處理,則將Element的first標為true
      16             if(publishing) {
      17                 auto func = [](auto &&element){ element.first = true; }; 
      18                 std::for_each(onceL.begin(), onceL.end(), func);
      19                 std::for_each(onL.begin(), onL.end(), func);
      20             } else {
      21                 onceL.clear();
      22                 onL.clear();
      23             }
      24         }
      25 
      26         Connection once(Listener f) {        //注冊一次性事件
      27             return onceL.emplace(onceL.cend(), false, std::move(f));
      28         }
      29 
      30         Connection on(Listener f) {          //注冊長期事件
      31             return onL.emplace(onL.cend(), false, std::move(f));
      32         }
      33 
      34         void erase(Connection conn) noexcept {
      35             conn->first = true;
      36 
      37             if(!publishing) {
      38                 auto pred = [](auto &&element){ return element.first; };
      39                 onceL.remove_if(pred);
      40                 onL.remove_if(pred);
      41             }
      42         }
      43 
      44         void publish(E event, T &ref) {
      45             ListenerList currentL;  
      46             onceL.swap(currentL);    //這里講onceL和currentL的數據交換,所以onceL在交換之后實際已經沒有數據了,從而實現一次性的事件
      47 
      48             auto func = [&event, &ref](auto &&element) {
      49                 return element.first ? void() : element.second(event, ref);
      50             };
      51 
      52             publishing = true;      //標記正在處理事件
      53 
      54             std::for_each(onL.rbegin(), onL.rend(), func);
      55             std::for_each(currentL.rbegin(), currentL.rend(), func);
      56 
      57             publishing = false;      //標記處理事件結束
      58 
      59             onL.remove_if([](auto &&element){ return element.first; });  //清除onL中first被標記為true的項,與第4行和第15行對應
      60         }
      61 
      62     private:
      63         bool publishing{false};
      64         ListenerList onceL{};    //保存一次性事件函數列表
      65         ListenerList onL{};      //保存長期事件函數列表
      66     };

          接下來把目光移動到第63行,如果你覺得沒什么異常,那就可以跳過了。如果感覺不對勁,也可以很明顯看出來是對類成員的初始化操作,但是這種初始化操作不常見,在C++11中,被稱作為列表初始化,詳細可以參看:http://zh.cppreference.com/w/cpp/language/list_initialization

          

          emitter.hpp文件去除了libuv相關的依賴后,是可以單獨拿出來使用的,可以用于單線程回調。但是值得注意的是該類不是線程安全的,另外它也不適用于異步事件,以后我有時間可以把它改造一下,到時候再和各位分享。

          

      三、下一篇

        本來說這一篇可能會等個幾天才能寫出來的,晚上吃了飯就開始寫了,已經快12點了,還挺快的。得趕快睡覺了。

        下一篇目前暫定說一下UnderlyingType 和 Resource,如果篇幅短的話再加點其他的東西。

        這次可能就真得等個幾天了,KeKe~~

          

      posted @ 2017-09-18 23:47  yxfangcs  閱讀(1465)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 人妻体内射精一区二区三区| 久久国产精品成人影院| 亚洲男人电影天堂无码| 国产精品不卡区一区二| 国产久免费热视频在线观看| 欧美大胆老熟妇乱子伦视频| 麻花传媒在线观看免费| 91亚洲国产成人精品性色| 最新国产AV最新国产在钱| 99中文字幕精品国产| 亚洲中文字幕精品第三区| 文中字幕一区二区三区视频播放| 99精品国产一区二区三区不卡| 成人片在线看无码不卡| 99re6这里有精品热视频| 国产精品普通话国语对白露脸| 成人网站网址导航| 国产日韩精品免费二三氏| 人妻无码久久久久久久久久久| 亚洲人成人日韩中文字幕| 国产麻豆一精品一av一免费| 久久人人妻人人爽人人爽| 少妇高潮喷水正在播放| AV最新高清无码专区| 无码AV无码免费一区二区| 四虎成人精品在永久在线| 国产精品无码成人午夜电影| 东方四虎av在线观看| 镇远县| 国产蜜臀久久av一区二区| 国产日韩久久免费影院| 高清自拍亚洲精品二区| 亚洲国产午夜精品福利| 城步| 98日韩精品人妻一二区| 国产偷国产偷亚洲清高动态图| 国产又色又爽又黄的网站免费| 欧美激情内射喷水高潮| 国产色悠悠视频在线观看| 日韩国产亚洲一区二区三区| 亚洲成人av免费一区|