You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

intrusive_list.h 6.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /**
  2. * \file imperative/python/src/intrusive_list.h
  3. * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  4. *
  5. * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
  6. *
  7. * Unless required by applicable law or agreed to in writing,
  8. * software distributed under the License is distributed on an
  9. * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. */
  11. #include "megbrain/utils/metahelper.h"
  12. namespace mgb::imperative::python::intrusive_list {
  13. // copy policy
  14. struct after_t {};
  15. struct before_t {};
  16. struct disable_t {};
  17. template <typename T>
  18. struct Tail;
  19. // invariant: next->prev == this
  20. template <typename T>
  21. struct Head {
  22. Tail<T>* next;
  23. Head(Tail<T>* node = nullptr) : next(node) {}
  24. Head(const Head<T>&) = delete;
  25. Head<T>& operator=(const Head<T>&) = delete;
  26. Head(Head<T>&& rhs) : next(rhs.next) {
  27. rhs.next = nullptr;
  28. if (next) {
  29. next->prev = this;
  30. }
  31. }
  32. Head<T>& operator=(Head<T>&& rhs) {
  33. mgb_assert(!next);
  34. next = rhs.next;
  35. rhs.next = nullptr;
  36. if (next) {
  37. next->prev = this;
  38. }
  39. return *this;
  40. }
  41. ~Head() {
  42. if (next) {
  43. next->prev = nullptr;
  44. }
  45. }
  46. };
  47. // invariant: prev->next == this
  48. template <typename T>
  49. struct Tail {
  50. Head<T>* prev;
  51. Tail(Head<T>* node = nullptr) : prev(node) {}
  52. Tail(const Tail<T>&) = delete;
  53. Tail<T>& operator=(const Tail<T>&) = delete;
  54. Tail(Tail<T>&& rhs) : prev(rhs.prev) {
  55. rhs.prev = nullptr;
  56. if (prev) {
  57. prev->next = this;
  58. }
  59. }
  60. Tail<T>& operator=(Tail<T>&& rhs) {
  61. mgb_assert(!prev);
  62. prev = rhs.prev;
  63. rhs.prev = nullptr;
  64. if (prev) {
  65. prev->next = this;
  66. }
  67. return *this;
  68. }
  69. ~Tail() {
  70. if (prev) {
  71. prev->next = nullptr;
  72. }
  73. }
  74. };
  75. template <typename T, typename policy>
  76. struct Node;
  77. template <typename T>
  78. class Iterator {
  79. T* ptr;
  80. void inc() { ptr = static_cast<T*>(ptr->Head<T>::next); }
  81. void dec() { ptr = static_cast<T*>(ptr->Head<T>::prev); }
  82. public:
  83. Iterator(Head<T>& head) : ptr(static_cast<T*>(head.next)) {}
  84. Iterator(Tail<T>& tail) : ptr(static_cast<T*>(tail.prev)) {}
  85. template <typename policy>
  86. Iterator(Node<T, policy>& node) : ptr(static_cast<T*>(&node)) {}
  87. T& operator*() { return *static_cast<T*>(ptr); }
  88. T* operator->() { return static_cast<T*>(ptr); }
  89. operator bool() { return ptr; }
  90. bool operator==(const Iterator<T>& rhs) { return ptr == rhs.ptr; }
  91. Iterator& operator++() {
  92. inc();
  93. return *this;
  94. }
  95. Iterator& operator--() {
  96. dec();
  97. return *this;
  98. }
  99. Iterator operator++(int) {
  100. auto ret = *this;
  101. inc();
  102. return ret;
  103. }
  104. Iterator operator--(int) {
  105. auto ret = *this;
  106. dec();
  107. return ret;
  108. }
  109. };
  110. // Node in a doubly linked list. Unlike std::list, nodes are not owned by a container.
  111. // Instead, nodes may join or leave a list freely.
  112. // NOTE: Derived classes have to explicitly declare copy / assignment as default,
  113. // otherwise the compiler generated version would use the const T& signature,
  114. // which is deleted.
  115. template <typename T = void, typename policy = disable_t>
  116. struct Node : Tail<std::conditional_t<std::is_same_v<T, void>, Node<T, policy>, T>>,
  117. Head<std::conditional_t<std::is_same_v<T, void>, Node<T, policy>, T>> {
  118. private:
  119. using this_t = Node<T, policy>;
  120. using U = std::conditional_t<std::is_same_v<T, void>, this_t, T>;
  121. public:
  122. using head_t = Head<U>;
  123. using tail_t = Tail<U>;
  124. using head_t::next;
  125. using tail_t::prev;
  126. Node() = default;
  127. Node(const this_t&) = delete;
  128. this_t& operator=(const this_t&) = delete;
  129. //! constructed node is inserted after the input node
  130. Node(after_t, head_t& node) : tail_t(&node), head_t(node.next) {
  131. node.next = this;
  132. if (next) {
  133. next->prev = this;
  134. }
  135. }
  136. //! constructed node is inserted before the input node
  137. Node(before_t, tail_t& node) : head_t(&node), tail_t(node.prev) {
  138. node.prev = this;
  139. if (prev) {
  140. prev->next = this;
  141. }
  142. }
  143. Node(this_t&& rhs) : tail_t(rhs.prev), head_t(rhs.next) {
  144. rhs.prev = nullptr;
  145. rhs.next = nullptr;
  146. if (prev) {
  147. prev->next = this;
  148. }
  149. if (next) {
  150. next->prev = this;
  151. }
  152. }
  153. Node& operator=(this_t&& rhs) {
  154. unlink();
  155. prev = rhs.prev;
  156. next = rhs.next;
  157. rhs.prev = nullptr;
  158. rhs.next = nullptr;
  159. if (prev) {
  160. prev->next = this;
  161. }
  162. if (next) {
  163. next->prev = this;
  164. }
  165. return *this;
  166. }
  167. template <
  168. typename p = policy,
  169. typename = std::enable_if_t<
  170. std::is_same_v<p, before_t> || std::is_same_v<p, after_t>, void>>
  171. Node(this_t& rhs) : Node(policy{}, rhs) {}
  172. template <
  173. typename p = policy,
  174. typename = std::enable_if_t<
  175. std::is_same_v<p, before_t> || std::is_same_v<p, after_t>, void>>
  176. this_t& operator=(this_t& rhs) {
  177. insert(policy{}, rhs);
  178. return *this;
  179. }
  180. void unlink() {
  181. if (prev) {
  182. prev->next = next;
  183. }
  184. if (next) {
  185. next->prev = prev;
  186. }
  187. prev = nullptr;
  188. next = nullptr;
  189. }
  190. //! this node is unlinked from its list and inserted after the input node
  191. void insert(after_t, head_t& node) {
  192. unlink();
  193. prev = &node;
  194. next = node.next;
  195. node.next = this;
  196. if (next) {
  197. next->prev = this;
  198. }
  199. }
  200. //! this node is unlinked from its list and inserted before the input node
  201. void insert(before_t, tail_t& node) {
  202. unlink();
  203. next = &node;
  204. prev = node.prev;
  205. node.prev = this;
  206. if (prev) {
  207. prev->next = this;
  208. }
  209. }
  210. void insert_before(tail_t& node) { insert(before_t{}, node); }
  211. void insert_after(head_t& node) { insert(after_t{}, node); }
  212. ~Node() { unlink(); }
  213. };
  214. } // namespace mgb::imperative::python::intrusive_list

MegEngine 安装包中集成了使用 GPU 运行代码所需的 CUDA 环境,不用区分 CPU 和 GPU 版。 如果想要运行 GPU 程序,请确保机器本身配有 GPU 硬件设备并安装好驱动。 如果你想体验在云端 GPU 算力平台进行深度学习开发的感觉,欢迎访问 MegStudio 平台