diff --git a/.gitignore b/.gitignore index a307c5f..3e8c18b 100644 --- a/.gitignore +++ b/.gitignore @@ -222,5 +222,6 @@ _Pvt_Extensions misc/ *.sublime* test.* -src +src/ *.sln +run.bat diff --git a/README.md b/README.md index 528a5fd..40756a5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ gb single-file public domain libraries for C & C++ library | latest version | category | languages | description ----------------|----------------|----------|-----------|------------- **gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++ -**gb.hpp** | 0.21d | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development +**gb.hpp** | 0.22 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development **gb_math.hpp** | 0.02b | math | C++11 | A C++11 math library geared towards game development **gb_ini.h** | 0.91 | misc | C, C++ | A simple ini file loader library for C & C++ @@ -26,3 +26,17 @@ Yes. I think these libraries are brilliant and use many of these on a daily basi ### May I contribute? Yes. + +### What is the versioning system that you use? + +I may change it in the future but at the moment it is like this this: + +`1.23b` + +* `1` = major version +* `23` = minor version +* `b` = patch + - 1.23 => zero patches + - 1.23a => patch 1 + - 1.23b => patch 2 + - etc. diff --git a/gb.hpp b/gb.hpp index 40b4de9..c2c064a 100644 --- a/gb.hpp +++ b/gb.hpp @@ -1,8 +1,9 @@ -// gb.hpp - v0.21d - public domain C++11 helper library - no warranty implied; use at your own risk +// gb.hpp - v0.22 - public domain C++11 helper library - no warranty implied; use at your own risk // (Experimental) A C++11 helper library without STL geared towards game development /* Version History: + 0.22 - Code rearrangment into namespaces 0.21d - Fix array::free 0.21c - Fix Another Typo causing unresolved external symbol 0.21b - Typo fixes @@ -611,6 +612,38 @@ __GB_NAMESPACE_END #define GB_DEFER_2(x, y) GB_DEFER_1(x, y) #define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__) #define defer(code) auto GB_DEFER_3(_defer_) = __GB_NAMESPACE_PREFIX::impl::defer_func([&](){code;}) + + /* EXAMPLES + + // `defer (...)` will defer a statement till the end of scope + + FILE* file = fopen("test.txt", "rb"); + if (file == nullptr) + { + // Handle Error + } + defer (fclose()); // Will always be called at the end of scope + + // + + auto m = mutex::make(); + defer (mutex::destroy(&m)); // Mutex will be destroyed at the end of scope + + { + mutex::lock(&m); + defer (mutex::unlock(&m)); // Mutex will unlock at end of scope + + // Do whatever + } + + // You can scope multiple statements together if needed with {...} + defer ({ + func1(); + func2(); + func3(); + }); + + */ #endif #if !defined(GB_CASTS_WITHOUT_NAMESPACE) @@ -619,16 +652,6 @@ __GB_NAMESPACE_START #ifndef GB_SPECIAL_CASTS #define GB_SPECIAL_CASTS - // IMPORTANT NOTE(bill): Very similar to doing `*(T*)(&u)` but easier/clearer to write - // however, it can be dangerous if sizeof(T) > sizeof(U) e.g. unintialized memory, undefined behavior - // *(T*)(&u) ~~ pseudo_cast(u) - template - inline T - pseudo_cast(const U& u) - { - return reinterpret_cast(u); - } - // NOTE(bill): Very similar to doing `*(T*)(&u)` template inline Dest @@ -640,6 +663,16 @@ __GB_NAMESPACE_START ::memcpy(&dest, &source, sizeof(Dest)); return dest; } + + // IMPORTANT NOTE(bill): Very similar to doing `*(T*)(&u)` but easier/clearer to write + // however, it can be dangerous if sizeof(T) > sizeof(U) e.g. unintialized memory, undefined behavior + // *(T*)(&u) ~~ pseudo_cast(u) + template + inline T + pseudo_cast(const U& u) + { + return reinterpret_cast(u); + } #endif // FORENOTE(bill): There used to be a magic_cast that was equivalent to @@ -719,6 +752,8 @@ void post(Semaphore* semaphore, u32 count = 1); void wait(Semaphore* semaphore); } // namespace semaphore +// TODO(bill): Should I make a std::function<> equivalent to allow for captured lambdas? +// TODO(bill): Is this thread function definitions good enough? using Thread_Function = s32(void*); struct Thread @@ -781,6 +816,47 @@ struct Allocator GB_DISABLE_COPY(Allocator); }; +// TODO(bill): Should `Allocator` not even be a pure virtual base class? +/* +// Alternative Allocator types +struct Allocator +{ + void* data; + void* (*alloc)(usize size, usize align); + void (*dealloc)(const void* ptr); + s64 (*allocated_size)(const void* ptr); + s64 (*total_allocated)(void); +}; + +// or + +enum class Allocator_Mode +{ + ALLOC, + DEALLOC, + ALLOCATED_SIZE, + TOTAL_ALLOCATED, +}; + +using Allocator_Function = void*(Allocator_Mode mode, + s64 size, s64 align, + void* old_memory_pointer, + s64* output_size, + void* allocator_data, s64 flags); + +struct Allocator +{ + void* data; + Allocator_Function* function; +}; + +// Both of these may be better and more customizable but I do not know. I need to think about this. +// And discuss with others. +// The latter method would allow for one function call but the allocation is usually much slower than +// dereferencing the function pointer +*/ + + /// An allocator that used the malloc(). Allocations are padded with the size of /// the allocation and align them to the desired alignment struct Heap_Allocator : Allocator @@ -801,8 +877,6 @@ struct Heap_Allocator : Allocator virtual void dealloc(const void* ptr); virtual s64 allocated_size(const void* ptr); virtual s64 total_allocated(); - - Header* get_header_ptr(const void* ptr); }; struct Arena_Allocator : Allocator @@ -849,6 +923,23 @@ struct Temp_Allocator : Allocator }; +namespace heap_allocator +{ +Heap_Allocator::Header* get_header_ptr(const void* ptr); +} // namespace heap_allocator + +namespace arena_allocator +{ +void clear(Arena_Allocator* arena); +} // namespace arena_allocator + + +namespace temporary_arena_memory +{ +Temporary_Arena_Memory make(Arena_Allocator* arena); +void free(Temporary_Arena_Memory* tmp); +} // namespace temporary_arena_memory + namespace memory { void* align_forward(void* ptr, usize align); @@ -866,6 +957,7 @@ bool equals(const void* a, const void* b, usize bytes); inline void* alloc(Allocator* a, usize size, usize align = GB_DEFAULT_ALIGNMENT) { GB_ASSERT(a != nullptr); return a->alloc(size, align); } inline void dealloc(Allocator* a, const void* ptr) { GB_ASSERT(a != nullptr); return a->dealloc(ptr); } +// TODO(bill): Should I overload free() or not would that be too confusing? template inline T* alloc_struct(Allocator* a) { return static_cast(alloc(a, sizeof(T), alignof(T))); } @@ -876,154 +968,6 @@ inline T* alloc_array(Allocator* a, usize count) { return static_cast(alloc( template inline T* alloc_array(Allocator* a) { return static_cast(alloc(a, count * sizeof(T), alignof(T))); } -inline void -clear_arena(Arena_Allocator* arena) -{ - GB_ASSERT(arena->temp_count == 0, - "%ld Temporary_Arena_Memory have not be cleared", arena->temp_count); - - arena->total_allocated_count = 0; -} - -inline Temporary_Arena_Memory -make_temporary_arena_memory(Arena_Allocator* arena) -{ - Temporary_Arena_Memory tmp = {}; - tmp.arena = arena; - tmp.original_count = arena->total_allocated_count; -} - -inline void -free_temporary_arena_memory(Temporary_Arena_Memory* tmp) -{ - if (tmp->arena == nullptr) - return; - GB_ASSERT(tmp->arena->total_allocated() >= tmp->original_count); - tmp->arena->total_allocated_count = tmp->original_count; - GB_ASSERT(tmp->arena->temp_count > 0); - tmp->arena->temp_count--; -} - - -template -Temp_Allocator::Temp_Allocator(Allocator* backing_) -: backing(backing_) -, chunk_size(4 * 1024) // 4K -{ - current_pointer = physical_start = buffer; - physical_end = physical_start + BUFFER_SIZE; - *static_cast(physical_start) = 0; - current_pointer = memory::pointer_add(current_pointer, sizeof(void*)); -} - -template -Temp_Allocator::~Temp_Allocator() -{ - void* ptr = *static_cast(buffer); - while (ptr) - { - void* next = *static_cast(ptr); - backing_->dealloc(ptr); - ptr = next; - } - -} - -template -void* -Temp_Allocator::alloc(usize size, usize align) -{ - current_pointer = static_cast(memory::align_forward(current_pointer, align)); - if (size > static_cast(physical_end) - current_pointer) - { - usize to_allocate = sizeof(void*) + size + align; - if (to_allocate < chunk_size) - to_allocate = chunk_size; - chunk_size *= 2; - void* ptr = backing_->alloc(to_allocate); - *static_cast(physical_start) = ptr; - current_pointer = physical_start = static_cast(ptr); - *static_cast(physical_start) = 0; - current_pointer = memory::pointer_add(current_pointer, sizeof(void*)); - current_pointer = static_cast(memory::align_forward(current_pointer, align)); - } - - void* result = current_pointer; - current_pointer += size; - return (result); -} - -namespace memory -{ -inline void* -align_forward(void* ptr, usize align) -{ - GB_ASSERT(GB_IS_POWER_OF_TWO(align), - "Alignment must be a power of two and not zero -- %llu", align); - - uintptr p = uintptr(ptr); - const usize modulo = p % align; - if (modulo) - p += (align - modulo); - return reinterpret_cast(p); -} - -inline void* -pointer_add(void* ptr, usize bytes) -{ - return static_cast(static_cast(ptr) + bytes); -} - -inline const void* -pointer_add(const void* ptr, usize bytes) -{ - return static_cast(static_cast(ptr) + bytes); -} - -inline void* -pointer_sub(void* ptr, usize bytes) -{ - return static_cast(static_cast(ptr) - bytes); -} - -inline const void* -pointer_sub(const void* ptr, usize bytes) -{ - return static_cast(static_cast(ptr) - bytes); -} - -inline void* -set(void* ptr, u8 value, usize bytes) -{ - return memset(ptr, value, bytes); -} - -inline void* -zero(void* ptr, usize bytes) -{ - return memory::set(ptr, 0, bytes); -} - - -inline void* -copy(void* dest, const void* src, usize bytes) -{ - return memcpy(dest, src, bytes); -} - -inline void* -move(void* dest, const void* src, usize bytes) -{ - return memmove(dest, src, bytes); -} - -inline bool -equals(const void* a, const void* b, usize bytes) -{ - return (memcmp(a, b, bytes) == 0); -} -} // namespace memory - //////////////////////////////// /// /// /// String /// @@ -1247,12 +1191,295 @@ template void remove_all(Hash_Table* h, u64 key); } // namespace multi_hash_table +//////////////////////////////// +/// /// +/// Hash /// +/// /// +//////////////////////////////// + +namespace hash +{ +u32 adler32(const void* key, u32 num_bytes); + +u32 crc32(const void* key, u32 num_bytes); +u64 crc64(const void* key, usize num_bytes); + +// TODO(bill): Complete hashing functions +// u32 fnv32(const void* key, usize num_bytes); +// u64 fnv64(const void* key, usize num_bytes); +// u32 fnv32a(const void* key, usize num_bytes); +// u64 fnv64a(const void* key, usize num_bytes); + +u32 murmur32(const void* key, u32 num_bytes, u32 seed = 0x9747b28c); +u64 murmur64(const void* key, usize num_bytes, u64 seed = 0x9747b28c); +} // namespace hash + +//////////////////////////////// +/// /// +/// Time /// +/// /// +//////////////////////////////// + +struct Time +{ + s64 microseconds; +}; + +extern const Time TIME_ZERO; + +namespace time +{ +Time now(); +void sleep(Time time); + +Time seconds(f32 s); +Time milliseconds(s32 ms); +Time microseconds(s64 us); + +f32 as_seconds(Time t); +s32 as_milliseconds(Time t); +s64 as_microseconds(Time t); +} // namespace time + +bool operator==(Time left, Time right); +bool operator!=(Time left, Time right); + +bool operator<(Time left, Time right); +bool operator>(Time left, Time right); + +bool operator<=(Time left, Time right); +bool operator>=(Time left, Time right); + +Time operator-(Time right); + +Time operator+(Time left, Time right); +Time operator-(Time left, Time right); + +Time& operator+=(Time& left, Time right); +Time& operator-=(Time& left, Time right); + +Time operator*(Time left, f32 right); +Time operator*(Time left, s64 right); +Time operator*(f32 left, Time right); +Time operator*(s64 left, Time right); + +Time& operator*=(Time& left, f32 right); +Time& operator*=(Time& left, s64 right); + +Time operator/(Time left, f32 right); +Time operator/(Time left, s64 right); + +Time& operator/=(Time& left, f32 right); +Time& operator/=(Time& left, s64 right); + +f32 operator/(Time left, Time right); + +Time operator%(Time left, Time right); +Time& operator%=(Time& left, Time right); + + +//////////////////////////////// +/// /// +/// OS /// +/// /// +//////////////////////////////// + +namespace os +{ +u64 time_stamp_counter(); +} // namespace os + +#if 0 +// TODO(bill): still in development +struct File +{ +#if defined(GB_SYSTEM_WINDOWS) + HANDLE win32_handle; + Mutex mutex; + + char* name; // TODO(bill): uses malloc + + b32 is_console; +#else + #error Implement file system +#endif +}; + +namespace file +{ +enum Flag : u32 +{ + READ = 0x1, + WRITE = 0x2, +}; + +uintptr fd(const File* file); + +bool new_from_fd(File* file, uintptr fd, const char* name); + +bool open(File* file, const char* filename, u32 flag, u32 perm); +bool close(File* file); + +bool create(File* file, const char* filename, u32 flag); + +bool read(File* file, void* buffer, u32 bytes_to_read); +bool write(File* file, const void* memory, u32 bytes_to_write); + +bool read_at(File* file, void* buffer, u32 bytes_to_read, s64 offset); +bool write_at(File* file, const void* memory, u32 bytes_to_write, s64 offset); + +s64 size(File* file); + +bool set_pos(File* file, s64 pos); +bool get_pos(File* file, s64* pos); +} // namespace file +#endif + + +//////////////////////////////// +/// /// +/// Implementations /// +/// /// +//////////////////////////////// + +//////////////////////////////// +/// /// +/// Allocators /// +/// /// +//////////////////////////////// + +template +Temp_Allocator::Temp_Allocator(Allocator* backing_) +: backing(backing_) +, chunk_size(4 * 1024) // 4K - page size +{ + current_pointer = physical_start = buffer; + physical_end = physical_start + BUFFER_SIZE; + *static_cast(physical_start) = 0; + current_pointer = memory::pointer_add(current_pointer, sizeof(void*)); +} + +template +Temp_Allocator::~Temp_Allocator() +{ + void* ptr = *static_cast(buffer); + while (ptr) + { + void* next = *static_cast(ptr); + backing_->dealloc(ptr); + ptr = next; + } + +} + +template +void* +Temp_Allocator::alloc(usize size, usize align) +{ + current_pointer = static_cast(memory::align_forward(current_pointer, align)); + if (size > static_cast(physical_end) - current_pointer) + { + usize to_allocate = sizeof(void*) + size + align; + if (to_allocate < chunk_size) + to_allocate = chunk_size; + chunk_size *= 2; + void* ptr = backing_->alloc(to_allocate); + *static_cast(physical_start) = ptr; + current_pointer = physical_start = static_cast(ptr); + *static_cast(physical_start) = 0; + current_pointer = memory::pointer_add(current_pointer, sizeof(void*)); + current_pointer = static_cast(memory::align_forward(current_pointer, align)); + } + + void* result = current_pointer; + current_pointer += size; + return (result); +} + + +//////////////////////////////// +/// /// +/// Memory /// +/// /// +//////////////////////////////// + +namespace memory +{ +inline void* +align_forward(void* ptr, usize align) +{ + GB_ASSERT(GB_IS_POWER_OF_TWO(align), + "Alignment must be a power of two and not zero -- %llu", align); + + uintptr p = uintptr(ptr); + const usize modulo = p % align; + if (modulo) + p += (align - modulo); + return reinterpret_cast(p); +} + +inline void* +pointer_add(void* ptr, usize bytes) +{ + return static_cast(static_cast(ptr) + bytes); +} + +inline const void* +pointer_add(const void* ptr, usize bytes) +{ + return static_cast(static_cast(ptr) + bytes); +} + +inline void* +pointer_sub(void* ptr, usize bytes) +{ + return static_cast(static_cast(ptr) - bytes); +} + +inline const void* +pointer_sub(const void* ptr, usize bytes) +{ + return static_cast(static_cast(ptr) - bytes); +} + +inline void* +set(void* ptr, u8 value, usize bytes) +{ + return memset(ptr, value, bytes); +} + +inline void* +zero(void* ptr, usize bytes) +{ + return memory::set(ptr, 0, bytes); +} + + +inline void* +copy(void* dest, const void* src, usize bytes) +{ + return memcpy(dest, src, bytes); +} + +inline void* +move(void* dest, const void* src, usize bytes) +{ + return memmove(dest, src, bytes); +} + +inline bool +equals(const void* a, const void* b, usize bytes) +{ + return (memcmp(a, b, bytes) == 0); +} +} // namespace memory //////////////////////////////// /// /// /// Array /// /// /// //////////////////////////////// + template inline Array::Array(Allocator* a, usize count_) @@ -1425,6 +1652,7 @@ grow(Array* a, usize min_capacity) /// Hash Table /// /// /// //////////////////////////////// + template inline Hash_Table::Hash_Table() @@ -1831,148 +2059,10 @@ remove_all(Hash_Table* h, u64 key) } } // namespace multi_hash_table -//////////////////////////////// -/// /// -/// Hash /// -/// /// -//////////////////////////////// - -namespace hash -{ -u32 adler32(const void* key, u32 num_bytes); - -u32 crc32(const void* key, u32 num_bytes); -u64 crc64(const void* key, usize num_bytes); - -// TODO(bill): Complete hashing functions -// u32 fnv32(const void* key, usize num_bytes); -// u64 fnv64(const void* key, usize num_bytes); -// u32 fnv32a(const void* key, usize num_bytes); -// u64 fnv64a(const void* key, usize num_bytes); - -u32 murmur32(const void* key, u32 num_bytes, u32 seed = 0x9747b28c); -u64 murmur64(const void* key, usize num_bytes, u64 seed = 0x9747b28c); -} // namespace hash - -//////////////////////////////// -/// /// -/// Time /// -/// /// -//////////////////////////////// - -struct Time -{ - s64 microseconds; -}; - -extern const Time TIME_ZERO; - -// NOTE(bill): namespace time cannot be used for numerous reasons - -namespace time -{ -Time now(); -void sleep(Time time); - -Time seconds(f32 s); -Time milliseconds(s32 ms); -Time microseconds(s64 us); - -f32 as_seconds(Time t); -s32 as_milliseconds(Time t); -s64 as_microseconds(Time t); -} // namespace time - -bool operator==(Time left, Time right); -bool operator!=(Time left, Time right); - -bool operator<(Time left, Time right); -bool operator>(Time left, Time right); - -bool operator<=(Time left, Time right); -bool operator>=(Time left, Time right); - -Time operator-(Time right); - -Time operator+(Time left, Time right); -Time operator-(Time left, Time right); - -Time& operator+=(Time& left, Time right); -Time& operator-=(Time& left, Time right); - -Time operator*(Time left, f32 right); -Time operator*(Time left, s64 right); -Time operator*(f32 left, Time right); -Time operator*(s64 left, Time right); - -Time& operator*=(Time& left, f32 right); -Time& operator*=(Time& left, s64 right); - -Time operator/(Time left, f32 right); -Time operator/(Time left, s64 right); - -Time& operator/=(Time& left, f32 right); -Time& operator/=(Time& left, s64 right); - -f32 operator/(Time left, Time right); - -Time operator%(Time left, Time right); -Time& operator%=(Time& left, Time right); -//////////////////////////////// -/// /// -/// OS /// -/// /// -//////////////////////////////// - -#if 0 -// TODO(bill): still in development -struct File -{ -#if defined(GB_SYSTEM_WINDOWS) - HANDLE win32_handle; - Mutex mutex; - - char* name; // TODO(bill): uses malloc - - b32 is_console; -#else - #error Implement file system -#endif -}; - -namespace file -{ -enum Flag : u32 -{ - READ = 0x1, - WRITE = 0x2, -}; - -uintptr fd(const File* file); - -bool new_from_fd(File* file, uintptr fd, const char* name); - -bool open(File* file, const char* filename, u32 flag, u32 perm); -bool close(File* file); - -bool create(File* file, const char* filename, u32 flag); - -bool read(File* file, void* buffer, u32 bytes_to_read); -bool write(File* file, const void* memory, u32 bytes_to_write); - -bool read_at(File* file, void* buffer, u32 bytes_to_read, s64 offset); -bool write_at(File* file, const void* memory, u32 bytes_to_write, s64 offset); - -s64 size(File* file); - -bool set_pos(File* file, s64 pos); -bool get_pos(File* file, s64* pos); -} // namespace file -#endif __GB_NAMESPACE_END @@ -2483,6 +2573,20 @@ Heap_Allocator::~Heap_Allocator() #endif } +namespace heap_allocator +{ +inline Heap_Allocator::Header* +get_header_ptr(const void* ptr) +{ + const usize* data = reinterpret_cast(ptr) - 1; + + while (*data == GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE) + data--; + + return (Heap_Allocator::Header*)(data); +} +} // namespace heap_allocator + void* Heap_Allocator::alloc(usize size, usize align) { @@ -2516,7 +2620,7 @@ Heap_Allocator::dealloc(const void* ptr) defer (mutex::unlock(&mutex)); - Header* h = get_header_ptr(ptr); + Header* h = heap_allocator::get_header_ptr(ptr); total_allocated_count -= h->size; allocation_count--; @@ -2530,7 +2634,7 @@ Heap_Allocator::allocated_size(const void* ptr) mutex::lock(&mutex); defer (mutex::unlock(&mutex)); - return get_header_ptr(ptr)->size; + return heap_allocator::get_header_ptr(ptr)->size; } s64 @@ -2539,17 +2643,6 @@ Heap_Allocator::total_allocated() return total_allocated_count; } -Heap_Allocator::Header* -Heap_Allocator::get_header_ptr(const void* ptr) -{ - const usize* data = reinterpret_cast(ptr) - 1; - - while (*data == GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE) - data--; - - return (Heap_Allocator::Header*)(data); -} - Arena_Allocator::Arena_Allocator(Allocator* backing_, usize size) : backing(backing_) , physical_start(nullptr) @@ -2598,6 +2691,42 @@ inline s64 Arena_Allocator::allocated_size(const void*) { return -1; } inline s64 Arena_Allocator::total_allocated() { return total_allocated_count; } +namespace arena_allocator +{ +inline void +clear(Arena_Allocator* arena) +{ + GB_ASSERT(arena->temp_count == 0, + "%ld Temporary_Arena_Memory have not be cleared", arena->temp_count); + + arena->total_allocated_count = 0; +} +} // namespace arena_allocator + + +namespace temporary_arena_memory +{ +inline Temporary_Arena_Memory +make(Arena_Allocator* arena) +{ + Temporary_Arena_Memory tmp = {}; + tmp.arena = arena; + tmp.original_count = arena->total_allocated_count; +} + +inline void +free(Temporary_Arena_Memory* tmp) +{ + if (tmp->arena == nullptr) + return; + GB_ASSERT(tmp->arena->total_allocated() >= tmp->original_count); + tmp->arena->total_allocated_count = tmp->original_count; + GB_ASSERT(tmp->arena->temp_count > 0); + tmp->arena->temp_count--; +} +} // namespace temporary_arena_memory + + //////////////////////////////// /// /// /// String /// @@ -3516,6 +3645,22 @@ Time& operator%=(Time& left, Time right) { return (left = left % right); } /// OS /// /// /// //////////////////////////////// + +namespace os +{ +GB_FORCE_INLINE u64 +time_stamp_counter() +{ +#if GB_SYSTEM_WINDOWS + return __rdtsc(); +#else + // TODO(bill): Check that rdtsc() works + return rdtsc(); +#endif +} +} // namespace os + + #if 0 namespace file {