Itoyori  v0.0.1
util.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cstdio>
4 #include <cstdlib>
5 #include <cstdint>
6 #include <cstdarg>
7 #include <ctime>
8 #include <unistd.h>
9 #include <iostream>
10 #include <sstream>
11 #include <new>
12 #include <optional>
13 #include <limits>
14 #include <vector>
15 #include <tuple>
16 #include <memory>
17 #include <utility>
18 
19 #define ITYR_CONCAT_(x, y) x##y
20 #define ITYR_CONCAT(x, y) ITYR_CONCAT_(x, y)
21 
22 #ifdef DOCTEST_LIBRARY_INCLUDED
23 
24 #define ITYR_TEST_CASE(name) DOCTEST_TEST_CASE(name)
25 #define ITYR_SUBCASE(name) DOCTEST_SUBCASE(name)
26 #define ITYR_REQUIRE(cond) DOCTEST_REQUIRE(cond)
27 #define ITYR_REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__)
28 #define ITYR_CHECK(cond) DOCTEST_CHECK(cond)
29 #define ITYR_CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__)
30 #define ITYR_CHECK_THROWS_AS(exp, exception) DOCTEST_CHECK_THROWS_AS(exp, exception)
31 
32 #else
33 
34 #ifdef __COUNTER__
35 #define ITYR_ANON_NAME(x) ITYR_CONCAT(x, __COUNTER__)
36 #else
37 #define ITYR_ANON_NAME(x) ITYR_CONCAT(x, __LINE__)
38 #endif
39 
40 #define ITYR_TEST_CASE(name) [[maybe_unused]] static inline void ITYR_ANON_NAME(__ityr_test_anon_fn)()
41 #define ITYR_SUBCASE(name)
42 #define ITYR_REQUIRE(cond) if (!(cond)) { ityr::common::die("Assertion failed (%s:%d)", __FILE__, __LINE__); }
43 #define ITYR_REQUIRE_MESSAGE(cond, msg, ...) if (!(cond)) { ityr::common::die(msg " (%s:%d)", ##__VA_ARGS__, __FILE__, __LINE__); }
44 #ifdef NDEBUG
45 #define ITYR_CHECK(cond) do { (void)sizeof(cond); } while (0)
46 #define ITYR_CHECK_MESSAGE(cond, ...) do { (void)sizeof(cond); } while (0)
47 #else
48 #define ITYR_CHECK(cond) ITYR_REQUIRE(cond)
49 #define ITYR_CHECK_MESSAGE(cond, ...) ITYR_REQUIRE_MESSAGE(cond, __VA_ARGS__)
50 #endif
51 #define ITYR_CHECK_THROWS_AS(exp, exception) exp
52 
53 #endif
54 
55 #define ITYR_ANON_VAR ITYR_CONCAT(anon_, __LINE__)
56 
57 namespace ityr::common {
58 
59 #ifdef __cpp_lib_hardware_interference_size
61 #else
62 constexpr std::size_t hardware_destructive_interference_size = 64;
63 #endif
64 
65 inline uint64_t clock_gettime_ns() {
66  struct timespec ts;
67  clock_gettime(CLOCK_MONOTONIC, &ts);
68  return (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
69 }
70 
71 [[noreturn]] __attribute__((noinline))
72 inline void die(const char* fmt, ...) {
73  constexpr int slen = 256;
74  static char msg[slen];
75 
76  va_list args;
77  va_start(args, fmt);
78  vsnprintf(msg, slen, fmt, args);
80 
81  fprintf(stderr, "\x1b[31m%s\x1b[39m\n", msg);
82  fflush(stderr);
83 
84  std::abort();
85 }
86 
87 template <typename T>
88 inline T getenv_with_default(const char* env_var, T default_val) {
89  if (const char* val_str = std::getenv(env_var)) {
90  T val;
91  std::stringstream ss(val_str);
92  ss >> val;
93  if (ss.fail()) {
94  die("Environment variable '%s' is invalid.\n", env_var);
95  }
96  return val;
97  } else {
98  return default_val;
99  }
100 }
101 
102 inline uint64_t next_pow2(uint64_t x) {
103  x--;
104  x |= x >> 1;
105  x |= x >> 2;
106  x |= x >> 4;
107  x |= x >> 8;
108  x |= x >> 16;
109  x |= x >> 32;
110  return x + 1;
111 }
112 
113 ITYR_TEST_CASE("[ityr::common::util] next_pow2") {
114  ITYR_CHECK(next_pow2(0) == 0);
115  ITYR_CHECK(next_pow2(1) == 1);
116  ITYR_CHECK(next_pow2(2) == 2);
117  ITYR_CHECK(next_pow2(3) == 4);
118  ITYR_CHECK(next_pow2(4) == 4);
119  ITYR_CHECK(next_pow2(5) == 8);
120  ITYR_CHECK(next_pow2(15) == 16);
121  ITYR_CHECK(next_pow2((uint64_t(1) << 38) - 100) == uint64_t(1) << 38);
122 }
123 
124 template <typename T>
125 inline bool is_pow2(T x) {
126  return !(x & (x - 1));
127 }
128 
129 template <typename T>
130 inline T round_down_pow2(T x, T alignment) {
131  ITYR_CHECK(is_pow2(alignment));
132  return x & ~(alignment - 1);
133 }
134 
135 template <typename T>
136 inline T* round_down_pow2(T* x, uintptr_t alignment) {
137  ITYR_CHECK(is_pow2(alignment));
138  return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(x) & ~(alignment - 1));
139 }
140 
141 template <typename T>
142 inline T round_up_pow2(T x, T alignment) {
143  ITYR_CHECK(is_pow2(alignment));
144  return (x + alignment - 1) & ~(alignment - 1);
145 }
146 
147 template <typename T>
148 inline T* round_up_pow2(T* x, uintptr_t alignment) {
149  ITYR_CHECK(is_pow2(alignment));
150  return reinterpret_cast<T*>((reinterpret_cast<uintptr_t>(x) + alignment - 1) & ~(alignment - 1));
151 }
152 
153 ITYR_TEST_CASE("[ityr::common::util] round up/down for integers") {
154  ITYR_CHECK(is_pow2(128));
155  ITYR_CHECK(!is_pow2(129));
156  ITYR_CHECK(round_down_pow2(1100, 128) == 1024);
157  ITYR_CHECK(round_down_pow2(128, 128) == 128);
158  ITYR_CHECK(round_down_pow2(129, 128) == 128);
159  ITYR_CHECK(round_down_pow2(255, 128) == 128);
160  ITYR_CHECK(round_down_pow2(73, 128) == 0);
161  ITYR_CHECK(round_down_pow2(0, 128) == 0);
162  ITYR_CHECK(round_up_pow2(1100, 128) == 1152);
163  ITYR_CHECK(round_up_pow2(128, 128) == 128);
164  ITYR_CHECK(round_up_pow2(129, 128) == 256);
165  ITYR_CHECK(round_up_pow2(255, 128) == 256);
166  ITYR_CHECK(round_up_pow2(73, 128) == 128);
167  ITYR_CHECK(round_up_pow2(0, 128) == 0);
168 }
169 
170 inline std::size_t get_page_size() {
171  static std::size_t pagesize = sysconf(_SC_PAGE_SIZE);
172  return pagesize;
173 }
174 
175 template <typename T>
176 class singleton {
177 public:
178  using instance_type = T;
179 
180  static auto& get() {
182  return *get_optional();
183  }
184 
185  static bool initialized() {
186  return get_optional().has_value();
187  }
188 
189  template <typename... Args>
190  static void init(Args&&... args) {
191  get_optional().emplace(std::forward<Args>(args)...);
192  }
193 
194  static void fini() {
196  get_optional().reset();
197  }
198 
199 private:
200  static auto& get_optional() {
201  static std::optional<T> instance;
202  return instance;
203  }
204 };
205 
206 template <typename Singleton>
208 public:
209  template <typename... Args>
211  if (!Singleton::initialized()) {
212  Singleton::init(std::forward<Args>(args)...);
213  should_finalize_ = true;
214  }
215  }
216 
218  if (should_finalize_) {
219  Singleton::fini();
220  }
221  }
222 
225 
228 
229  bool should_finalize() const { return should_finalize_; }
230 
231 private:
232  bool should_finalize_ = false;
233 };
234 
235 // for testing
236 class move_only_t {
237 public:
239  move_only_t(const long v) : value_(v) {}
240 
241  long value() const { return value_; }
242 
243  move_only_t(const move_only_t&) = delete;
244  move_only_t& operator=(const move_only_t&) = delete;
245 
246  move_only_t(move_only_t&& mo) : value_(mo.value_) {
247  mo.value_ = -1;
248  }
250  value_ = mo.value_;
251  mo.value_ = -1;
252  return *this;
253  }
254 
255 private:
256  long value_ = 0;
257 };
258 
259 inline move_only_t operator+(const move_only_t& mo1, const move_only_t& mo2) {
260  return move_only_t(mo1.value() + mo2.value());
261 }
262 
263 }
Definition: util.hpp:236
move_only_t & operator=(const move_only_t &)=delete
move_only_t(move_only_t &&mo)
Definition: util.hpp:246
move_only_t()
Definition: util.hpp:238
move_only_t & operator=(move_only_t &&mo)
Definition: util.hpp:249
move_only_t(const long v)
Definition: util.hpp:239
long value() const
Definition: util.hpp:241
move_only_t(const move_only_t &)=delete
Definition: util.hpp:207
singleton_initializer & operator=(singleton_initializer &&)=delete
bool should_finalize() const
Definition: util.hpp:229
singleton_initializer(const singleton_initializer &)=delete
singleton_initializer & operator=(const singleton_initializer &)=delete
singleton_initializer(singleton_initializer &&)=delete
~singleton_initializer()
Definition: util.hpp:217
singleton_initializer(Args &&... args)
Definition: util.hpp:210
Definition: util.hpp:176
T instance_type
Definition: util.hpp:178
static bool initialized()
Definition: util.hpp:185
static auto & get()
Definition: util.hpp:180
static void init(Args &&... args)
Definition: util.hpp:190
static void fini()
Definition: util.hpp:194
#define ITYR_CHECK(cond)
Definition: util.hpp:48
singleton< profiler< mode > > instance
Definition: profiler.hpp:259
Definition: allocator.hpp:16
T round_up_pow2(T x, T alignment)
Definition: util.hpp:142
va_list args
Definition: util.hpp:76
bool is_pow2(T x)
Definition: util.hpp:125
fprintf(stderr, "\x1b[31m%s\x1b[39m\n", msg)
vsnprintf(msg, slen, fmt, args)
fflush(stderr)
T round_down_pow2(T x, T alignment)
Definition: util.hpp:130
__attribute__((noinline)) inline void die(const char *fmt
constexpr std::size_t hardware_destructive_interference_size
Definition: util.hpp:62
std::size_t get_page_size()
Definition: util.hpp:170
T getenv_with_default(const char *env_var, T default_val)
Definition: util.hpp:88
move_only_t operator+(const move_only_t &mo1, const move_only_t &mo2)
Definition: util.hpp:259
uint64_t clock_gettime_ns()
Definition: util.hpp:65
va_start(args, fmt)
uint64_t next_pow2(uint64_t x)
Definition: util.hpp:102
void fini()
Definition: ito.hpp:45
void init(MPI_Comm comm=MPI_COMM_WORLD)
Definition: ito.hpp:41