bit-range.hpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #pragma once
  2. namespace nall {
  3. template<int...> struct BitRange;
  4. /* static BitRange */
  5. template<int Precision, int Lo, int Hi> struct BitRange<Precision, Lo, Hi> {
  6. static_assert(Precision >= 1 && Precision <= 64);
  7. enum : uint { bits = Precision };
  8. using type =
  9. conditional_t<bits <= 8, uint8_t,
  10. conditional_t<bits <= 16, uint16_t,
  11. conditional_t<bits <= 32, uint32_t,
  12. conditional_t<bits <= 64, uint64_t,
  13. void>>>>;
  14. enum : uint { lo = Lo < 0 ? Precision + Lo : Lo };
  15. enum : uint { hi = Hi < 0 ? Precision + Hi : Hi };
  16. enum : type { mask = ~0ull >> 64 - (hi - lo + 1) << lo };
  17. enum : uint { shift = lo };
  18. BitRange(const BitRange& source) = delete;
  19. inline auto& operator=(const BitRange& source) {
  20. target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask;
  21. return *this;
  22. }
  23. template<typename T> inline BitRange(T* source) : target((type&)*source) {
  24. static_assert(sizeof(T) == sizeof(type));
  25. }
  26. inline operator type() const {
  27. return (target & mask) >> shift;
  28. }
  29. inline auto operator++(int) {
  30. auto value = (target & mask) >> shift;
  31. target = target & ~mask | target + (1 << shift) & mask;
  32. return value;
  33. }
  34. inline auto operator--(int) {
  35. auto value = (target & mask) >> shift;
  36. target = target & ~mask | target - (1 << shift) & mask;
  37. return value;
  38. }
  39. inline auto& operator++() {
  40. target = target & ~mask | target + (1 << shift) & mask;
  41. return *this;
  42. }
  43. inline auto& operator--() {
  44. target = target & ~mask | target - (1 << shift) & mask;
  45. return *this;
  46. }
  47. template<typename T> inline auto& operator=(const T& source) {
  48. type value = source;
  49. target = target & ~mask | value << shift & mask;
  50. return *this;
  51. }
  52. template<typename T> inline auto& operator*=(const T& source) {
  53. auto value = ((target & mask) >> shift) * source;
  54. target = target & ~mask | value << shift & mask;
  55. return *this;
  56. }
  57. template<typename T> inline auto& operator/=(const T& source) {
  58. auto value = ((target & mask) >> shift) / source;
  59. target = target & ~mask | value << shift & mask;
  60. return *this;
  61. }
  62. template<typename T> inline auto& operator%=(const T& source) {
  63. auto value = ((target & mask) >> shift) % source;
  64. target = target & ~mask | value << shift & mask;
  65. return *this;
  66. }
  67. template<typename T> inline auto& operator+=(const T& source) {
  68. auto value = ((target & mask) >> shift) + source;
  69. target = target & ~mask | value << shift & mask;
  70. return *this;
  71. }
  72. template<typename T> inline auto& operator-=(const T& source) {
  73. auto value = ((target & mask) >> shift) - source;
  74. target = target & ~mask | value << shift & mask;
  75. return *this;
  76. }
  77. template<typename T> inline auto& operator<<=(const T& source) {
  78. auto value = ((target & mask) >> shift) << source;
  79. target = target & ~mask | value << shift & mask;
  80. return *this;
  81. }
  82. template<typename T> inline auto& operator>>=(const T& source) {
  83. auto value = ((target & mask) >> shift) >> source;
  84. target = target & ~mask | value << shift & mask;
  85. return *this;
  86. }
  87. template<typename T> inline auto& operator&=(const T& source) {
  88. type value = source;
  89. target = target & (~mask | value << shift & mask);
  90. return *this;
  91. }
  92. template<typename T> inline auto& operator^=(const T& source) {
  93. type value = source;
  94. target = target ^ value << shift & mask;
  95. return *this;
  96. }
  97. template<typename T> inline auto& operator|=(const T& source) {
  98. type value = source;
  99. target = target | value << shift & mask;
  100. return *this;
  101. }
  102. private:
  103. type& target;
  104. };
  105. /* dynamic BitRange */
  106. template<int Precision> struct BitRange<Precision> {
  107. static_assert(Precision >= 1 && Precision <= 64);
  108. enum : uint { bits = Precision };
  109. using type =
  110. conditional_t<bits <= 8, uint8_t,
  111. conditional_t<bits <= 16, uint16_t,
  112. conditional_t<bits <= 32, uint32_t,
  113. conditional_t<bits <= 64, uint64_t,
  114. void>>>>;
  115. BitRange(const BitRange& source) = delete;
  116. inline auto& operator=(const BitRange& source) {
  117. target = target & ~mask | ((source.target & source.mask) >> source.shift) << shift & mask;
  118. return *this;
  119. }
  120. template<typename T> inline BitRange(T* source, int index) : target((type&)*source) {
  121. static_assert(sizeof(T) == sizeof(type));
  122. if(index < 0) index = Precision + index;
  123. mask = 1ull << index;
  124. shift = index;
  125. }
  126. template<typename T> inline BitRange(T* source, int lo, int hi) : target((type&)*source) {
  127. static_assert(sizeof(T) == sizeof(type));
  128. if(lo < 0) lo = Precision + lo;
  129. if(hi < 0) hi = Precision + hi;
  130. if(lo > hi) swap(lo, hi);
  131. mask = ~0ull >> 64 - (hi - lo + 1) << lo;
  132. shift = lo;
  133. }
  134. inline operator type() const {
  135. return (target & mask) >> shift;
  136. }
  137. inline auto operator++(int) {
  138. auto value = (target & mask) >> shift;
  139. target = target & ~mask | target + (1 << shift) & mask;
  140. return value;
  141. }
  142. inline auto operator--(int) {
  143. auto value = (target & mask) >> shift;
  144. target = target & ~mask | target - (1 << shift) & mask;
  145. return value;
  146. }
  147. inline auto& operator++() {
  148. target = target & ~mask | target + (1 << shift) & mask;
  149. return *this;
  150. }
  151. inline auto& operator--() {
  152. target = target & ~mask | target - (1 << shift) & mask;
  153. return *this;
  154. }
  155. template<typename T> inline auto& operator=(const T& source) {
  156. type value = source;
  157. target = target & ~mask | value << shift & mask;
  158. return *this;
  159. }
  160. template<typename T> inline auto& operator*=(const T& source) {
  161. auto value = ((target & mask) >> shift) * source;
  162. target = target & ~mask | value << shift & mask;
  163. return *this;
  164. }
  165. template<typename T> inline auto& operator/=(const T& source) {
  166. auto value = ((target & mask) >> shift) / source;
  167. target = target & ~mask | value << shift & mask;
  168. return *this;
  169. }
  170. template<typename T> inline auto& operator%=(const T& source) {
  171. auto value = ((target & mask) >> shift) % source;
  172. target = target & ~mask | value << shift & mask;
  173. return *this;
  174. }
  175. template<typename T> inline auto& operator+=(const T& source) {
  176. auto value = ((target & mask) >> shift) + source;
  177. target = target & ~mask | value << shift & mask;
  178. return *this;
  179. }
  180. template<typename T> inline auto& operator-=(const T& source) {
  181. auto value = ((target & mask) >> shift) - source;
  182. target = target & ~mask | value << shift & mask;
  183. return *this;
  184. }
  185. template<typename T> inline auto& operator<<=(const T& source) {
  186. auto value = ((target & mask) >> shift) << source;
  187. target = target & ~mask | value << shift & mask;
  188. return *this;
  189. }
  190. template<typename T> inline auto& operator>>=(const T& source) {
  191. auto value = ((target & mask) >> shift) >> source;
  192. target = target & ~mask | value << shift & mask;
  193. return *this;
  194. }
  195. template<typename T> inline auto& operator&=(const T& source) {
  196. type value = source;
  197. target = target & (~mask | value << shift & mask);
  198. return *this;
  199. }
  200. template<typename T> inline auto& operator^=(const T& source) {
  201. type value = source;
  202. target = target ^ value << shift & mask;
  203. return *this;
  204. }
  205. template<typename T> inline auto& operator|=(const T& source) {
  206. type value = source;
  207. target = target | value << shift & mask;
  208. return *this;
  209. }
  210. private:
  211. type& target;
  212. type mask;
  213. uint shift;
  214. };
  215. }