xenium
utils.hpp
1 //
2 // Copyright (c) 2018-2020 Manuel Pöter.
3 // Licensed under the MIT License. See LICENSE file in the project root for full license information.
4 //
5 
6 #ifndef XENIUM_UTILS_HPP
7 #define XENIUM_UTILS_HPP
8 
9 #include <cstdint>
10 #ifdef _M_AMD64
11  #include <intrin.h>
12 #endif
13 
14 namespace xenium::utils {
15 template <typename T>
16 constexpr bool is_power_of_two(T val) {
17  return (val & (val - 1)) == 0;
18 }
19 
20 template <typename T>
21 constexpr unsigned find_last_bit_set(T val) {
22  unsigned result = 0;
23  for (; val != 0; val >>= 1) {
24  ++result;
25  }
26  return result;
27 }
28 
29 template <typename T>
30 constexpr T next_power_of_two(T val) {
31  if (is_power_of_two(val)) {
32  return val;
33  }
34 
35  return static_cast<T>(1) << find_last_bit_set(val);
36 }
37 
38 template <typename T>
39 struct modulo {
40  T operator()(T a, T b) { return a % b; }
41 };
42 
43 // TODO - use intrinsics for rotate operation (if available)
44 template <uintptr_t C>
45 struct rotate {
46  static uintptr_t left(uintptr_t v) {
47  static_assert(C > 0, "should never happen!");
48  return (v >> (64 - C)) | (v << C);
49  }
50 
51  static uintptr_t right(uintptr_t v) {
52  static_assert(C > 0, "should never happen!");
53  return (v >> C) | (v << (64 - C));
54  }
55 };
56 
57 template <>
58 struct rotate<0> {
59  static uintptr_t left(uintptr_t v) { return v; }
60  static uintptr_t right(uintptr_t v) { return v; }
61 };
62 
63 #if defined(__sparc__)
64 static inline std::uint64_t getticks() {
65  std::uint64_t ret;
66  __asm__("rd %%tick, %0" : "=r"(ret));
67  return ret;
68 }
69 #elif defined(__x86_64__)
70 static inline std::uint64_t getticks() {
71  std::uint32_t hi, lo;
72  __asm__("rdtsc" : "=a"(lo), "=d"(hi));
73  return (static_cast<std::uint64_t>(hi) << 32) | static_cast<std::uint64_t>(lo);
74 }
75 #elif defined(_M_AMD64)
76 static inline std::uint64_t getticks() {
77  return __rdtsc();
78 }
79 #else
80  // TODO - add support for more compilers!
81  #error "Unsupported compiler"
82 #endif
83 
84 inline std::uint64_t random() {
85  return getticks() >> 4;
86 }
87 } // namespace xenium::utils
88 #endif