gb/gb.hpp

6903 lines
161 KiB
C++
Raw Normal View History

// gb.hpp - v0.16 - public domain C++11 helper library - no warranty implied; use at your own risk
2015-09-27 14:03:47 -04:00
// (Experimental) A C++11 helper library without STL geared towards game development
2015-10-05 16:30:55 -04:00
/*
Version History:
2015-10-28 14:32:42 -04:00
0.17 - Death to OOP
0.16 - All References are const convention
2015-10-18 07:18:54 -04:00
0.15 - Namespaced Types
0.14 - Casts and Quaternion Look At
2015-10-05 16:58:47 -04:00
0.13a - Fix Todos
0.13 - Basic Type Traits
0.12 - Random
0.11 - Complex
0.10 - Atomics
0.09 - Bug Fixes
0.08 - Matrix(2,3)
0.07 - Bug Fixes
0.06 - Os spec ideas
0.05 - Transform Type and Quaternion Functions
0.04 - String
0.03 - Hash Functions
0.02 - Hash Table
0.01 - Initial Version
2015-10-05 16:30:55 -04:00
LICENSE
This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit.
WARNING
- This library is _highly_ experimental and features may not work as expected.
- This also means that many functions are not documented.
- This library is not compatible with STL at all! (By design)
Context:
- Common Macros
- Assert
- Types
2015-10-18 07:18:54 -04:00
- Type Traits
2015-10-05 16:30:55 -04:00
- C++11 Move Semantics
- Defer
2015-10-18 07:18:54 -04:00
- Casts
- pseudo_cast
- bit_cast
2015-10-05 16:30:55 -04:00
- Memory
- Mutex
- Atomics
2015-10-28 14:32:42 -04:00
- Semaphore
- Thread
2015-10-05 16:30:55 -04:00
- Allocator
- Heap Allocator
- Arena Allocator
- Temporary Arena Memory
2015-10-28 14:32:42 -04:00
- Functions
2015-10-05 16:30:55 -04:00
- String
- Array
- Hash Table
- Hash Functions
- Math
- Types
- Vector(2,3,4)
- Complex
- Quaternion
- Matrix(2,3,4)
- Euler_Angles
- Transform
- Aabb
- Sphere
- Plane
- Operations
- Functions & Constants
- Type Functions
- Random
- Generator_Type
- Geneartor Definition (Template/Concept)
- Mt19937_32
- Mt19937_64
2015-10-05 16:58:47 -04:00
- Random_Device
2015-10-05 16:30:55 -04:00
- Functions
*/
2015-09-27 14:03:47 -04:00
#ifndef GB_INCLUDE_GB_HPP
#define GB_INCLUDE_GB_HPP
#if !defined(__cplusplus) && __cplusplus >= 201103L
2015-10-18 07:18:54 -04:00
#error This library is only for C++11 and above
2015-09-27 14:03:47 -04:00
#endif
// NOTE(bill): Because static means three different things in C/C++
// Great Design(!)
#define global static
#define internal static
#define local_persist static
#if defined(_MSC_VER)
2015-10-18 07:18:54 -04:00
#define _ALLOW_KEYWORD_MACROS
#endif
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
#if !defined(alignof) // Needed for MSVC 2013 'cause Microsoft "loves" standards
2015-09-27 14:03:47 -04:00
#define alignof(x) __alignof(x)
#endif
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// System OS ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
#if defined(_WIN32) || defined(_WIN64)
2015-10-18 07:18:54 -04:00
#define GB_SYSTEM_WINDOWS 1
2015-09-27 14:03:47 -04:00
#elif defined(__APPLE__) && defined(__MACH__)
2015-10-18 07:18:54 -04:00
#define GB_SYSTEM_OSX 1
2015-09-27 14:03:47 -04:00
#elif defined(__unix__)
2015-10-18 07:18:54 -04:00
#define GB_SYSTEM_UNIX 1
2015-09-27 14:03:47 -04:00
#if defined(__linux__)
2015-10-18 07:18:54 -04:00
#define GB_SYSTEM_LINUX 1
2015-09-27 14:03:47 -04:00
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
2015-10-18 07:18:54 -04:00
#define GB_SYSTEM_FREEBSD 1
2015-09-27 14:03:47 -04:00
#else
2015-10-18 07:18:54 -04:00
#error This UNIX operating system is not supported by gb.hpp
2015-09-27 14:03:47 -04:00
#endif
#else
2015-10-18 07:18:54 -04:00
#error This operating system is not supported by gb.hpp
2015-09-27 14:03:47 -04:00
#endif
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Environment Bit Size ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN64)
2015-10-18 07:18:54 -04:00
#define GB_ARCH_64_BIT 1
2015-09-27 14:03:47 -04:00
#else
2015-10-18 07:18:54 -04:00
#define GB_ARCH_32_BIT 1
2015-09-27 14:03:47 -04:00
#endif
#endif
// TODO(bill): Check if this KEPLER_ENVIRONMENT works on clang
#if defined(__GNUC__)
#if defined(__x86_64__) || defined(__ppc64__)
2015-10-18 07:18:54 -04:00
#define GB_ARCH_64_BIT 1
2015-09-27 14:03:47 -04:00
#else
2015-10-18 07:18:54 -04:00
#define GB_ARCH_32_BIT 1
2015-09-27 14:03:47 -04:00
#endif
#endif
2015-10-18 07:18:54 -04:00
// #if !defined(GB_LITTLE_EDIAN) && !defined(GB_BIG_EDIAN)
// // Source: http://sourceforge.net/p/predef/wiki/Endianness/
// #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
// defined(__BIG_ENDIAN__) || \
// defined(__ARMEB__) || \
// defined(__THUMBEB__) || \
// defined(__AARCH64EB__) || \
// defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
// // It's a big-endian target architecture
// #define GB_BIG_EDIAN 1
// #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
// defined(__LITTLE_ENDIAN__) || \
// defined(__ARMEL__) || \
// defined(__THUMBEL__) || \
// defined(__AARCH64EL__) || \
// defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
// // It's a little-endian target architecture
// #define GB_LITTLE_EDIAN 1
// #else
// #error I don't know what architecture this is!
// #endif
// #endif
2015-09-27 14:03:47 -04:00
#define GB_IS_POWER_OF_TWO(x) ((x) != 0) && !((x) & ((x) - 1))
2015-09-29 10:11:18 -04:00
#include <math.h>
2015-09-27 14:03:47 -04:00
#include <stdio.h>
2015-10-18 07:18:54 -04:00
2015-10-05 16:30:55 -04:00
#if !defined(GB_HAS_NO_CONSTEXPR)
#if defined(_GNUC_VER) && _GNUC_VER < 406 // Less than gcc 4.06
2015-10-28 14:32:42 -04:00
#define GB_HAS_NO_CONSTEXPR 1
2015-10-05 16:30:55 -04:00
#elif defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015/MSVC++ 14.0
2015-10-28 14:32:42 -04:00
#define GB_HAS_NO_CONSTEXPR 1
2015-10-05 16:30:55 -04:00
#elif !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L
2015-10-28 14:32:42 -04:00
#define GB_HAS_NO_CONSTEXPR 1
2015-10-05 16:30:55 -04:00
#endif
#endif
#if defined(GB_HAS_NO_CONSTEXPR)
2015-10-18 07:18:54 -04:00
#define GB_CONSTEXPR
2015-10-05 16:30:55 -04:00
#else
2015-10-18 07:18:54 -04:00
#define GB_CONSTEXPR constexpr
2015-10-05 16:30:55 -04:00
#endif
#ifndef GB_FORCE_INLINE
2015-10-05 13:17:30 -04:00
#if defined(_MSC_VER)
2015-10-18 07:18:54 -04:00
#define GB_FORCE_INLINE __forceinline
2015-10-05 13:17:30 -04:00
#else
2015-10-28 14:32:42 -04:00
#define GB_FORCE_INLINE __attribute__ ((__always_inline__))
2015-10-05 13:17:30 -04:00
#endif
#endif
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-18 07:18:54 -04:00
#define NOMINMAX 1
#define VC_EXTRALEAN 1
#define WIN32_EXTRA_LEAN 1
#define WIN32_LEAN_AND_MEAN 1
2015-10-04 15:59:40 -04:00
2015-10-18 07:18:54 -04:00
#include <windows.h>
#include <mmsystem.h> // Time functions
// #include <ntsecapi.h> // Random generation functions
2015-10-04 15:59:40 -04:00
2015-10-18 07:18:54 -04:00
#undef NOMINMAX
#undef VC_EXTRALEAN
#undef WIN32_EXTRA_LEAN
#undef WIN32_LEAN_AND_MEAN
2015-10-04 15:59:40 -04:00
2015-10-18 07:18:54 -04:00
#include <intrin.h>
2015-09-27 14:03:47 -04:00
#else
2015-10-18 07:18:54 -04:00
#include <pthread.h>
#include <sys/time.h>
2015-09-27 14:03:47 -04:00
#endif
2015-10-28 14:32:42 -04:00
#if !defined(NDEBUG)
2015-10-18 07:18:54 -04:00
#define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
2015-09-28 16:58:33 -04:00
#else
2015-10-18 07:18:54 -04:00
#define GB_ASSERT(x, ...) ((void)sizeof(x))
2015-09-28 16:58:33 -04:00
#endif
2015-10-28 14:32:42 -04:00
#if !defined(GB_ARRAY_BOUND_CHECKING)
#define GB_ARRAY_BOUND_CHECKING 1
#endif
extern "C" inline void
gb__abort(void)
{
// TODO(bill): Get a better way to abort
*(int*)0 = 0;
// raise(SIGABRT);
}
2015-10-18 07:18:54 -04:00
/// Helper function used as a better alternative to assert which allows for
/// optional printf style error messages
2015-09-28 16:58:33 -04:00
extern "C" inline void
gb__assert_handler(bool condition, const char* condition_str,
2015-10-05 16:30:55 -04:00
const char* filename, size_t line,
const char* error_text = nullptr, ...)
2015-09-28 16:58:33 -04:00
{
if (condition)
return;
2015-10-04 15:59:40 -04:00
fprintf(stderr, "ASSERT! %s(%lu): %s", filename, line, condition_str);
2015-09-28 16:58:33 -04:00
if (error_text)
{
fprintf(stderr, " - ");
va_list args;
va_start(args, error_text);
vfprintf(stderr, error_text, args);
va_end(args);
}
fprintf(stderr, "\n");
2015-10-28 14:32:42 -04:00
gb__abort();
2015-09-28 16:58:33 -04:00
}
2015-10-18 07:18:54 -04:00
////////////////////////////////
/// ///
/// snprintf_msvc ///
/// ///
////////////////////////////////
#if defined(_MSC_VER)
2015-09-28 16:58:33 -04:00
2015-10-18 07:18:54 -04:00
extern "C" inline int
gb__vsnprintf_compatible(char* buffer, size_t size, const char* format, va_list args)
{
int result = -1;
if (size > 0)
result = _vsnprintf_s(buffer, size, _TRUNCATE, format, args);
if (result == -1)
return _vscprintf(format, args);
return result;
}
extern "C" inline int
gb__snprintf_compatible(char* buffer, size_t size, const char* format, ...)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
va_list args;
va_start(args, format);
int result = gb__vsnprintf_compatible(buffer, size, format, args);
va_end(args);
return result;
}
#if !defined(GB_DO_NOT_USE_MSVC_SPRINTF_FIX)
#define snprintf gb__snprintf_compatible
#define vsnprintf gb__vsnprintf_compatible
#endif // GB_DO_NOT_USE_MSVC_SPRINTF_FIX
#endif
#if !defined(__GB_NAMESPACE_PREFIX) && !defined(GB_NO_GB_NAMESPACE)
#define __GB_NAMESPACE_PREFIX gb
#else
#define __GB_NAMESPACE_PREFIX
#endif
#if defined(GB_NO_GB_NAMESPACE)
#define __GB_NAMESPACE_START
#define __GB_NAMESPACE_END
#else
#define __GB_NAMESPACE_START namespace __GB_NAMESPACE_PREFIX {
#define __GB_NAMESPACE_END } // namespace __GB_NAMESPACE_PREFIX
#endif
#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
__GB_NAMESPACE_START
2015-10-05 16:30:55 -04:00
#endif // GB_BASIC_WITHOUT_NAMESPACE
2015-10-18 07:18:54 -04:00
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Types ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-10-28 14:32:42 -04:00
2015-09-27 14:03:47 -04:00
#if defined(_MSC_VER)
2015-10-28 14:32:42 -04:00
using u8 = unsigned __int8;
using s8 = signed __int8;
using u16 = unsigned __int16;
using s16 = signed __int16;
using u32 = unsigned __int32;
using s32 = signed __int32;
2015-10-18 07:18:54 -04:00
using u64 = unsigned __int64;
2015-10-28 14:32:42 -04:00
using s64 = signed __int64;
2015-09-27 14:03:47 -04:00
#else
2015-10-28 14:32:42 -04:00
using u8 = unsigned char;
using s8 = signed char;
using u16 = unsigned short;
using s16 = signed short;
using u32 = unsigned int;
using s32 = signed int;
using u64 = unsigned long long;
using s64 = signed long long;
2015-09-27 14:03:47 -04:00
#endif
2015-10-28 14:32:42 -04:00
static_assert( sizeof(u8) == 1, "u8 is not 8 bits");
static_assert(sizeof(u16) == 2, "u16 is not 16 bits");
static_assert(sizeof(u32) == 4, "u32 is not 32 bits");
static_assert(sizeof(u64) == 8, "u64 is not 64 bits");
2015-09-27 14:03:47 -04:00
using f32 = float;
using f64 = double;
2015-10-04 15:59:40 -04:00
#if defined(GB_B8_AS_BOOL)
2015-10-18 07:18:54 -04:00
using b8 = bool;
2015-09-27 14:03:47 -04:00
#else
2015-10-18 07:18:54 -04:00
using b8 = s8;
2015-09-27 14:03:47 -04:00
#endif
using b32 = s32;
// NOTE(bill): (std::)size_t is not used not because it's a bad concept but on
// the platforms that I will be using:
2015-09-27 15:43:22 -04:00
// sizeof(size_t) == sizeof(usize) == sizeof(s64)
2015-09-27 14:03:47 -04:00
// NOTE(bill): This also allows for a signed version of size_t which is similar
// to ptrdiff_t
// NOTE(bill): If (u)intptr is a better fit, please use that.
// NOTE(bill): Also, I hate the `_t` suffix
#if defined(GB_ARCH_64_BIT)
2015-10-18 07:18:54 -04:00
using ssize = s64;
using usize = u64;
2015-09-27 14:03:47 -04:00
#elif defined(GB_ARCH_32_BIT)
2015-10-18 07:18:54 -04:00
using usize = s32;
using usize = u32;
2015-09-27 14:03:47 -04:00
#else
2015-10-18 07:18:54 -04:00
#error Unknown architecture bit size
2015-09-27 14:03:47 -04:00
#endif
static_assert(sizeof(usize) == sizeof(size_t),
2015-10-05 16:30:55 -04:00
"`usize` is not the same size as `size_t`");
2015-09-27 14:03:47 -04:00
static_assert(sizeof(ssize) == sizeof(usize),
2015-10-05 16:30:55 -04:00
"`ssize` is not the same size as `usize`");
2015-09-27 14:03:47 -04:00
using intptr = intptr_t;
using uintptr = uintptr_t;
using ptrdiff = ptrdiff_t;
2015-10-18 07:18:54 -04:00
#define GB_U8_MIN 0u
#define GB_U8_MAX 0xffu
2015-10-04 15:59:40 -04:00
#define GB_S8_MIN (-0x7f - 1)
2015-10-18 07:18:54 -04:00
#define GB_S8_MAX 0x7f
2015-10-04 15:59:40 -04:00
2015-10-18 07:18:54 -04:00
#define GB_U16_MIN 0u
#define GB_U16_MAX 0xffffu
2015-10-04 15:59:40 -04:00
#define GB_S16_MIN (-0x7fff - 1)
2015-10-18 07:18:54 -04:00
#define GB_S16_MAX 0x7fff
2015-10-04 15:59:40 -04:00
2015-10-18 07:18:54 -04:00
#define GB_U32_MIN 0u
#define GB_U32_MAX 0xffffffffu
2015-10-04 15:59:40 -04:00
#define GB_S32_MIN (-0x7fffffff - 1)
2015-10-18 07:18:54 -04:00
#define GB_S32_MAX 0x7fffffff
2015-10-04 15:59:40 -04:00
2015-10-18 07:18:54 -04:00
#define GB_U64_MIN 0ull
#define GB_U64_MAX 0xffffffffffffffffull
2015-10-04 15:59:40 -04:00
#define GB_S64_MIN (-0x7fffffffffffffffll - 1)
2015-10-18 07:18:54 -04:00
#define GB_S64_MAX 0x7fffffffffffffffll
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
2015-10-28 14:32:42 -04:00
#define GB_USIZE_MIX GB_U64_MIN
#define GB_USIZE_MAX GB_U64_MAX
2015-10-04 15:59:40 -04:00
2015-10-28 14:32:42 -04:00
#define GB_SSIZE_MIX GB_S64_MIN
#define GB_SSIZE_MAX GB_S64_MAX
2015-10-04 15:59:40 -04:00
#elif defined(GB_ARCH_32_BIT)
2015-10-28 14:32:42 -04:00
#define GB_USIZE_MIX GB_U32_MIN
#define GB_USIZE_MAX GB_U32_MAX
2015-10-04 15:59:40 -04:00
2015-10-28 14:32:42 -04:00
#define GB_SSIZE_MIX GB_S32_MIN
#define GB_SSIZE_MAX GB_S32_MAX
2015-10-04 15:59:40 -04:00
#endif
2015-10-05 16:30:55 -04:00
#if defined(GB_BASIC_WITHOUT_NAMESPACE)
2015-10-18 07:18:54 -04:00
#define U8_MIN 0u
#define U8_MAX 0xffu
#define S8_MIN (-0x7f - 1)
#define S8_MAX 0x7f
#define U16_MIN 0u
#define U16_MAX 0xffffu
#define S16_MIN (-0x7fff - 1)
#define S16_MAX 0x7fff
#define U32_MIN 0u
#define U32_MAX 0xffffffffu
#define S32_MIN (-0x7fffffff - 1)
#define S32_MAX 0x7fffffff
#define U64_MIN 0ull
#define U64_MAX 0xffffffffffffffffull
#define S64_MIN (-0x7fffffffffffffffll - 1)
#define S64_MAX 0x7fffffffffffffffll
#if defined(GB_ARCH_64_BIT)
#define USIZE_MIX U64_MIN
#define USIZE_MAX U64_MAX
#define SSIZE_MIX S64_MIN
#define SSIZE_MAX S64_MAX
#elif defined(GB_ARCH_32_BIT)
#define USIZE_MIX U32_MIN
#define USIZE_MAX U32_MAX
#define SSIZE_MIX S32_MIN
#define SSIZE_MAX S32_MAX
#endif
2015-10-03 10:26:29 -04:00
#endif
2015-10-04 15:59:40 -04:00
2015-10-05 16:30:55 -04:00
#if !defined(GB_BASIC_WITHOUT_NAMESPACE)
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_END
2015-10-05 16:30:55 -04:00
#endif // GB_BASIC_WITHOUT_NAMESPACE
2015-09-30 17:12:16 -04:00
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_START
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-10-05 16:30:55 -04:00
/// C++11 Types Traits ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-10-05 16:30:55 -04:00
template <typename T> struct Add_Const_Def { using Type = const T; };
template <typename T> using Add_Const = typename Add_Const_Def<T>::Type;
template <typename T> struct Add_Volatile_Def { using Type = volatile T; };
template <typename T> using Add_Volatile = typename Add_Volatile_Def<T>::Type;
template <typename T> using Add_Const_Volatile = Add_Const<Add_Volatile<T>>;
template <typename T> struct Add_Lvalue_Reference_Def { using Type = T&; };
template <typename T> struct Add_Lvalue_Reference_Def<T&> { using Type = T&; };
template <typename T> struct Add_Lvalue_Reference_Def<T&&> { using Type = T&; };
template <> struct Add_Lvalue_Reference_Def<void> { using Type = void; };
template <> struct Add_Lvalue_Reference_Def<const void> { using Type = const void; };
template <> struct Add_Lvalue_Reference_Def<volatile void> { using Type = volatile void; };
template <> struct Add_Lvalue_Reference_Def<const volatile void> { using Type = const volatile void; };
2015-10-28 14:32:42 -04:00
template <typename T> using Add_Lvalue_Reference = typename Add_Lvalue_Reference_Def<T>::Type;
2015-10-05 16:30:55 -04:00
template <typename T> struct Add_Rvalue_Reference_Def { using Type = T&&; };
template <typename T> struct Add_Rvalue_Reference_Def<T&> { using Type = T&; };
template <typename T> struct Add_Rvalue_Reference_Def<T&&> { using Type = T&&; };
template <> struct Add_Rvalue_Reference_Def<void> { using Type = void; };
template <> struct Add_Rvalue_Reference_Def<const void> { using Type = const void; };
template <> struct Add_Rvalue_Reference_Def<volatile void> { using Type = volatile void; };
template <> struct Add_Rvalue_Reference_Def<const volatile void> { using Type = const volatile void; };
template <typename T> using Add_Rvalue_Reference = typename Add_Rvalue_Reference_Def<T>::Type;
template <typename T> struct Remove_Pointer_Def { using Type = T; };
template <typename T> struct Remove_Pointer_Def<T*> { using Type = T; };
template <typename T> struct Remove_Pointer_Def<T* const> { using Type = T; };
template <typename T> struct Remove_Pointer_Def<T* volatile> { using Type = T; };
template <typename T> struct Remove_Pointer_Def<T* const volatile> { using Type = T; };
template <typename T> using Remove_Pointer = typename Remove_Pointer_Def<T>::Type;
template <typename T> struct Add_Pointer_Def { using Type = T*; };
template <typename T> using Add_Pointer = typename Add_Pointer_Def<T>::Type;
template <typename T> struct Remove_Const_Def { using Type = T; };
template <typename T> struct Remove_Const_Def<const T> { using Type = T; };
template <typename T> using Remove_Const = typename Remove_Const_Def<T>::Type;
template <typename T> struct Remove_Volatile_Def { using Type = T; };
template <typename T> struct Remove_Volatile_Def<volatile T> { using Type = T; };
template <typename T> using Remove_Volatile = typename Remove_Const_Def<T>::Type;
template <typename T> using Remove_Const_Volatile = Remove_Const<Remove_Volatile<T>>;
template <typename T> struct Remove_Reference_Def { using Type = T; };
template <typename T> struct Remove_Reference_Def<T&> { using Type = T; };
template <typename T> struct Remove_Reference_Def<T&&> { using Type = T; };
template <typename T> using Remove_Reference = typename Remove_Reference_Def<T>::Type;
////////////////////////////////
/// ///
/// C++11 Move Semantics ///
/// ///
////////////////////////////////
2015-09-27 14:03:47 -04:00
template <typename T>
inline T&&
2015-10-05 16:30:55 -04:00
forward(Remove_Reference<T>& t)
2015-09-27 14:03:47 -04:00
{
2015-09-28 15:31:26 -04:00
return static_cast<T&&>(t);
2015-09-27 14:03:47 -04:00
}
template <typename T>
inline T&&
2015-10-05 16:30:55 -04:00
forward(Remove_Reference<T>&& t)
2015-09-27 14:03:47 -04:00
{
2015-09-28 15:31:26 -04:00
return static_cast<T&&>(t);
2015-09-27 14:03:47 -04:00
}
template <typename T>
2015-10-05 16:30:55 -04:00
inline Remove_Reference<T>&&
2015-09-27 14:03:47 -04:00
move(T&& t)
{
2015-10-05 16:30:55 -04:00
return static_cast<Remove_Reference<T>&&>(t);
2015-09-27 14:03:47 -04:00
}
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Defer ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
namespace impl
{
2015-09-30 17:12:16 -04:00
template <typename Func>
2015-09-27 14:03:47 -04:00
struct Defer
{
2015-10-28 14:32:42 -04:00
Func f;
2015-09-27 14:03:47 -04:00
2015-10-28 14:32:42 -04:00
Defer(Func&& f) : f{forward<Func>(f)} {}
~Defer() { f(); };
2015-09-27 14:03:47 -04:00
};
2015-09-30 17:12:16 -04:00
template <typename Func>
Defer<Func>
2015-10-28 14:32:42 -04:00
defer_func(Func&& f) { return Defer<Func>(forward<Func>(f)); }
2015-09-27 14:03:47 -04:00
} // namespace impl
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_END
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
// NOTE(bill): These macros are in the global namespace thus, defer can be treated without a __GB_NAMESPACE_PREFIX:: prefix
2015-09-27 14:03:47 -04:00
#define GB_DEFER_1(x, y) x##y
#define GB_DEFER_2(x, y) GB_DEFER_1(x, y)
2015-09-28 18:57:43 -04:00
#define GB_DEFER_3(x) GB_DEFER_2(GB_DEFER_2(GB_DEFER_2(x, __COUNTER__), _), __LINE__)
2015-10-18 07:18:54 -04:00
#define defer(code) auto GB_DEFER_3(_defer_) = __GB_NAMESPACE_PREFIX::impl::defer_func([&](){code;})
2015-09-27 14:03:47 -04:00
2015-10-05 16:30:55 -04:00
#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_START
2015-10-05 16:30:55 -04:00
#endif // GB_CASTS_WITHOUT_NAMESPACE
2015-10-18 07:18:54 -04:00
// 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<T>(u)
2015-10-05 16:30:55 -04:00
template <typename T, typename U>
inline T
pseudo_cast(const U& u)
{
return reinterpret_cast<const T&>(u);
}
2015-10-18 07:18:54 -04:00
// NOTE(bill): Very similar to doing `*(T*)(&u)`
template <typename Dest, typename Source>
inline Dest
bit_cast(const Source& source)
{
static_assert(sizeof(Dest) <= sizeof(Source),
"bit_cast<Dest>(const Source&) - sizeof(Dest) <= sizeof(Source)");
Dest dest;
::memcpy(&dest, &source, sizeof(Dest));
return dest;
}
// FORENOTE(bill): There used to be a magic_cast that was equivalent to
// a C-style cast but I removed it as I could not get it work as intented
// for everything using only C++ style casts
2015-10-05 16:58:47 -04:00
2015-10-05 16:30:55 -04:00
#if !defined(GB_CASTS_WITHOUT_NAMESPACE)
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_END
2015-10-05 16:30:55 -04:00
#endif // GB_CASTS_WITHOUT_NAMESPACE
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_START
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Memory ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-10-18 07:18:54 -04:00
/// Mutex
2015-09-27 14:03:47 -04:00
struct Mutex
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-09-27 14:03:47 -04:00
HANDLE win32_mutex;
#else
pthread_mutex_t posix_mutex;
#endif
};
2015-10-18 07:18:54 -04:00
namespace mutex
{
2015-10-28 14:32:42 -04:00
Mutex make();
void destroy(Mutex* mutex);
void lock(Mutex* mutex);
bool try_lock(Mutex* mutex);
void unlock(Mutex* mutex);
2015-10-18 07:18:54 -04:00
} // namespace mutex
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
/// Atomic Types
struct Atomic32 { u32 nonatomic; };
struct Atomic64 { u64 nonatomic; };
2015-10-03 10:26:29 -04:00
namespace atomic
{
2015-10-28 14:32:42 -04:00
// TODO(bill): Should these functions have suffixes or is the overloading fine?
u32 load(const Atomic32* object);
void store(Atomic32* object, u32 value);
u32 compare_exchange_strong(Atomic32* object, u32 expected, u32 desired);
u32 exchanged(Atomic32* object, u32 desired);
u32 fetch_add(Atomic32* object, s32 operand);
u32 fetch_and(Atomic32* object, u32 operand);
u32 fetch_or(Atomic32* object, u32 operand);
u64 load(const Atomic64* object);
void store(Atomic64* object, u64 value);
u64 compare_exchange_strong(Atomic64* object, u64 expected, u64 desired);
u64 exchanged(Atomic64* object, u64 desired);
u64 fetch_add(Atomic64* object, s64 operand);
u64 fetch_and(Atomic64* object, u64 operand);
u64 fetch_or(Atomic64* object, u64 operand);
2015-10-03 10:26:29 -04:00
} // namespace atomic
2015-10-28 14:32:42 -04:00
struct Semaphore
{
#if defined(GB_SYSTEM_WINDOWS)
HANDLE win32_handle;
#else
Mutex mutex;
pthread_cond_t cond;
s32 count;
#endif
};
namespace semaphore
{
Semaphore make();
void destroy(Semaphore* semaphore);
void post(Semaphore* semaphore, u32 count = 1);
void wait(Semaphore* semaphore);
} // namespace semaphore
using Thread_Function = s32(void*);
struct Thread
{
#if defined(GB_SYSTEM_WINDOWS)
HANDLE win32_handle;
#else
pthread_t posix_handle;
#endif
Thread_Function* function;
void* data;
Semaphore semaphore;
usize stack_size;
b32 is_running;
};
namespace thread
{
Thread make();
void destroy(Thread* thread);
void start(Thread* thread, Thread_Function* func, void* data = nullptr, usize stack_size = 0);
void stop(Thread* thread);
bool is_running(const Thread& thread);
} // namespace thread
2015-10-18 07:18:54 -04:00
/// Default alignment for memory allocations
2015-09-28 15:31:26 -04:00
#ifndef GB_DEFAULT_ALIGNMENT
2015-10-18 07:18:54 -04:00
#if defined(GB_ARCH_32_BIT)
#define GB_DEFAULT_ALIGNMENT 4
#elif defined(GB_ARCH_64_BIT)
#define GB_DEFAULT_ALIGNMENT 8
#else
#define GB_DEFAULT_ALIGNMENT 4
#endif
#endif GB_DEFAULT_ALIGNMENT
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
/// Base class for memory allocators
2015-09-27 14:03:47 -04:00
struct Allocator
{
Allocator() {}
virtual ~Allocator() {}
2015-10-18 07:18:54 -04:00
/// Allocates the specified amount of memory aligned to the specified alignment
2015-09-27 14:03:47 -04:00
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT) = 0;
2015-10-18 07:18:54 -04:00
/// Deallocates/frees an allocation made with alloc()
2015-10-04 15:59:40 -04:00
virtual void dealloc(const void* ptr) = 0;
2015-10-18 07:18:54 -04:00
/// Returns the amount of usuable memory allocated at `ptr`.
///
/// If the allocator does not support tracking of the allocation size,
/// the function will return -1
2015-09-27 15:43:22 -04:00
virtual s64 allocated_size(const void* ptr) = 0;
2015-10-18 07:18:54 -04:00
/// Returns the total amount of memory allocated by this allocator
///
/// If the allocator does not track memory, the function will return -1
2015-09-27 15:43:22 -04:00
virtual s64 total_allocated() = 0;
2015-09-27 14:03:47 -04:00
// Delete copying
Allocator(const Allocator&) = delete;
Allocator& operator=(const Allocator&) = delete;
};
2015-10-18 07:18:54 -04:00
/// An allocator that used the malloc(). Allocations are padded with the size of
/// the allocation and align them to the desired alignment
2015-09-27 14:03:47 -04:00
struct Heap_Allocator : Allocator
{
struct Header
{
2015-09-27 15:43:22 -04:00
s64 size;
2015-09-27 14:03:47 -04:00
};
2015-10-28 14:32:42 -04:00
Mutex mutex = mutex::make();
s64 total_allocated_count = 0;
s64 allocation_count = 0;
2015-09-27 14:03:47 -04:00
2015-10-05 16:30:55 -04:00
Heap_Allocator() = default;
2015-09-27 14:03:47 -04:00
virtual ~Heap_Allocator();
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
2015-10-04 15:59:40 -04:00
virtual void dealloc(const void* ptr);
2015-09-27 15:43:22 -04:00
virtual s64 allocated_size(const void* ptr);
virtual s64 total_allocated();
Header* get_header_ptr(const void* ptr);
2015-09-27 14:03:47 -04:00
};
struct Arena_Allocator : Allocator
{
2015-10-03 10:26:29 -04:00
Allocator* backing;
void* physical_start;
s64 total_size;
s64 total_allocated_count;
s64 temp_count;
2015-09-27 14:03:47 -04:00
explicit Arena_Allocator(Allocator* backing, usize size);
2015-10-03 10:26:29 -04:00
explicit Arena_Allocator(void* start, usize size);
virtual ~Arena_Allocator();
2015-09-29 10:11:18 -04:00
2015-09-27 14:03:47 -04:00
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
2015-10-04 15:59:40 -04:00
virtual void dealloc(const void* ptr);
2015-09-27 15:43:22 -04:00
virtual s64 allocated_size(const void* ptr);
virtual s64 total_allocated();
2015-09-27 14:03:47 -04:00
};
2015-10-18 07:18:54 -04:00
struct Temporary_Arena_Memory
{
Arena_Allocator* arena;
s64 original_count;
};
template <usize BUFFER_SIZE>
struct Temp_Allocator : Allocator
{
u8 buffer[BUFFER_SIZE];
Allocator* backing;
u8* physical_start;
u8* current_pointer;
u8* physical_end;
usize chunk_size; // Chunks to allocate from backing allocator
explicit Temp_Allocator(Allocator* backing);
2015-10-18 07:18:54 -04:00
virtual ~Temp_Allocator();
virtual void* alloc(usize size, usize align = GB_DEFAULT_ALIGNMENT);
virtual void dealloc(const void*) {}
virtual s64 allocated_size(const void*) { return -1; }
virtual s64 total_allocated() { return -1; }
};
namespace memory
{
void* align_forward(void* ptr, usize align);
2015-10-28 14:32:42 -04:00
void* pointer_add(void* ptr, usize bytes);
void* pointer_sub(void* ptr, usize bytes);
2015-10-18 07:18:54 -04:00
const void* pointer_add(const void* ptr, usize bytes);
const void* pointer_sub(const void* ptr, usize bytes);
void* set(void* ptr, u8 value, usize bytes);
void* zero(void* ptr, usize bytes);
void* copy(void* dest, const void* src, usize bytes);
void* move(void* dest, const void* src, usize bytes);
2015-10-28 14:32:42 -04:00
bool equals(const void* a, const void* b, usize bytes);
2015-10-18 07:18:54 -04:00
} // namespace memory
2015-10-28 14:32:42 -04:00
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); }
2015-10-18 07:18:54 -04:00
template <typename T>
inline T* alloc_struct(Allocator* a) { return static_cast<T*>(alloc(a, sizeof(T), alignof(T))); }
2015-10-18 07:18:54 -04:00
template <typename T>
inline T* alloc_array(Allocator* a, usize count) { return static_cast<T*>(alloc(a, count * sizeof(T), alignof(T))); }
2015-10-18 07:18:54 -04:00
template <typename T, usize count>
inline T* alloc_array(Allocator* a) { return static_cast<T*>(alloc(a, count * sizeof(T), alignof(T))); }
2015-10-18 07:18:54 -04:00
2015-10-03 10:26:29 -04:00
inline void
clear_arena(Arena_Allocator* arena)
2015-10-03 10:26:29 -04:00
{
GB_ASSERT(arena->temp_count == 0,
"%ld Temporary_Arena_Memory have not be cleared", arena->temp_count);
2015-10-03 10:26:29 -04:00
arena->total_allocated_count = 0;
2015-10-03 10:26:29 -04:00
}
2015-09-27 14:03:47 -04:00
inline Temporary_Arena_Memory
make_temporary_arena_memory(Arena_Allocator* arena)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
Temporary_Arena_Memory tmp = {};
tmp.arena = arena;
tmp.original_count = arena->total_allocated_count;
2015-10-04 15:59:40 -04:00
}
inline void
free_temporary_arena_memory(Temporary_Arena_Memory* tmp)
2015-10-04 15:59:40 -04:00
{
if (tmp->arena == nullptr)
2015-10-04 15:59:40 -04:00
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--;
2015-09-27 14:03:47 -04:00
}
2015-10-18 07:18:54 -04:00
template <usize BUFFER_SIZE>
Temp_Allocator<BUFFER_SIZE>::Temp_Allocator(Allocator* backing_)
: backing(backing_)
2015-10-18 07:18:54 -04:00
, chunk_size(4 * 1024) // 4K
{
current_pointer = physical_start = buffer;
physical_end = physical_start + BUFFER_SIZE;
*static_cast<void**>(physical_start) = 0;
current_pointer = memory::pointer_add(current_pointer, sizeof(void*));
}
template <usize BUFFER_SIZE>
Temp_Allocator<BUFFER_SIZE>::~Temp_Allocator()
{
void* ptr = *static_cast<void**>(buffer);
while (ptr)
{
void* next = *static_cast<void**>(ptr);
backing_->dealloc(ptr);
ptr = next;
}
}
template <usize BUFFER_SIZE>
void*
Temp_Allocator<BUFFER_SIZE>::alloc(usize size, usize align)
{
current_pointer = (u8*)memory::align_forward(current_pointer, align);
if (size > (usize)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<void**>(physical_start) = ptr;
current_pointer = physical_start = (u8*)ptr;
*static_cast<void**>(physical_start) = 0;
current_pointer = memory::pointer_add(current_pointer, sizeof(void*));
current_pointer = (u8*)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<void*>(p);
}
inline void*
pointer_add(void* ptr, usize bytes)
{
return static_cast<void*>(static_cast<u8*>(ptr) + bytes);
}
inline const void*
pointer_add(const void* ptr, usize bytes)
{
return static_cast<const void*>(static_cast<const u8*>(ptr) + bytes);
}
inline void*
pointer_sub(void* ptr, usize bytes)
{
return static_cast<void*>(static_cast<u8*>(ptr) - bytes);
}
inline const void*
pointer_sub(const void* ptr, usize bytes)
{
return static_cast<const void*>(static_cast<const u8*>(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
2015-10-28 14:32:42 -04:00
equals(const void* a, const void* b, usize bytes)
2015-10-18 07:18:54 -04:00
{
return (memcmp(a, b, bytes) == 0);
}
} // namespace memory
2015-09-28 16:58:33 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 16:58:33 -04:00
/// String ///
2015-09-30 17:12:16 -04:00
/// ///
2015-10-04 15:59:40 -04:00
/// C compatible string ///
/// ///
2015-09-28 16:58:33 -04:00
////////////////////////////////
2015-10-18 07:18:54 -04:00
/// A "better" string type that is compatible with C style read-only functions
2015-09-28 16:58:33 -04:00
using String = char*;
2015-10-18 07:18:54 -04:00
namespace string
{
using Size = u32;
struct Header
2015-09-28 16:58:33 -04:00
{
Allocator* allocator;
2015-10-18 07:18:54 -04:00
Size len;
Size cap;
2015-09-28 16:58:33 -04:00
};
2015-10-18 07:18:54 -04:00
inline Header* header(String str) { return (Header*)str - 1; }
2015-09-28 16:58:33 -04:00
String make(Allocator* a, const char* str = "");
String make(Allocator* a, const void* str, Size len);
2015-10-28 14:32:42 -04:00
void free(String str);
2015-09-28 16:58:33 -04:00
String duplicate(Allocator* a, const String str);
2015-09-28 16:58:33 -04:00
2015-10-18 07:18:54 -04:00
Size length(const String str);
Size capacity(const String str);
Size available_space(const String str);
2015-09-28 16:58:33 -04:00
2015-10-18 07:18:54 -04:00
void clear(String str);
2015-09-28 16:58:33 -04:00
void append(String* str, const String other);
void append_cstring(String* str, const char* other);
void append(String* str, const void* other, Size len);
2015-09-28 16:58:33 -04:00
void make_space_for(String* str, Size add_len);
2015-10-18 07:18:54 -04:00
usize allocation_size(const String str);
2015-09-28 16:58:33 -04:00
2015-10-18 07:18:54 -04:00
bool equals(const String lhs, const String rhs);
2015-10-28 14:32:42 -04:00
int compare(const String lhs, const String rhs); // NOTE(bill): three-way comparison
2015-09-28 16:58:33 -04:00
void trim(String* str, const char* cut_set);
2015-10-18 07:18:54 -04:00
} // namespace string
2015-10-03 10:26:29 -04:00
// TODO(bill): string libraries
2015-09-28 16:58:33 -04:00
2015-10-28 14:32:42 -04:00
namespace strconv
{
// Inspired by the golang strconv library but not exactly due to numerous reasons
// TODO(bill): Should this use gb::String or just plain old C Strings?
bool parse_bool(const char* str, bool* value);
bool parse_f32(const char* str, f32* value);
bool parse_f64(const char* str, f64* value);
bool parse_int(const char* str, int base, s8* value);
bool parse_int(const char* str, int base, s16* value);
bool parse_int(const char* str, int base, s32* value);
bool parse_int(const char* str, int base, s64* value);
bool parse_uint(const char* str, int base, u8* value);
bool parse_uint(const char* str, int base, u16* value);
bool parse_uint(const char* str, int base, u32* value);
bool parse_uint(const char* str, int base, u64* value);
void format_bool(bool value, char* buffer, usize len);
void format_f32(f32 value, char* buffer, usize len);
void format_f64(f64 value, char* buffer, usize len);
void format_int(s64 value, char* buffer, usize len);
void format_uint(u64 value, char* buffer, usize len);
} // namespace strconv
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Array ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-10-18 07:18:54 -04:00
/// Dynamic resizable array for POD types only
2015-09-27 14:03:47 -04:00
template <typename T>
struct Array
{
Allocator* allocator;
2015-09-27 15:43:22 -04:00
s64 count;
2015-10-18 07:18:54 -04:00
s64 capacity;
2015-09-27 15:43:22 -04:00
T* data;
2015-09-27 14:03:47 -04:00
2015-09-27 15:43:22 -04:00
Array() = default;
2015-10-18 07:18:54 -04:00
Array(const Array& array);
explicit Array(Allocator* a, usize count = 0);
2015-10-18 07:18:54 -04:00
~Array();
Array& operator=(const Array& array);
2015-10-28 14:32:42 -04:00
inline const T&
operator[](usize index) const
{
#if GB_ARRAY_BOUND_CHECKING
GB_ASSERT(index < static_cast<usize>(capacity), "Array out of bounds");
#endif
return data[index];
}
2015-09-27 14:03:47 -04:00
2015-10-28 14:32:42 -04:00
inline T&
operator[](usize index)
{
#if GB_ARRAY_BOUND_CHECKING
GB_ASSERT(index < static_cast<usize>(capacity), "Array out of bounds");
#endif
return data[index];
}
2015-09-27 14:03:47 -04:00
};
2015-10-18 07:18:54 -04:00
namespace array
{
/// Helper functions to make and free an array
template <typename T> Array<T> make(Allocator* allocator, usize count = 0);
template <typename T> void free(Array<T>* array);
2015-10-18 07:18:54 -04:00
/// Appends `item` to the end of the array
template <typename T> void append(Array<T>* a, const T& item);
2015-10-18 07:18:54 -04:00
/// Appends `items[count]` to the end of the array
template <typename T> void append(Array<T>* a, const T* items, usize count);
2015-10-18 07:18:54 -04:00
/// Pops the last item form the array. The array cannot be empty.
template <typename T> void pop_back(Array<T>* a);
2015-10-18 07:18:54 -04:00
/// Removes all items from the array - does not free memory
template <typename T> void clear(Array<T>* a);
2015-10-18 07:18:54 -04:00
/// Modify the size of a array - only reallocates when necessary
template <typename T> void resize(Array<T>* a, usize count);
2015-10-18 07:18:54 -04:00
/// Makes sure that the array has at least the specified capacity - or the array the grows
template <typename T> void reserve(Array<T>* a, usize capacity);
2015-10-18 07:18:54 -04:00
/// Reallocates the array to the specific capacity
template <typename T> void set_capacity(Array<T>* a, usize capacity);
2015-10-18 07:18:54 -04:00
/// Grows the array to keep append() to be O(1)
template <typename T> void grow(Array<T>* a, usize min_capacity = 0);
2015-10-18 07:18:54 -04:00
} // namespace array
/// Used to iterate over the array with a C++11 for loop
2015-09-27 14:03:47 -04:00
template <typename T> inline T* begin(Array<T>& a) { return a.data; }
template <typename T> inline const T* begin(const Array<T>& a) { return a.data; }
template <typename T> inline T* end(Array<T>& a) { return a.data + a.count; }
template <typename T> inline const T* end(const Array<T>& a) { return a.data + a.count; }
2015-09-27 15:43:22 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 15:43:22 -04:00
/// Hash Table ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 15:43:22 -04:00
////////////////////////////////
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
/// Hash table for POD types only with a u64 key
2015-09-27 14:03:47 -04:00
template <typename T>
2015-09-27 15:43:22 -04:00
struct Hash_Table
2015-09-27 14:03:47 -04:00
{
2015-09-27 15:43:22 -04:00
struct Entry
2015-09-27 14:03:47 -04:00
{
2015-09-27 15:43:22 -04:00
u64 key;
s64 next;
T value;
};
2015-09-27 14:03:47 -04:00
2015-09-27 15:43:22 -04:00
Array<s64> hashes;
Array<Entry> entries;
2015-09-27 14:03:47 -04:00
2015-09-27 15:43:22 -04:00
Hash_Table() = default;
explicit Hash_Table(Allocator* a);
Hash_Table(const Hash_Table<T>& other);
Hash_Table<T>& operator=(const Hash_Table<T>& other);
2015-09-27 15:43:22 -04:00
~Hash_Table() = default;
};
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
namespace hash_table
{
/// Helper function to make a hash table
template <typename T> Hash_Table<T> make(Allocator* a);
2015-10-18 07:18:54 -04:00
/// Return `true` if the specified key exist in the hash table
template <typename T> bool has(const Hash_Table<T>& h, u64 key);
/// Returns the value stored at the key, or a `default_value` if the key is not found in the hash table
template <typename T> const T& get(const Hash_Table<T>& h, u64 key, const T& default_value);
/// Sets the value for the key in the hash table
template <typename T> void set(Hash_Table<T>* h, u64 key, const T& value);
2015-10-18 07:18:54 -04:00
/// Removes the key from the hash table if it exists
template <typename T> void remove(Hash_Table<T>* h, u64 key);
2015-10-18 07:18:54 -04:00
/// Resizes the hash table's lookup table to the specified size
template <typename T> void reserve(Hash_Table<T>* h, usize capacity);
2015-10-18 07:18:54 -04:00
/// Remove all elements from the hash table
template <typename T> void clear(Hash_Table<T>* h);
2015-10-18 07:18:54 -04:00
} // namespace hash_table
/// Used to iterate over the array with a C++11 for loop - in random order
2015-10-05 16:30:55 -04:00
template <typename T> typename const Hash_Table<T>::Entry* begin(const Hash_Table<T>& h);
template <typename T> typename const Hash_Table<T>::Entry* end(const Hash_Table<T>& h);
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
namespace multi_hash_table
{
/// Outputs all the items that with the specified key
2015-10-28 14:32:42 -04:00
template <typename T> void get(const Hash_Table<T>& h, u64 key, Array<T>& items);
2015-10-18 07:18:54 -04:00
/// Returns the count of entries with the specified key
2015-10-28 14:32:42 -04:00
template <typename T> usize count(const Hash_Table<T>& h, u64 key);
2015-10-18 07:18:54 -04:00
/// Finds the first entry with specified key in the hash table
template <typename T> typename const Hash_Table<T>::Entry* find_first(const Hash_Table<T>& h, u64 key);
/// Finds the next entry with same key as `e`
template <typename T> typename const Hash_Table<T>::Entry* find_next(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e);
/// Inserts the `value` as an additional value for the specified key
template <typename T> void insert(Hash_Table<T>* h, u64 key, const T& value);
2015-10-18 07:18:54 -04:00
/// Removes a specified entry `e` from the hash table
template <typename T> void remove_entry(Hash_Table<T>* h, typename const Hash_Table<T>::Entry* e);
2015-10-18 07:18:54 -04:00
/// Removes all entries with from the hash table with the specified key
template <typename T> void remove_all(Hash_Table<T>* h, u64 key);
2015-10-18 07:18:54 -04:00
} // namespace multi_hash_table
2015-10-28 14:32:42 -04:00
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Array ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-28 15:31:26 -04:00
template <typename T>
2015-10-18 07:18:54 -04:00
inline
Array<T>::Array(Allocator* a, usize count_)
: allocator(a)
2015-10-18 07:18:54 -04:00
, count(0)
, capacity(0)
, data(nullptr)
{
2015-10-18 07:18:54 -04:00
if (count_ > 0)
2015-09-27 14:03:47 -04:00
{
2015-09-28 15:31:26 -04:00
data = alloc_array<T>(a, count_);
if (data)
2015-10-18 07:18:54 -04:00
count = capacity = count_;
2015-09-28 15:31:26 -04:00
}
}
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
template <typename T>
2015-10-28 14:32:42 -04:00
inline
2015-10-18 07:18:54 -04:00
Array<T>::Array(const Array<T>& other)
: allocator(other.allocator)
, count(0)
, capacity(0)
, data(nullptr)
{
const auto n = other.count;
array::set_capacity(this, n);
2015-10-18 07:18:54 -04:00
memory::copy(data, other.data, n * sizeof(T));
count = n;
}
2015-09-28 15:31:26 -04:00
2015-10-18 07:18:54 -04:00
template <typename T>
2015-10-28 14:32:42 -04:00
inline
Array<T>::~Array()
2015-10-18 07:18:54 -04:00
{
if (allocator)
dealloc(allocator, data);
2015-10-18 07:18:54 -04:00
}
template <typename T>
Array<T>&
Array<T>::operator=(const Array<T>& other)
{
const auto n = other.count;
array::resize(this, n);
2015-10-18 07:18:54 -04:00
memory::copy(data, other.data, n * sizeof(T));
return *this;
}
namespace array
{
2015-09-28 15:31:26 -04:00
template <typename T>
inline Array<T>
make(Allocator* allocator, usize count)
2015-09-27 14:03:47 -04:00
{
2015-09-28 15:31:26 -04:00
Array<T> array = {};
array.allocator = allocator;
2015-09-28 15:31:26 -04:00
array.count = 0;
2015-10-18 07:18:54 -04:00
array.capacity = 0;
2015-09-28 15:31:26 -04:00
array.data = nullptr;
if (count > 0)
2015-09-27 14:03:47 -04:00
{
2015-09-28 15:31:26 -04:00
array.data = alloc_array<T>(allocator, count);
if (array.data)
2015-10-18 07:18:54 -04:00
array.count = array.capacity = count;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return array;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
dealloc(Array<T>* array)
2015-09-27 14:03:47 -04:00
{
2015-09-28 15:31:26 -04:00
if (array.allocator)
dealloc(array.allocator, array.data);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
append(Array<T>* a, const T& item)
2015-09-28 15:31:26 -04:00
{
if (a->capacity < a->count + 1)
array::grow(a);
a->data[a->count++] = item;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
append(Array<T>* a, const T* items, usize count)
2015-09-27 14:03:47 -04:00
{
if (a->capacity <= a->count + count)
2015-10-28 14:32:42 -04:00
array::grow(a, a->count + count);
2015-09-27 14:03:47 -04:00
memory::copy(&a->data[a->count], items, count * sizeof(T));
a->count += count;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
pop_back(Array<T>* a)
2015-09-27 14:03:47 -04:00
{
GB_ASSERT(a->count > 0);
2015-09-27 14:03:47 -04:00
a->count--;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
clear(Array<T>* a)
2015-09-27 14:03:47 -04:00
{
array::resize(a, 0);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
resize(Array<T>* a, usize count)
2015-09-28 15:31:26 -04:00
{
if (a->capacity < static_cast<s64>(count))
array::grow(a, count);
a->count = count;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
reserve(Array<T>* a, usize capacity)
2015-09-28 15:31:26 -04:00
{
if (a->capacity < static_cast<s64>(capacity))
array::set_capacity(a, capacity);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
set_capacity(Array<T>* a, usize capacity)
2015-09-28 15:31:26 -04:00
{
if (static_cast<s64>(capacity) == a->capacity)
2015-09-28 15:31:26 -04:00
return;
2015-09-27 14:03:47 -04:00
if (static_cast<s64>(capacity) < a->count)
array::resize(a, capacity);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
T* data = nullptr;
2015-10-18 07:18:54 -04:00
if (capacity > 0)
2015-09-28 15:31:26 -04:00
{
data = alloc_array<T>(a->allocator, capacity);
memory::copy(data, a->data, a->count * sizeof(T));
2015-09-28 15:31:26 -04:00
}
dealloc(a->allocator, a->data);
a->data = data;
a->capacity = capacity;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
grow(Array<T>* a, usize min_capacity)
2015-09-28 15:31:26 -04:00
{
usize capacity = 2 * a->capacity + 2;
2015-10-18 07:18:54 -04:00
if (capacity < min_capacity)
capacity = min_capacity;
set_capacity(a, capacity);
2015-09-28 15:31:26 -04:00
}
2015-10-18 07:18:54 -04:00
} // namespace array
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Hash Table ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-10-18 07:18:54 -04:00
template <typename T>
inline
Hash_Table<T>::Hash_Table(Allocator* a)
: hashes(a)
, entries(a)
{
}
template <typename T>
2015-10-28 14:32:42 -04:00
inline
Hash_Table<T>::Hash_Table(const Hash_Table<T>& other)
: hashes(other.hashes)
, entries(other.entries)
{
}
template <typename T>
inline Hash_Table<T>&
Hash_Table<T>::operator=(const Hash_Table<T>& other)
2015-10-18 07:18:54 -04:00
{
hashes = other.hashes;
entries = other.entries;
return *this;
2015-10-18 07:18:54 -04:00
}
2015-10-18 07:18:54 -04:00
namespace hash_table
{
template <typename T>
inline Hash_Table<T>
make(Allocator* a)
2015-10-18 07:18:54 -04:00
{
return Hash_Table<T>(a);
2015-10-18 07:18:54 -04:00
}
2015-09-28 15:31:26 -04:00
namespace impl
{
struct Find_Result
{
s64 hash_index;
s64 data_prev;
s64 entry_index;
2015-09-28 15:31:26 -04:00
};
2015-09-27 14:03:47 -04:00
template <typename T> usize add_entry(Hash_Table<T>* h, u64 key);
template <typename T> void erase(Hash_Table<T>* h, const Find_Result& fr);
2015-10-18 07:18:54 -04:00
template <typename T> Find_Result find_result(const Hash_Table<T>& h, u64 key);
template <typename T> Find_Result find_result(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e);
template <typename T> s64 make_entry(Hash_Table<T>* h, u64 key);
template <typename T> void find_and_erase_entry(Hash_Table<T>* h, u64 key);
2015-10-18 07:18:54 -04:00
template <typename T> s64 find_entry_or_fail(const Hash_Table<T>& h, u64 key);
template <typename T> s64 find_or_make_entry(Hash_Table<T>* h, u64 key);
template <typename T> void rehash(Hash_Table<T>* h, usize new_capacity);
template <typename T> void grow(Hash_Table<T>* h);
template <typename T> bool is_full(Hash_Table<T>* h);
2015-10-18 07:18:54 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
usize
add_entry(Hash_Table<T>* h, u64 key)
2015-09-28 15:31:26 -04:00
{
typename Hash_Table<T>::Entry e;
e.key = key;
e.next = -1;
usize e_index = h->entries.count;
array::append(&h->entries, e);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return e_index;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
void
erase(Hash_Table<T>* h, const Find_Result& fr)
2015-09-28 15:31:26 -04:00
{
if (fr.data_prev < 0)
h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
2015-09-28 15:31:26 -04:00
else
h->entries[fr.data_prev].next = h->entries[fr.entry_index].next;
2015-09-27 14:03:47 -04:00
array::pop_back(h->entries); // updated array count
2015-09-27 14:03:47 -04:00
if (fr.entry_index == h->entries.count)
2015-09-28 15:31:26 -04:00
return;
2015-09-27 14:03:47 -04:00
h->entries[fr.entry_index] = h->entries[h->entries.count];
2015-09-27 14:03:47 -04:00
auto last = impl::find_result(h, h->entries[fr.entry_index].key);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
if (last.data_prev < 0)
h->hashes[last.hash_index] = fr.entry_index;
2015-09-28 15:31:26 -04:00
else
h->entries[last.entry_index].next = fr.entry_index;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
Find_Result
2015-10-18 07:18:54 -04:00
find_result(const Hash_Table<T>& h, u64 key)
2015-09-28 15:31:26 -04:00
{
Find_Result fr;
fr.hash_index = -1;
fr.data_prev = -1;
fr.entry_index = -1;
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
if (h.hashes.count == 0)
return fr;
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
fr.hash_index = key % h.hashes.count;
fr.entry_index = h.hashes[fr.hash_index];
while (fr.entry_index >= 0)
2015-09-28 15:31:26 -04:00
{
if (h.entries[fr.entry_index].key == key)
2015-09-28 15:31:26 -04:00
return fr;
fr.data_prev = fr.entry_index;
fr.entry_index = h.entries[fr.entry_index].next;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return fr;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
Find_Result
2015-10-18 07:18:54 -04:00
find_result(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e)
2015-09-28 15:31:26 -04:00
{
Find_Result fr;
2015-10-05 16:58:47 -04:00
fr.hash_index = -1;
fr.data_prev = -1;
fr.entry_index = -1;
2015-10-05 16:58:47 -04:00
if (h.hashes.count == 0 || !e)
return fr;
fr.hash_index = key % h.hashes.count;
fr.entry_index = h.hashes[fr.hash_index];
while (fr.entry_index >= 0)
2015-10-05 16:58:47 -04:00
{
if (&h.entries[fr.entry_index] == e)
2015-10-05 16:58:47 -04:00
return fr;
fr.data_prev = fr.entry_index;
fr.entry_index = h.entries[fr.entry_index].next;
2015-10-05 16:58:47 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return fr;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
2015-10-18 07:18:54 -04:00
s64
make_entry(Hash_Table<T>* h, u64 key)
2015-09-28 15:31:26 -04:00
{
const Find_Result fr = impl::find_result(*h, key);
2015-10-18 07:18:54 -04:00
const s64 index = impl::add_entry(h, key);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
if (fr.data_prev < 0)
h->hashes[fr.hash_index] = index;
2015-09-28 15:31:26 -04:00
else
h->entries[fr.data_prev].next = index;
2015-09-27 14:03:47 -04:00
h->entries[index].next = fr.entry_index;
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return index;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
void
find_and_erase_entry(Hash_Table<T>* h, u64 key)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
const Find_Result fr = impl::find_result(h, key);
if (fr.entry_index >= 0)
2015-10-18 07:18:54 -04:00
hash_table::erase(h, fr);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
s64
2015-10-18 07:18:54 -04:00
find_entry_or_fail(const Hash_Table<T>& h, u64 key)
2015-09-28 15:31:26 -04:00
{
return impl::find_result(h, key).entry_index;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
s64
find_or_make_entry(Hash_Table<T>* h, u64 key)
2015-09-28 15:31:26 -04:00
{
const auto fr = find_result(*h, key);
if (fr.entry_index >= 0)
return fr.entry_index;
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
s64 index = impl::add_entry(h, key);
2015-09-28 15:31:26 -04:00
if (fr.data_prev < 0)
h->hashes[fr.hash_index] = index;
2015-09-28 15:31:26 -04:00
else
h->entries[fr.data_prev].next = index;
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return index;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
void
rehash(Hash_Table<T>* h, usize new_capacity)
2015-09-27 14:03:47 -04:00
{
auto nh = hash_table::make<T>(h->hashes.allocator);
array::resize(&nh.hashes, new_capacity);
const usize old_count = h->entries.count;
array::resize(&nh.entries, old_count);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
for (usize i = 0; i < new_capacity; i++)
nh.hashes[i] = -1;
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
for (usize i = 0; i < old_count; i++)
{
auto& e = h->entries[i];
multi_hash_table::insert(&nh, e.key, e.value);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
auto empty = hash_table::make<T>(h->hashes.allocator);
h->~Hash_Table<T>();
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
memory::copy(&h, &nh, sizeof(Hash_Table<T>));
memory::copy(&nh, &empty, sizeof(Hash_Table<T>));
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
void
grow(Hash_Table<T>* h)
2015-09-28 15:31:26 -04:00
{
const usize new_capacity = 2 * h->entries.count + 2;
2015-10-18 07:18:54 -04:00
impl::rehash(h, new_capacity);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
bool
is_full(Hash_Table<T>* h)
2015-09-28 15:31:26 -04:00
{
// Make sure that there is enough space
const f32 maximum_load_coefficient = 0.75f;
return h->entries.count >= maximum_load_coefficient * h->hashes.count;
2015-09-28 15:31:26 -04:00
}
} // namespace impl
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline bool
2015-10-18 07:18:54 -04:00
has(const Hash_Table<T>& h, u64 key)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
return impl::find_entry_or_fail(h, key) >= 0;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline const T&
2015-10-18 07:18:54 -04:00
get(const Hash_Table<T>& h, u64 key, const T& default_value)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
const s64 index = impl::find_entry_or_fail(h, key);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
if (index < 0)
return default_value;
return h.entries[index].value;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
set(Hash_Table<T>* h, u64 key, const T& value)
2015-09-28 15:31:26 -04:00
{
if (h->hashes.count == 0)
2015-10-18 07:18:54 -04:00
impl::grow(h);
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
const s64 index = impl::find_or_make_entry(h, key);
h->entries[index].value = value;
2015-10-18 07:18:54 -04:00
if (impl::is_full(h))
impl::grow(h);
2015-09-28 15:31:26 -04:00
}
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
remove(Hash_Table<T>* h, u64 key)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
impl::find_and_erase_entry(h, key);
2015-09-28 15:31:26 -04:00
}
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
reserve(Hash_Table<T>* h, usize capacity)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
impl::rehash(h, capacity);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
clear(Hash_Table<T>* h)
2015-09-28 15:31:26 -04:00
{
array::clear(&h->hashes);
array::clear(&h->entries);
2015-09-28 15:31:26 -04:00
}
2015-10-18 07:18:54 -04:00
} // namespace hash_table
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
2015-10-05 16:30:55 -04:00
inline typename const Hash_Table<T>::Entry*
2015-09-28 15:31:26 -04:00
begin(const Hash_Table<T>& h)
{
return begin(h.entries);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
2015-10-05 16:30:55 -04:00
inline typename const Hash_Table<T>::Entry*
2015-09-28 15:31:26 -04:00
end(const Hash_Table<T>& h)
{
return end(h.entries);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
namespace multi_hash_table
{
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
2015-10-28 14:32:42 -04:00
get(const Hash_Table<T>& h, u64 key, Array<T>& items)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
auto e = multi_hash_table::find_first(h, key);
2015-09-28 15:31:26 -04:00
while (e)
{
2015-10-18 07:18:54 -04:00
array::append(items, e->value);
e = multi_hash_table::find_next(h, e);
2015-09-28 15:31:26 -04:00
}
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline usize
2015-10-28 14:32:42 -04:00
count(const Hash_Table<T>& h, u64 key)
2015-09-28 15:31:26 -04:00
{
usize count = 0;
2015-10-18 07:18:54 -04:00
auto e = multi_hash_table::find_first(h, key);
2015-09-28 15:31:26 -04:00
while (e)
{
2015-10-02 08:11:18 -04:00
count++;
2015-10-18 07:18:54 -04:00
e = multi_hash_table::find_next(h, e);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return count;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
2015-10-05 16:30:55 -04:00
inline typename const Hash_Table<T>::Entry*
2015-10-18 07:18:54 -04:00
find_first(const Hash_Table<T>& h, u64 key)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
const s64 index = multi_hash_table::find_first(h, key);
2015-09-28 15:31:26 -04:00
if (index < 0)
return nullptr;
return &h.entries[index];
2015-09-28 15:31:26 -04:00
}
template <typename T>
2015-10-05 16:30:55 -04:00
typename const Hash_Table<T>::Entry*
2015-10-18 07:18:54 -04:00
find_next(const Hash_Table<T>& h, typename const Hash_Table<T>::Entry* e)
2015-09-28 15:31:26 -04:00
{
if (!e)
return nullptr;
auto index = e->next;
while (index >= 0)
{
if (h.entries[index].ley == e->key)
return &h.entries[index];
index = h.entries[index].next;
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
return nullptr;
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
insert(Hash_Table<T>* h, u64 key, const T& value)
2015-09-28 15:31:26 -04:00
{
if (h->hashes.count == 0)
2015-10-18 07:18:54 -04:00
hash_table::impl::grow(h);
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
auto next = hash_table::impl::make_entry(h, key);
h->entries[next].value = value;
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
if (hash_table::impl::is_full(h))
hash_table::impl::grow(h);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
remove_entry(Hash_Table<T>* h, typename const Hash_Table<T>::Entry* e)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
const auto fr = hash_table::impl::find_result(h, e);
if (fr.entry_index >= 0)
2015-10-18 07:18:54 -04:00
hash_table::impl::erase(h, fr);
2015-09-28 15:31:26 -04:00
}
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
template <typename T>
inline void
remove_all(Hash_Table<T>* h, u64 key)
2015-09-28 15:31:26 -04:00
{
2015-10-18 07:18:54 -04:00
while (hash_table::has(h, key))
hash_table::remove(h, key);
2015-09-28 15:31:26 -04:00
}
2015-10-18 07:18:54 -04:00
} // namespace multi_hash_table
2015-09-27 14:03:47 -04:00
2015-09-28 16:58:33 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 16:58:33 -04:00
/// Hash ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 16:58:33 -04:00
////////////////////////////////
namespace hash
{
2015-09-28 18:57:43 -04:00
u32 adler32(const void* key, u32 num_bytes);
2015-09-28 16:58:33 -04:00
2015-09-28 18:57:43 -04:00
u32 crc32(const void* key, u32 num_bytes);
2015-09-28 16:58:33 -04:00
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
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Time ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
struct Time
{
s64 microseconds;
};
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
extern const Time TIME_ZERO;
// NOTE(bill): namespace time cannot be used for numerous reasons
2015-10-28 14:32:42 -04:00
namespace time
{
Time now();
void sleep(Time time);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time seconds(f32 s);
Time milliseconds(s32 ms);
Time microseconds(s64 us);
2015-10-03 10:26:29 -04:00
2015-10-28 14:32:42 -04:00
f32 as_seconds(Time t);
s32 as_milliseconds(Time t);
s64 as_microseconds(Time t);
} // namespace time
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
bool operator==(Time left, Time right);
bool operator!=(Time left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
bool operator<(Time left, Time right);
bool operator>(Time left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
bool operator<=(Time left, Time right);
bool operator>=(Time left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time operator-(Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time operator+(Time left, Time right);
Time operator-(Time left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time& operator+=(Time& left, Time right);
Time& operator-=(Time& left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time operator*(Time left, f32 right);
Time operator*(Time left, s64 right);
Time operator*(f32 left, Time right);
Time operator*(s64 left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time& operator*=(Time& left, f32 right);
Time& operator*=(Time& left, s64 right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time operator/(Time left, f32 right);
Time operator/(Time left, s64 right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
Time& operator/=(Time& left, f32 right);
Time& operator/=(Time& left, s64 right);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
f32 operator/(Time left, Time right);
2015-09-27 14:03:47 -04:00
2015-09-29 10:11:18 -04:00
Time operator%(Time left, Time right);
2015-09-28 15:31:26 -04:00
Time& operator%=(Time& left, Time right);
2015-09-27 14:03:47 -04:00
2015-10-28 14:32:42 -04:00
////////////////////////////////
/// ///
/// 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
2015-09-27 15:43:22 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Math Types ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 15:43:22 -04:00
////////////////////////////////
2015-10-28 14:32:42 -04:00
// TODO(bill): Should the math part be a separate library?
2015-09-28 15:31:26 -04:00
struct Vector2
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
union
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
struct { f32 x, y; };
f32 data[2];
};
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
inline const f32& operator[](usize index) const { return data[index]; }
inline f32& operator[](usize index) { return data[index]; }
};
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
struct Vector3
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
union
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
struct { f32 x, y, z; };
2015-10-18 07:18:54 -04:00
struct { f32 r, g, b; };
2015-09-28 15:31:26 -04:00
Vector2 xy;
2015-09-29 10:11:18 -04:00
f32 data[3];
2015-09-28 15:31:26 -04:00
};
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
inline const f32& operator[](usize index) const { return data[index]; }
inline f32& operator[](usize index) { return data[index]; }
};
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
struct Vector4
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
union
{
struct { f32 x, y, z, w; };
2015-10-18 07:18:54 -04:00
struct { f32 r, g, b, a; };
2015-09-28 15:31:26 -04:00
struct { Vector2 xy, zw; };
Vector3 xyz;
2015-10-18 07:18:54 -04:00
Vector3 rgb;
2015-09-28 15:31:26 -04:00
f32 data[4];
};
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
inline const f32& operator[](usize index) const { return data[index]; }
inline f32& operator[](usize index) { return data[index]; }
};
2015-10-04 15:59:40 -04:00
struct Complex
{
2015-10-05 13:17:30 -04:00
union
2015-10-04 15:59:40 -04:00
{
struct { f32 x, y; };
struct { f32 real, imag; };
f32 data[2];
};
inline const f32& operator[](usize index) const { return data[index]; }
inline f32& operator[](usize index) { return data[index]; }
};
2015-09-28 15:31:26 -04:00
struct Quaternion
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
union
{
struct { f32 x, y, z, w; };
Vector3 xyz;
f32 data[4];
};
2015-09-29 10:11:18 -04:00
inline const f32& operator[](usize index) const { return data[index]; }
inline f32& operator[](usize index) { return data[index]; }
};
struct Matrix2
{
union
{
struct { Vector2 x, y; };
Vector2 columns[2];
f32 data[4];
};
inline const Vector2& operator[](usize index) const { return columns[index]; }
inline Vector2& operator[](usize index) { return columns[index]; }
2015-09-28 15:31:26 -04:00
};
2015-09-27 15:43:22 -04:00
2015-09-29 10:11:18 -04:00
struct Matrix3
{
union
{
struct { Vector3 x, y, z; };
Vector3 columns[3];
f32 data[9];
};
inline const Vector3& operator[](usize index) const { return columns[index]; }
inline Vector3& operator[](usize index) { return columns[index]; }
};
2015-09-28 15:31:26 -04:00
struct Matrix4
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
union
{
struct { Vector4 x, y, z, w; };
2015-09-29 10:11:18 -04:00
Vector4 columns[4];
2015-09-28 15:31:26 -04:00
f32 data[16];
};
2015-09-27 15:43:22 -04:00
2015-09-29 10:11:18 -04:00
inline const Vector4& operator[](usize index) const { return columns[index]; }
inline Vector4& operator[](usize index) { return columns[index]; }
2015-09-28 15:31:26 -04:00
};
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
struct Euler_Angles
2015-09-27 15:43:22 -04:00
{
2015-09-28 15:31:26 -04:00
// NOTE(bill): All angles in radians
2015-10-18 07:18:54 -04:00
f32 pitch, yaw, roll;
2015-09-28 15:31:26 -04:00
};
2015-09-27 15:43:22 -04:00
struct Transform
{
2015-10-18 07:18:54 -04:00
Vector3 position;
Quaternion orientation;
Vector3 scale;
};
2015-10-03 10:26:29 -04:00
struct Aabb
{
2015-10-18 07:18:54 -04:00
Vector3 center, half_size;
};
struct Oobb
{
Matrix4 tm;
Aabb aabb;
2015-10-03 10:26:29 -04:00
};
struct Sphere
{
Vector3 center;
f32 radius;
};
struct Plane
{
Vector3 normal;
f32 distance; // negative distance to origin
};
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Math Type Op Overloads ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Vector2 Operators
bool operator==(const Vector2& a, const Vector2& b);
bool operator!=(const Vector2& a, const Vector2& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector2 operator-(const Vector2& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector2 operator+(const Vector2& a, const Vector2& b);
Vector2 operator-(const Vector2& a, const Vector2& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector2 operator*(const Vector2& a, f32 scalar);
Vector2 operator*(f32 scalar, const Vector2& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector2 operator/(const Vector2& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector2 operator*(const Vector2& a, const Vector2& b); // Hadamard Product
Vector2 operator/(const Vector2& a, const Vector2& b); // Hadamard Product
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector2& operator+=(Vector2& a, const Vector2& b);
Vector2& operator-=(Vector2& a, const Vector2& b);
Vector2& operator*=(Vector2& a, f32 scalar);
Vector2& operator/=(Vector2& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Vector3 Operators
bool operator==(const Vector3& a, const Vector3& b);
bool operator!=(const Vector3& a, const Vector3& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector3 operator-(const Vector3& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector3 operator+(const Vector3& a, const Vector3& b);
Vector3 operator-(const Vector3& a, const Vector3& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector3 operator*(const Vector3& a, f32 scalar);
Vector3 operator*(f32 scalar, const Vector3& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector3 operator/(const Vector3& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector3 operator*(const Vector3& a, const Vector3& b); // Hadamard Product
Vector3 operator/(const Vector3& a, const Vector3& b); // Hadamard Product
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector3& operator+=(Vector3& a, const Vector3& b);
Vector3& operator-=(Vector3& a, const Vector3& b);
Vector3& operator*=(Vector3& a, f32 scalar);
Vector3& operator/=(Vector3& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Vector4 Operators
bool operator==(const Vector4& a, const Vector4& b);
bool operator!=(const Vector4& a, const Vector4& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector4 operator-(const Vector4& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector4 operator+(const Vector4& a, const Vector4& b);
Vector4 operator-(const Vector4& a, const Vector4& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector4 operator*(const Vector4& a, f32 scalar);
Vector4 operator*(f32 scalar, const Vector4& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector4 operator/(const Vector4& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector4 operator*(const Vector4& a, const Vector4& b); // Hadamard Product
Vector4 operator/(const Vector4& a, const Vector4& b); // Hadamard Product
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Vector4& operator+=(Vector4& a, const Vector4& b);
Vector4& operator-=(Vector4& a, const Vector4& b);
Vector4& operator*=(Vector4& a, f32 scalar);
Vector4& operator/=(Vector4& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-10-04 15:59:40 -04:00
// Complex Operators
bool operator==(const Complex& a, const Complex& b);
bool operator!=(const Complex& a, const Complex& b);
Complex operator-(const Complex& a);
Complex operator+(const Complex& a, const Complex& b);
Complex operator-(const Complex& a, const Complex& b);
Complex operator*(const Complex& a, const Complex& b);
Complex operator*(const Complex& a, f32 s);
Complex operator*(f32 s, const Complex& a);
Complex operator/(const Complex& a, f32 s);
2015-09-28 15:31:26 -04:00
// Quaternion Operators
bool operator==(const Quaternion& a, const Quaternion& b);
bool operator!=(const Quaternion& a, const Quaternion& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Quaternion operator-(const Quaternion& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Quaternion operator+(const Quaternion& a, const Quaternion& b);
Quaternion operator-(const Quaternion& a, const Quaternion& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Quaternion operator*(const Quaternion& a, const Quaternion& b);
Quaternion operator*(const Quaternion& a, f32 s);
Quaternion operator*(f32 s, const Quaternion& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Quaternion operator/(const Quaternion& a, f32 s);
2015-09-27 15:43:22 -04:00
Vector3 operator*(const Quaternion& a, const Vector3& v); // Rotate v by a
2015-09-30 17:12:16 -04:00
// Matrix2 Operators
bool operator==(const Matrix2& a, const Matrix2& b);
bool operator!=(const Matrix2& a, const Matrix2& b);
Matrix2 operator+(const Matrix2& a, const Matrix2& b);
Matrix2 operator-(const Matrix2& a, const Matrix2& b);
Matrix2 operator*(const Matrix2& a, const Matrix2& b);
Vector2 operator*(const Matrix2& a, const Vector2& v);
Matrix2 operator*(const Matrix2& a, f32 scalar);
Matrix2 operator*(f32 scalar, const Matrix2& a);
Matrix2 operator/(const Matrix2& a, f32 scalar);
Matrix2& operator+=(Matrix2& a, const Matrix2& b);
Matrix2& operator-=(Matrix2& a, const Matrix2& b);
Matrix2& operator*=(Matrix2& a, const Matrix2& b);
// Matrix3 Operators
bool operator==(const Matrix3& a, const Matrix3& b);
bool operator!=(const Matrix3& a, const Matrix3& b);
Matrix3 operator+(const Matrix3& a, const Matrix3& b);
Matrix3 operator-(const Matrix3& a, const Matrix3& b);
Matrix3 operator*(const Matrix3& a, const Matrix3& b);
Vector3 operator*(const Matrix3& a, const Vector3& v);
Matrix3 operator*(const Matrix3& a, f32 scalar);
Matrix3 operator*(f32 scalar, const Matrix3& a);
Matrix3 operator/(const Matrix3& a, f32 scalar);
Matrix3& operator+=(Matrix3& a, const Matrix3& b);
Matrix3& operator-=(Matrix3& a, const Matrix3& b);
Matrix3& operator*=(Matrix3& a, const Matrix3& b);
2015-09-28 15:31:26 -04:00
// Matrix4 Operators
bool operator==(const Matrix4& a, const Matrix4& b);
bool operator!=(const Matrix4& a, const Matrix4& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4 operator+(const Matrix4& a, const Matrix4& b);
Matrix4 operator-(const Matrix4& a, const Matrix4& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4 operator*(const Matrix4& a, const Matrix4& b);
Vector4 operator*(const Matrix4& a, const Vector4& v);
Matrix4 operator*(const Matrix4& a, f32 scalar);
Matrix4 operator*(f32 scalar, const Matrix4& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4 operator/(const Matrix4& a, f32 scalar);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4& operator+=(Matrix4& a, const Matrix4& b);
Matrix4& operator-=(Matrix4& a, const Matrix4& b);
Matrix4& operator*=(Matrix4& a, const Matrix4& b);
2015-09-27 15:43:22 -04:00
// Transform Operators
// World = Parent * Local
Transform operator*(const Transform& ps, const Transform& ls);
Transform& operator*=(Transform* ps, const Transform& ls);
// Local = World / Parent
Transform operator/(const Transform& ws, const Transform& ps);
Transform& operator/=(Transform& ws, const Transform& ps);
2015-09-28 15:31:26 -04:00
//////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Math Functions & Constants ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
//////////////////////////////////
2015-10-04 15:59:40 -04:00
extern const Vector2 VECTOR2_ZERO;
extern const Vector3 VECTOR3_ZERO;
extern const Vector4 VECTOR4_ZERO;
extern const Complex COMPLEX_ZERO;
extern const Quaternion QUATERNION_IDENTITY;
extern const Matrix2 MATRIX2_IDENTITY;
extern const Matrix3 MATRIX3_IDENTITY;
extern const Matrix4 MATRIX4_IDENTITY;
extern const Euler_Angles EULER_ANGLES_ZERO;
extern const Transform TRANSFORM_IDENTITY;
2015-09-28 15:31:26 -04:00
namespace math
{
extern const f32 ZERO;
extern const f32 ONE;
extern const f32 THIRD;
extern const f32 TWO_THIRDS;
extern const f32 E;
extern const f32 PI;
extern const f32 TAU;
extern const f32 SQRT_2;
extern const f32 SQRT_3;
2015-10-05 13:17:30 -04:00
extern const f32 F32_PRECISION;
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Power
f32 sqrt(f32 x);
f32 pow(f32 x, f32 y);
f32 cbrt(f32 x);
f32 fast_inv_sqrt(f32 x);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Trigonometric
f32 sin(f32 radians);
f32 cos(f32 radians);
f32 tan(f32 radians);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 asin(f32 x);
f32 acos(f32 x);
f32 atan(f32 x);
f32 atan2(f32 y, f32 x);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 radians(f32 degrees);
f32 degrees(f32 radians);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Hyperbolic
f32 sinh(f32 x);
f32 cosh(f32 x);
f32 tanh(f32 x);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 asinh(f32 x);
f32 acosh(f32 x);
f32 atanh(f32 x);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Rounding
f32 ceil(f32 x);
f32 floor(f32 x);
f32 mod(f32 x, f32 y);
f32 truncate(f32 x);
f32 round(f32 x);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
s32 sign(s32 x);
s64 sign(s64 x);
f32 sign(f32 x);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Other
f32 abs(f32 x);
s8 abs( s8 x);
s16 abs(s16 x);
s32 abs(s32 x);
s64 abs(s64 x);
2015-09-27 15:43:22 -04:00
2015-10-05 13:17:30 -04:00
bool is_infinite(f32 x);
bool is_nan(f32 x);
2015-10-18 07:18:54 -04:00
#undef min
#undef max
2015-09-28 15:31:26 -04:00
s32 min(s32 a, s32 b);
s64 min(s64 a, s64 b);
f32 min(f32 a, f32 b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
s32 max(s32 a, s32 b);
s64 max(s64 a, s64 b);
f32 max(f32 a, f32 b);
2015-09-27 15:43:22 -04:00
2015-10-18 07:18:54 -04:00
2015-09-28 15:31:26 -04:00
s32 clamp(s32 x, s32 min, s32 max);
s64 clamp(s64 x, s64 min, s64 max);
f32 clamp(f32 x, f32 min, f32 max);
2015-09-27 15:43:22 -04:00
2015-10-03 10:26:29 -04:00
template <typename T>
2015-10-18 07:18:54 -04:00
T lerp(const T& x, const T& y, f32 t);
2015-10-03 10:26:29 -04:00
2015-10-05 13:17:30 -04:00
bool equals(f32 a, f32 b, f32 precision = F32_PRECISION);
2015-10-03 10:26:29 -04:00
template <typename T>
2015-10-28 14:32:42 -04:00
void swap(T* a, T* b);
2015-10-03 10:26:29 -04:00
template <typename T, usize N>
void swap(T (& a)[N], T (& b)[N]);
2015-09-28 15:31:26 -04:00
// Vector2 functions
f32 dot(const Vector2& a, const Vector2& b);
f32 cross(const Vector2& a, const Vector2& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 magnitude(const Vector2& a);
Vector2 normalize(const Vector2& a);
2015-09-27 15:43:22 -04:00
2015-10-03 10:26:29 -04:00
Vector2 hadamard(const Vector2& a, const Vector2& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Vector3 functions
f32 dot(const Vector3& a, const Vector3& b);
Vector3 cross(const Vector3& a, const Vector3& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 magnitude(const Vector3& a);
Vector3 normalize(const Vector3& a);
2015-09-27 15:43:22 -04:00
2015-10-03 10:26:29 -04:00
Vector3 hadamard(const Vector3& a, const Vector3& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
// Vector4 functions
f32 dot(const Vector4& a, const Vector4& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 magnitude(const Vector4& a);
Vector4 normalize(const Vector4& a);
2015-09-27 15:43:22 -04:00
2015-10-03 10:26:29 -04:00
Vector4 hadamard(const Vector4& a, const Vector4& b);
2015-09-27 15:43:22 -04:00
2015-10-04 15:59:40 -04:00
// Complex functions
f32 dot(const Complex& a, const Complex& b);
f32 magnitude(const Complex& a);
f32 norm(const Complex& a);
Complex normalize(const Complex& a);
Complex conjugate(const Complex& a);
Complex inverse(const Complex& a);
f32 complex_angle(const Complex& a);
inline f32 complex_argument(const Complex& a) { return complex_angle(a); }
Complex magnitude_angle(f32 magnitude, f32 radians);
inline Complex complex_polar(f32 magnitude, f32 radians) { return magnitude_angle(magnitude, radians); }
2015-09-28 15:31:26 -04:00
// Quaternion functions
f32 dot(const Quaternion& a, const Quaternion& b);
Quaternion cross(const Quaternion& a, const Quaternion& b);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 magnitude(const Quaternion& a);
2015-10-04 15:59:40 -04:00
f32 norm(const Quaternion& a);
2015-09-28 15:31:26 -04:00
Quaternion normalize(const Quaternion& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Quaternion conjugate(const Quaternion& a);
Quaternion inverse(const Quaternion& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 quaternion_angle(const Quaternion& a);
Vector3 quaternion_axis(const Quaternion& a);
Quaternion axis_angle(const Vector3& axis, f32 radians);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
f32 quaternion_roll(const Quaternion& a);
f32 quaternion_pitch(const Quaternion& a);
f32 quaternion_yaw(const Quaternion& a);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Euler_Angles quaternion_to_euler_angles(const Quaternion& a);
Quaternion euler_angles_to_quaternion(const Euler_Angles& e,
2015-10-05 16:30:55 -04:00
const Vector3& x_axis = {1, 0, 0},
const Vector3& y_axis = {0, 1, 0},
const Vector3& z_axis = {0, 0, 1});
2015-09-27 15:43:22 -04:00
// Spherical Linear Interpolation
Quaternion slerp(const Quaternion& x, const Quaternion& y, f32 t);
// Shoemake's Quaternion Curves
// Sqherical Cubic Interpolation
2015-10-04 15:59:40 -04:00
Quaternion squad(const Quaternion& p,
2015-10-05 16:30:55 -04:00
const Quaternion& a,
const Quaternion& b,
const Quaternion& q,
f32 t);
2015-09-30 17:12:16 -04:00
// Matrix2 functions
Matrix2 transpose(const Matrix2& m);
f32 determinant(const Matrix2& m);
Matrix2 inverse(const Matrix2& m);
2015-10-03 10:26:29 -04:00
Matrix2 hadamard(const Matrix2& a, const Matrix2&b);
2015-10-04 15:59:40 -04:00
Matrix4 matrix2_to_matrix4(const Matrix2& m);
2015-09-30 17:12:16 -04:00
// Matrix3 functions
Matrix3 transpose(const Matrix3& m);
f32 determinant(const Matrix3& m);
Matrix3 inverse(const Matrix3& m);
2015-10-03 10:26:29 -04:00
Matrix3 hadamard(const Matrix3& a, const Matrix3&b);
2015-10-04 15:59:40 -04:00
Matrix4 matrix3_to_matrix4(const Matrix3& m);
2015-09-28 15:31:26 -04:00
// Matrix4 functions
Matrix4 transpose(const Matrix4& m);
f32 determinant(const Matrix4& m);
Matrix4 inverse(const Matrix4& m);
2015-10-03 10:26:29 -04:00
Matrix4 hadamard(const Matrix4& a, const Matrix4&b);
2015-10-05 13:17:30 -04:00
bool is_affine(const Matrix4& m);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4 quaternion_to_matrix4(const Quaternion& a);
Quaternion matrix4_to_quaternion(const Matrix4& m);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4 translate(const Vector3& v);
Matrix4 rotate(const Vector3& v, f32 radians);
Matrix4 scale(const Vector3& v);
Matrix4 ortho(f32 left, f32 right, f32 bottom, f32 top);
Matrix4 ortho(f32 left, f32 right, f32 bottom, f32 top, f32 z_near, f32 z_far);
Matrix4 perspective(f32 fovy_radians, f32 aspect, f32 z_near, f32 z_far);
Matrix4 infinite_perspective(f32 fovy_radians, f32 aspect, f32 z_near);
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Matrix4
look_at_matrix4(const Vector3& eye, const Vector3& center, const Vector3& up = {0, 1, 0});
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
Quaternion
look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up = {0, 1, 0});
2015-09-27 15:43:22 -04:00
// Transform Functions
Vector3 transform_point(const Transform& transform, const Vector3& point);
Transform inverse(const Transform& t);
Matrix4 transform_to_matrix4(const Transform& t);
2015-09-27 15:43:22 -04:00
2015-10-28 14:32:42 -04:00
f32 perlin_noise3(f32 x, f32 y, f32 z, s32 x_wrap = 0, s32 y_wrap = 0, s32 z_wrap = 0);
} // namespace math
namespace aabb
{
Aabb calculate(const void* vertices, usize num_vertices, usize stride, usize offset);
2015-10-05 13:17:30 -04:00
2015-10-28 14:32:42 -04:00
f32 surface_area(const Aabb& aabb);
f32 volume(const Aabb& aabb);
2015-10-05 13:17:30 -04:00
2015-10-28 14:32:42 -04:00
Sphere to_sphere(const Aabb& aabb);
2015-10-03 10:26:29 -04:00
2015-10-05 13:17:30 -04:00
bool contains(const Aabb& aabb, const Vector3& point);
bool contains(const Aabb& a, const Aabb& b);
bool intersects(const Aabb& a, const Aabb& b);
2015-10-28 14:32:42 -04:00
Aabb transform_affine(const Aabb& aabb, const Matrix4& m);
} // namespace aabb
2015-10-05 13:17:30 -04:00
2015-10-28 14:32:42 -04:00
namespace sphere
{
2015-10-05 13:17:30 -04:00
Sphere calculate_min_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset, f32 step);
Sphere calculate_max_bounding_sphere(const void* vertices, usize num_vertices, usize stride, usize offset);
2015-10-28 14:32:42 -04:00
f32 surface_area(const Sphere& s);
f32 volume(const Sphere& s);
Aabb to_aabb(const Sphere& sphere);
2015-10-05 13:17:30 -04:00
2015-10-28 14:32:42 -04:00
bool contains_point(const Sphere& s, const Vector3& point);
2015-10-05 13:17:30 -04:00
2015-10-28 14:32:42 -04:00
f32 ray_intersection(const Vector3& from, const Vector3& dir, const Sphere& s);
} // namespace sphere
2015-10-03 10:26:29 -04:00
2015-10-28 14:32:42 -04:00
namespace plane
{
f32 ray_intersection(const Vector3& from, const Vector3& dir, const Plane& p);
2015-10-03 10:26:29 -04:00
2015-10-28 14:32:42 -04:00
bool intersection3(const Plane& p1, const Plane& p2, const Plane& p3, Vector3* ip);
} // namespace plane
2015-10-18 07:18:54 -04:00
2015-09-29 10:11:18 -04:00
2015-10-05 13:17:30 -04:00
namespace random
{
enum Generator_Type
{
MERSENNE_TWISTER_32,
MERSENNE_TWISTER_64,
2015-10-05 16:30:55 -04:00
RANDOM_DEVICE,
2015-10-05 13:17:30 -04:00
};
// NOTE(bill): Basic Definition of a Random Number Generator
2015-10-05 16:30:55 -04:00
// NOTE(bill): C++(17)?? Concepts might be useful here
2015-10-18 07:18:54 -04:00
// NOTE(bill): A vtable could be used but would not have good performance
// NOTE(bill): Just overload functions like mad?
2015-10-05 13:17:30 -04:00
/*
struct Generator
2015-10-05 16:30:55 -04:00
// concept Generator<typename T, typename U>
2015-10-05 13:17:30 -04:00
{
using Result_Type = T;
using Seed_Type = U;
Generator_Type type;
2015-10-05 16:30:55 -04:00
u32 entropy();
2015-10-05 13:17:30 -04:00
Result_Type next();
u32 next_u32();
s32 next_s32();
u64 next_u64();
s64 next_s64();
f32 next_f32();
f64 next_f64();
};
*/
2015-10-05 16:30:55 -04:00
template <typename T, typename U>
struct Generator_Base
2015-10-05 13:17:30 -04:00
{
2015-10-05 16:30:55 -04:00
using Result_Type = T;
using Seed_Type = U;
2015-10-05 13:17:30 -04:00
Seed_Type seed;
2015-10-05 16:30:55 -04:00
Generator_Type type;
};
2015-10-05 13:17:30 -04:00
2015-10-05 16:30:55 -04:00
struct Mt19937_32 : Generator_Base<s32, s32>
{
2015-10-05 13:17:30 -04:00
u32 index;
s32 mt[624];
2015-10-05 16:30:55 -04:00
u32 entropy();
2015-10-05 13:17:30 -04:00
Result_Type next();
u32 next_u32();
s32 next_s32();
u64 next_u64();
s64 next_s64();
f32 next_f32();
f64 next_f64();
};
2015-10-05 16:30:55 -04:00
struct Mt19937_64 : Generator_Base<s64, s64>
2015-10-05 13:17:30 -04:00
{
u32 index;
s64 mt[312];
2015-10-05 16:30:55 -04:00
u32 entropy();
Result_Type next();
u32 next_u32();
s32 next_s32();
u64 next_u64();
s64 next_s64();
f32 next_f32();
f64 next_f64();
};
struct Random_Device : Generator_Base<u32, u32>
{
u32 entropy();
2015-10-05 13:17:30 -04:00
Result_Type next();
u32 next_u32();
s32 next_s32();
u64 next_u64();
s64 next_s64();
f32 next_f32();
f64 next_f64();
};
2015-10-05 16:30:55 -04:00
// Makers for Generators
Mt19937_32 make_mt19937_32(Mt19937_32::Seed_Type seed);
Mt19937_64 make_mt19937_64(Mt19937_64::Seed_Type seed);
Random_Device make_random_device();
2015-10-05 13:17:30 -04:00
void set_seed(Mt19937_32* gen, Mt19937_32::Seed_Type seed);
void set_seed(Mt19937_64* gen, Mt19937_64::Seed_Type seed);
2015-10-05 13:17:30 -04:00
2015-10-28 14:32:42 -04:00
template <typename Generator> typename Generator::Result_Type next(Generator* gen);
2015-10-05 13:17:30 -04:00
template <typename Generator> s32 uniform_s32_distribution(Generator* gen, s32 min_inc, s32 max_inc);
template <typename Generator> s64 uniform_s64_distribution(Generator* gen, s64 min_inc, s64 max_inc);
template <typename Generator> u32 uniform_u32_distribution(Generator* gen, u32 min_inc, u32 max_inc);
template <typename Generator> u64 uniform_u64_distribution(Generator* gen, u64 min_inc, u64 max_inc);
template <typename Generator> f32 uniform_f32_distribution(Generator* gen, f32 min_inc, f32 max_inc);
template <typename Generator> f64 uniform_f64_distribution(Generator* gen, f64 min_inc, f64 max_inc);
2015-10-05 13:17:30 -04:00
template <typename Generator> ssize uniform_ssize_distribution(Generator* gen, ssize min_inc, ssize max_inc);
template <typename Generator> usize uniform_usize_distribution(Generator* gen, usize min_inc, usize max_inc);
2015-10-05 13:17:30 -04:00
2015-10-05 16:30:55 -04:00
inline Mt19937_32
make_mt19937_32(Mt19937_32::Seed_Type seed)
2015-10-05 13:17:30 -04:00
{
2015-10-05 16:30:55 -04:00
Mt19937_32 gen = {};
2015-10-05 13:17:30 -04:00
gen.type = MERSENNE_TWISTER_32;
set_seed(&gen, seed);
2015-10-05 13:17:30 -04:00
return gen;
}
2015-10-05 16:30:55 -04:00
inline Mt19937_64
make_mt19937_64(Mt19937_64::Seed_Type seed)
2015-10-05 13:17:30 -04:00
{
2015-10-05 16:30:55 -04:00
Mt19937_64 gen = {};
2015-10-05 13:17:30 -04:00
gen.type = MERSENNE_TWISTER_64;
set_seed(&gen, seed);
2015-10-05 13:17:30 -04:00
return gen;
}
2015-10-05 16:30:55 -04:00
inline Random_Device
make_random_device()
{
Random_Device gen = {};
gen.type = RANDOM_DEVICE;
return gen;
}
2015-10-05 13:17:30 -04:00
inline void
set_seed(Mt19937_32* gen, Mt19937_32::Seed_Type seed)
2015-10-05 13:17:30 -04:00
{
gen->seed = seed;
gen->mt[0] = seed;
2015-10-05 13:17:30 -04:00
for (u32 i = 1; i < 624; i++)
gen->mt[i] = 1812433253 * (gen->mt[i-1] ^ gen->mt[i-1] >> 30) + i;
2015-10-05 13:17:30 -04:00
}
inline void
set_seed(Mt19937_64* gen, Mt19937_64::Seed_Type seed)
2015-10-05 13:17:30 -04:00
{
gen->seed = seed;
gen->mt[0] = seed;
2015-10-05 13:17:30 -04:00
for (u32 i = 1; i < 312; i++)
gen->mt[i] = 6364136223846793005ull * (gen->mt[i-1] ^ gen->mt[i-1] >> 62) + i;
2015-10-05 13:17:30 -04:00
}
2015-10-05 16:30:55 -04:00
template <typename Generator>
inline typename Generator::Result_Type
next(Generator* gen)
2015-10-05 16:30:55 -04:00
{
return gen->next();
2015-10-05 16:30:55 -04:00
}
2015-10-05 13:17:30 -04:00
template <typename Generator>
inline s32
uniform_s32_distribution(Generator* gen, s32 min_inc, s32 max_inc)
2015-10-05 13:17:30 -04:00
{
return (gen->next_s32() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
}
template <typename Generator>
inline s64
uniform_s64_distribution(Generator* gen, s64 min_inc, s64 max_inc)
2015-10-05 13:17:30 -04:00
{
return (gen->next_s64() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
}
template <typename Generator>
inline u32
uniform_u32_distribution(Generator* gen, u32 min_inc, u32 max_inc)
2015-10-05 13:17:30 -04:00
{
return (gen->next_u64() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
}
template <typename Generator>
inline u64
uniform_u64_distribution(Generator* gen, u64 min_inc, u64 max_inc)
2015-10-05 13:17:30 -04:00
{
return (gen->next_u64() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
}
template <typename Generator>
inline f32
uniform_f32_distribution(Generator* gen, f32 min_inc, f32 max_inc)
2015-10-05 13:17:30 -04:00
{
f64 n = (gen->next_s64() >> 11) * (1.0/4503599627370495.0);
2015-10-05 16:30:55 -04:00
return static_cast<f32>(n * (max_inc - min_inc + 1.0) + min_inc);
2015-10-05 13:17:30 -04:00
}
template <typename Generator>
inline f64
uniform_f64_distribution(Generator* gen, f64 min_inc, f64 max_inc)
2015-10-05 13:17:30 -04:00
{
f64 n = (gen->next_s64() >> 11) * (1.0/4503599627370495.0);
2015-10-05 13:17:30 -04:00
return n * (max_inc - min_inc + 1.0) + min_inc;
}
template <typename Generator>
inline ssize
uniform_ssize_distribution(Generator* gen, ssize min_inc, ssize max_inc)
2015-10-05 13:17:30 -04:00
{
#if GB_ARCH_32_BIT
return (gen->next_s32() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
#elif GB_ARCH_64_BIT
return (gen->next_s64() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
#else
#error Bit size not supported
#endif
}
template <typename Generator>
inline usize
uniform_usize_distribution(Generator* gen, usize min_inc, usize max_inc)
2015-10-05 13:17:30 -04:00
{
#if GB_ARCH_32_BIT
return (gen->next_u32() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
#elif GB_ARCH_64_BIT
return (gen->next_u64() % (max_inc - min_inc + 1)) + min_inc;
2015-10-05 13:17:30 -04:00
#else
#error Bit size not supported
#endif
}
} // namespace random
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_END
2015-09-29 10:11:18 -04:00
2015-09-28 15:31:26 -04:00
#endif // GB_INCLUDE_GB_HPP
2015-09-27 15:43:22 -04:00
2015-09-28 15:31:26 -04:00
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
2015-10-05 13:17:30 -04:00
/// It's turtles all the way down!
2015-09-28 15:31:26 -04:00
///
///
///
///
///
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Implemenation ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-10-04 15:59:40 -04:00
#if defined(GB_IMPLEMENTATION)
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_START
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Memory ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-10-28 14:32:42 -04:00
namespace mutex
{
Mutex
make()
2015-09-27 14:03:47 -04:00
{
2015-10-28 14:32:42 -04:00
Mutex m = {};
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-28 14:32:42 -04:00
m.win32_mutex = CreateMutex(0, false, 0);
2015-09-27 14:03:47 -04:00
#else
2015-10-28 14:32:42 -04:00
pthread_mutex_init(&m.posix_mutex, nullptr);
2015-09-27 14:03:47 -04:00
#endif
2015-10-28 14:32:42 -04:00
return m;
2015-09-27 14:03:47 -04:00
}
2015-10-28 14:32:42 -04:00
void
destroy(Mutex* m)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-28 14:32:42 -04:00
CloseHandle(m->win32_mutex);
2015-09-27 14:03:47 -04:00
#else
2015-10-28 14:32:42 -04:00
pthread_mutex_destroy(&m->posix_mutex);
2015-09-27 14:03:47 -04:00
#endif
}
2015-10-28 14:32:42 -04:00
void lock(Mutex* m)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-28 14:32:42 -04:00
WaitForSingleObject(m->win32_mutex, INFINITE);
2015-09-27 14:03:47 -04:00
#else
2015-10-28 14:32:42 -04:00
pthread_mutex_lock(&m->posix_mutex);
2015-09-27 14:03:47 -04:00
#endif
}
2015-10-28 14:32:42 -04:00
bool try_lock(Mutex* m)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-28 14:32:42 -04:00
return WaitForSingleObject(m->win32_mutex, 0) == WAIT_OBJECT_0;
2015-09-27 14:03:47 -04:00
#else
2015-10-28 14:32:42 -04:00
return pthread_mutex_trylock(&m->posix_mutex) == 0;
2015-09-27 14:03:47 -04:00
#endif
}
2015-10-28 14:32:42 -04:00
void unlock(Mutex* m)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-28 14:32:42 -04:00
ReleaseMutex(m->win32_mutex);
2015-09-27 14:03:47 -04:00
#else
2015-10-28 14:32:42 -04:00
pthread_mutex_unlock(&m->posix_mutex);
2015-09-27 14:03:47 -04:00
#endif
}
2015-10-18 07:18:54 -04:00
} // namespace mutex
2015-09-27 14:03:47 -04:00
2015-10-03 10:26:29 -04:00
// Atomics
namespace atomic
{
#if defined(_MSC_VER)
inline u32
2015-10-28 14:32:42 -04:00
load(const Atomic32* object)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
return object->nonatomic;
2015-10-03 10:26:29 -04:00
}
inline void
2015-10-28 14:32:42 -04:00
store(Atomic32* object, u32 value)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
object->nonatomic = value;
2015-10-03 10:26:29 -04:00
}
inline u32
2015-10-28 14:32:42 -04:00
compare_exchange_strong(Atomic32* object, u32 expected, u32 desired)
2015-10-03 10:26:29 -04:00
{
2015-10-05 16:30:55 -04:00
return _InterlockedCompareExchange(reinterpret_cast<long*>(object), desired, expected);
2015-10-03 10:26:29 -04:00
}
inline u32
2015-10-28 14:32:42 -04:00
exchanged(Atomic32* object, u32 desired)
2015-10-03 10:26:29 -04:00
{
2015-10-05 16:30:55 -04:00
return _InterlockedExchange(reinterpret_cast<long*>(object), desired);
2015-10-03 10:26:29 -04:00
}
inline u32
2015-10-28 14:32:42 -04:00
fetch_add(Atomic32* object, s32 operand)
2015-10-03 10:26:29 -04:00
{
2015-10-05 16:30:55 -04:00
return _InterlockedExchangeAdd(reinterpret_cast<long*>(object), operand);
2015-10-03 10:26:29 -04:00
}
inline u32
2015-10-28 14:32:42 -04:00
fetch_and(Atomic32* object, u32 operand)
2015-10-03 10:26:29 -04:00
{
2015-10-05 16:30:55 -04:00
return _InterlockedAnd(reinterpret_cast<long*>(object), operand);
2015-10-03 10:26:29 -04:00
}
inline u32
2015-10-28 14:32:42 -04:00
fetch_or_32(Atomic32* object, u32 operand)
2015-10-03 10:26:29 -04:00
{
2015-10-05 16:30:55 -04:00
return _InterlockedOr(reinterpret_cast<long*>(object), operand);
2015-10-03 10:26:29 -04:00
}
inline u64
2015-10-28 14:32:42 -04:00
load(const Atomic64* object)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
return object->nonatomic;
2015-10-03 10:26:29 -04:00
#else
// NOTE(bill): The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b
u64 result;
__asm
{
mov esi, object;
mov ebx, eax;
mov ecx, edx;
2015-10-05 16:30:55 -04:00
lock cmpxchg8b [esi];
mov dword ptr result, eax;
mov dword ptr result[4], edx;
2015-10-03 10:26:29 -04:00
}
return result;
#endif
}
inline void
2015-10-28 14:32:42 -04:00
store(Atomic64* object, u64 value)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
object->nonatomic = value;
2015-10-03 10:26:29 -04:00
#else
// NOTE(bill): The most compatible way to get an atomic 64-bit load on x86 is with cmpxchg8b
__asm
{
mov esi, object;
mov ebx, dword ptr value;
mov ecx, dword ptr value[4];
retry:
cmpxchg8b [esi];
jne retry;
}
#endif
}
inline u64
2015-10-28 14:32:42 -04:00
compare_exchange_strong(Atomic64* object, u64 expected, u64 desired)
2015-10-03 10:26:29 -04:00
{
2015-10-05 16:30:55 -04:00
_InterlockedCompareExchange64(reinterpret_cast<s64*>(object), desired, expected);
2015-10-03 10:26:29 -04:00
}
inline u64
2015-10-28 14:32:42 -04:00
exchanged(Atomic64* object, u64 desired)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
2015-10-05 16:30:55 -04:00
return _InterlockedExchange64(reinterpret_cast<s64*>(object), desired);
2015-10-03 10:26:29 -04:00
#else
u64 expected = object->nonatomic;
while (true)
{
2015-10-05 16:30:55 -04:00
u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), desired, expected);
2015-10-03 10:26:29 -04:00
if (original == expected)
return original;
expected = original;
}
#endif
}
inline u64
2015-10-28 14:32:42 -04:00
fetch_add(Atomic64* object, s64 operand)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
2015-10-05 16:30:55 -04:00
return _InterlockedExchangeAdd64(reinterpret_cast<s64*>(object), operand);
2015-10-03 10:26:29 -04:00
#else
u64 expected = object->nonatomic;
while (true)
{
2015-10-05 16:30:55 -04:00
u64 original = _InterlockedExchange64(reinterpret_cast<s64*>(object), expected + operand, expected);
2015-10-03 10:26:29 -04:00
if (original == expected)
return original;
expected = original;
}
#endif
}
inline u64
2015-10-28 14:32:42 -04:00
fetch_and(Atomic64* object, u64 operand)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
2015-10-05 16:30:55 -04:00
return _InterlockedAnd64(reinterpret_cast<s64*>(object), operand);
2015-10-03 10:26:29 -04:00
#else
u64 expected = object->nonatomic;
while (true)
{
2015-10-05 16:30:55 -04:00
u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), expected & operand, expected);
2015-10-03 10:26:29 -04:00
if (original == expected)
return original;
expected = original;
}
#endif
}
inline u64
2015-10-28 14:32:42 -04:00
fetch_or(Atomic64* object, u64 operand)
2015-10-03 10:26:29 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
2015-10-05 16:30:55 -04:00
return _InterlockedAnd64(reinterpret_cast<s64*>(object), operand);
2015-10-03 10:26:29 -04:00
#else
u64 expected = object->nonatomic;
while (true)
{
2015-10-05 16:30:55 -04:00
u64 original = _InterlockedCompareExchange64(reinterpret_cast<s64*>(object), expected | operand, expected);
2015-10-03 10:26:29 -04:00
if (original == expected)
return original;
expected = original;
}
#endif
}
#else
#error TODO(bill): Implement atomics for this platform
#endif
} // namespace atomic
2015-10-28 14:32:42 -04:00
namespace semaphore
{
Semaphore
make()
{
Semaphore semaphore = {};
#if defined(GB_SYSTEM_WINDOWS)
semaphore.win32_handle = CreateSemaphore(nullptr, 0, GB_S32_MAX, nullptr);
GB_ASSERT(semaphore.win32_handle != nullptr, "CreateSemaphore: GetLastError = %d", GetLastError());
#else
semaphore.count = 0;
s32 result = pthread_cond_init(&semaphore.cond, nullptr);
GB_ASSERT(result == 0, "pthread_cond_init: errno = %d", result);
semaphore.mutex = mutex::make();
#endif
return semaphore;
}
void
destroy(Semaphore* semaphore)
{
#if defined(GB_SYSTEM_WINDOWS)
BOOL err = CloseHandle(semaphore->win32_handle);
GB_ASSERT(err != 0, "CloseHandle: GetLastError = %d", GetLastError());
#else
s32 result = pthread_cond_destroy(&semaphore->cond);
GB_ASSERT(result == 0, "pthread_cond_destroy: errno = %d", result);
mutex::destroy(&semaphore->mutex);
#endif
}
void
post(Semaphore* semaphore, u32 count)
{
#if defined(GB_SYSTEM_WINDOWS)
BOOL err = ReleaseSemaphore(semaphore->win32_handle, count, nullptr);
GB_ASSERT(err != 0, "ReleaseSemaphore: GetLastError = %d", GetLastError());
#else
mutex::lock(semaphore->mutex);
defer (mutex::unlock(semaphore->mutex));
for (u32 i = 0; i < count; i++)
{
s32 result = pthread_cond_signal(&semaphore->cond);
GB_ASSERT(result == 0, "pthread_cond_signal: errno = %d", result);
}
semaphore->count += count;
#endif
}
void
wait(Semaphore* semaphore)
{
#if defined(GB_SYSTEM_WINDOWS)
DWORD result = WaitForSingleObject(semaphore->win32_handle, INFINITE);
GB_ASSERT(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError = %d", GetLastError());
#else
mutex::lock(semaphore->mutex);
defer (mutex::unlock(semaphore->mutex));
while (count <= 0)
{
s32 result = pthread_cond_wait(&semaphore->cond, &semaphore->mutex.posix_mutex);
GB_ASSERT(result == 0, "pthread_cond_wait: errno = %d", result);
}
count--;
#endif
}
} // namespace semaphore
namespace thread
{
Thread
make()
{
Thread thread = {};
#if defined(GB_SYSTEM_WINDOWS)
thread.win32_handle = INVALID_HANDLE_VALUE;
#else
thread.posix_handle = 0;
#endif
thread.function = nullptr;
thread.data = nullptr;
thread.stack_size = 0;
thread.is_running = false;
thread.semaphore = semaphore::make();
return thread;
}
void
destroy(Thread* thread)
{
if (thread->is_running)
thread::stop(thread);
semaphore::destroy(&thread->semaphore);
}
internal s32
run(Thread* thread)
{
semaphore::post(&thread->semaphore);
return thread->function(thread->data);
}
#if defined(GB_SYSTEM_WINDOWS)
internal DWORD WINAPI
thread_proc(void* arg)
{
Thread* thread = static_cast<Thread*>(arg);
s32 result = thread::run(thread);
return result;
}
#else
internal void*
thread_proc(void* arg)
{
local_persist s32 result = -1;
result = thread::run(static_cast<Thread*>(arg));
return (void*)&result;
}
#endif
void
start(Thread* thread, Thread_Function* func, void* data, usize stack_size)
{
GB_ASSERT(!thread->is_running);
GB_ASSERT(func != nullptr);
thread->function = func;
thread->data = data;
thread->stack_size = stack_size;
#if defined(GB_SYSTEM_WINDOWS)
thread->win32_handle = CreateThread(nullptr, stack_size, thread_proc, thread, 0, nullptr);
GB_ASSERT(thread->win32_handle != nullptr,
"CreateThread: GetLastError = %d", GetLastError());
#else
pthread_attr_t attr;
s32 result = pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
GB_ASSERT(result == 0, "pthread_attr_init: errno = %d", result);
if (thread->stack_size != 0)
{
result = pthread_attr_setstacksize(&attr, thread->stack_size);
GB_ASSERT(result == 0, "pthread_attr_setstacksize: errno = %d", result);
}
result = pthread_create(&thread->posix_handle, &attr, thread_proc, thread);
GB_ASSERT(result == 0, "pthread_create: errno = %d", result);
// NOTE(bill): Free attr memory
result = pthread_attr_destroy(&attr);
GB_ASSERT(result == 0, "pthread_attr_destroy: errno = %d", result);
// NOTE(bill): So much boiler patch compared to windows.h (for once)
#endif
thread->is_running = true;
semaphore::wait(&thread->semaphore);
}
void
stop(Thread* thread)
{
if (!thread->is_running)
return;
#if defined(GB_SYSTEM_WINDOWS)
WaitForSingleObject(thread->win32_handle, INFINITE);
CloseHandle(thread->win32_handle);
thread->win32_handle = INVALID_HANDLE_VALUE;
#else
#endif
thread->is_running = false;
}
bool
is_running(const Thread& thread)
{
return thread.is_running != 0;
}
} // namespace thread
2015-10-18 07:18:54 -04:00
#define GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE (usize)(-1)
2015-09-27 14:03:47 -04:00
Heap_Allocator::~Heap_Allocator()
{
2015-10-18 07:18:54 -04:00
#if 0
2015-09-27 14:03:47 -04:00
GB_ASSERT(allocation_count == 0 && total_allocated() == 0,
2015-10-05 16:30:55 -04:00
"Heap Allocator: allocation count = %lld; total allocated = %lld",
allocation_count, total_allocated());
2015-10-18 07:18:54 -04:00
#endif
2015-09-27 14:03:47 -04:00
}
void*
Heap_Allocator::alloc(usize size, usize align)
{
2015-10-28 14:32:42 -04:00
mutex::lock(&mutex);
defer (mutex::unlock(&mutex));
2015-09-27 14:03:47 -04:00
const usize total = size + align + sizeof(Header);
2015-10-18 07:18:54 -04:00
Header* h = static_cast<Header*>(::malloc(total));
2015-09-27 14:03:47 -04:00
h->size = total;
2015-10-03 10:26:29 -04:00
void* data = memory::align_forward(h + 1, align);
2015-09-27 14:03:47 -04:00
{ // Pad header
2015-10-05 16:30:55 -04:00
usize* ptr = reinterpret_cast<usize*>(h+1);
2015-09-27 14:03:47 -04:00
while (ptr != data)
*ptr++ = GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE;
}
total_allocated_count += total;
allocation_count++;
return data;
}
void
2015-10-04 15:59:40 -04:00
Heap_Allocator::dealloc(const void* ptr)
2015-09-27 14:03:47 -04:00
{
if (!ptr)
return;
2015-10-28 14:32:42 -04:00
mutex::lock(&mutex);
defer (mutex::unlock(&mutex));
2015-09-27 14:03:47 -04:00
2015-09-27 15:43:22 -04:00
Header* h = get_header_ptr(ptr);
2015-09-27 14:03:47 -04:00
total_allocated_count -= h->size;
allocation_count--;
2015-10-18 07:18:54 -04:00
::free(h);
2015-09-27 14:03:47 -04:00
}
2015-09-27 15:43:22 -04:00
s64
2015-09-27 14:03:47 -04:00
Heap_Allocator::allocated_size(const void* ptr)
{
2015-10-28 14:32:42 -04:00
mutex::lock(&mutex);
defer (mutex::unlock(&mutex));
2015-09-27 14:03:47 -04:00
2015-09-27 15:43:22 -04:00
return get_header_ptr(ptr)->size;
2015-09-27 14:03:47 -04:00
}
2015-09-27 15:43:22 -04:00
s64
2015-09-27 14:03:47 -04:00
Heap_Allocator::total_allocated()
{
return total_allocated_count;
}
2015-09-27 15:43:22 -04:00
Heap_Allocator::Header*
Heap_Allocator::get_header_ptr(const void* ptr)
{
2015-10-18 07:18:54 -04:00
const usize* data = reinterpret_cast<const usize*>(ptr) - 1;
2015-09-27 15:43:22 -04:00
while (*data == GB_HEAP_ALLOCATOR_HEADER_PAD_VALUE)
data--;
2015-10-18 07:18:54 -04:00
return (Heap_Allocator::Header*)(data);
2015-09-27 15:43:22 -04:00
}
2015-09-27 14:03:47 -04:00
Arena_Allocator::Arena_Allocator(Allocator* backing_, usize size)
: backing(backing_)
2015-10-03 10:26:29 -04:00
, physical_start(nullptr)
2015-10-18 07:18:54 -04:00
, total_size(size)
2015-09-29 10:11:18 -04:00
, temp_count(0)
, total_allocated_count(0)
{
2015-10-03 10:26:29 -04:00
physical_start = backing->alloc(size);
2015-09-29 10:11:18 -04:00
}
2015-10-03 10:26:29 -04:00
Arena_Allocator::Arena_Allocator(void* start, usize size)
: backing(nullptr)
, physical_start(start)
2015-10-18 07:18:54 -04:00
, total_size(size)
2015-10-03 10:26:29 -04:00
, temp_count(0)
, total_allocated_count(0)
2015-09-27 14:03:47 -04:00
{
2015-10-03 10:26:29 -04:00
}
2015-09-27 14:03:47 -04:00
2015-10-03 10:26:29 -04:00
Arena_Allocator::~Arena_Allocator()
{
if (backing)
backing->dealloc(physical_start);
2015-10-04 15:59:40 -04:00
GB_ASSERT(total_allocated_count == 0,
2015-10-05 16:30:55 -04:00
"Memory leak of %ld bytes, maybe you forgot to call clear_arena()?", total_allocated_count);
2015-10-03 10:26:29 -04:00
}
void* Arena_Allocator::alloc(usize size, usize align)
{
s64 actual_size = size + align;
2015-10-04 15:59:40 -04:00
if (total_allocated_count + actual_size > total_size)
2015-10-03 10:26:29 -04:00
return nullptr;
2015-09-27 14:03:47 -04:00
2015-10-18 07:18:54 -04:00
void* ptr = memory::align_forward(memory::pointer_add(physical_start, total_allocated_count), align);
2015-09-27 14:03:47 -04:00
2015-10-04 15:59:40 -04:00
total_allocated_count += actual_size;
2015-09-27 14:03:47 -04:00
return ptr;
}
2015-10-04 15:59:40 -04:00
inline void Arena_Allocator::dealloc(const void*) {}
2015-09-29 10:11:18 -04:00
2015-10-04 15:59:40 -04:00
inline s64 Arena_Allocator::allocated_size(const void*) { return -1; }
2015-09-27 14:03:47 -04:00
2015-10-04 15:59:40 -04:00
inline s64 Arena_Allocator::total_allocated() { return total_allocated_count; }
2015-09-27 14:03:47 -04:00
2015-09-28 16:58:33 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 16:58:33 -04:00
/// String ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 16:58:33 -04:00
////////////////////////////////
2015-10-18 07:18:54 -04:00
namespace string
{
String make(Allocator* a, const char* str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
return string::make(a, str, (string::Size)strlen(str));
2015-09-28 16:58:33 -04:00
}
String make(Allocator* a, const void* init_str, Size len)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
usize header_size = sizeof(string::Header);
2015-09-28 16:58:33 -04:00
void* ptr = alloc(a, header_size + len + 1);
if (!init_str)
2015-10-18 07:18:54 -04:00
memory::zero(ptr, header_size + len + 1);
2015-09-28 16:58:33 -04:00
if (ptr == nullptr)
return nullptr;
2015-10-05 16:30:55 -04:00
String str = static_cast<char*>(ptr) + header_size;
2015-10-18 07:18:54 -04:00
string::Header* header = string::header(str);
header->allocator = a;
2015-09-28 16:58:33 -04:00
header->len = len;
header->cap = len;
if (len && init_str)
2015-10-18 07:18:54 -04:00
memory::copy(str, init_str, len);
2015-09-28 16:58:33 -04:00
str[len] = '\0';
return str;
}
2015-10-28 14:32:42 -04:00
void free(String str)
2015-09-28 16:58:33 -04:00
{
if (str == nullptr)
return;
2015-10-18 07:18:54 -04:00
string::Header* h = string::header(str);
2015-09-28 16:58:33 -04:00
Allocator* a = h->allocator;
2015-10-28 14:32:42 -04:00
if (a)
dealloc(a, h);
2015-09-28 16:58:33 -04:00
}
2015-10-28 14:32:42 -04:00
String duplicate(Allocator* a, const String str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
return string::make(a, str, string::length(str));
2015-09-28 16:58:33 -04:00
}
2015-10-18 07:18:54 -04:00
Size length(const String str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
return string::header(str)->len;
2015-09-28 16:58:33 -04:00
}
2015-10-18 07:18:54 -04:00
Size capacity(const String str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
return string::header(str)->cap;
2015-09-28 16:58:33 -04:00
}
2015-10-18 07:18:54 -04:00
Size available_space(const String str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
string::Header* h = string::header(str);
2015-09-28 16:58:33 -04:00
if (h->cap > h->len)
return h->cap - h->len;
return 0;
}
2015-10-18 07:18:54 -04:00
void clear(String str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
string::header(str)->len = 0;
2015-09-28 16:58:33 -04:00
str[0] = '\0';
}
void append(String* str, const String other)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
string::append(str, other, string::length(other));
2015-09-28 16:58:33 -04:00
}
void append_cstring(String* str, const char* other)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
string::append(str, other, (Size)strlen(other));
2015-09-28 16:58:33 -04:00
}
void append(String* str, const void* other, Size other_len)
2015-09-28 16:58:33 -04:00
{
Size curr_len = string::length(*str);
2015-09-28 16:58:33 -04:00
2015-10-18 07:18:54 -04:00
string::make_space_for(str, other_len);
2015-09-28 16:58:33 -04:00
if (str == nullptr)
return;
2015-10-18 07:18:54 -04:00
memory::copy(str + curr_len, other, other_len);
2015-09-28 16:58:33 -04:00
str[curr_len + other_len] = '\0';
string::header(*str)->len = curr_len + other_len;
2015-09-28 16:58:33 -04:00
}
namespace impl
{
// NOTE(bill): ptr _must_ be allocated with Allocator* a
internal inline void*
string_realloc(Allocator* a, void* ptr, usize old_size, usize new_size)
2015-09-28 16:58:33 -04:00
{
if (!ptr)
return alloc(a, new_size);
if (new_size < old_size)
new_size = old_size;
if (old_size == new_size)
return ptr;
void* new_ptr = alloc(a, new_size);
if (!new_ptr)
return nullptr;
2015-10-18 07:18:54 -04:00
memory::copy(new_ptr, ptr, old_size);
2015-09-28 16:58:33 -04:00
dealloc(a, ptr);
return new_ptr;
}
} // namespace impl
2015-10-28 14:32:42 -04:00
void
make_space_for(String* str, Size add_len)
2015-09-28 16:58:33 -04:00
{
Size len = string::length(*str);
2015-10-18 07:18:54 -04:00
Size new_len = len + add_len;
2015-09-28 16:58:33 -04:00
Size available = string::available_space(*str);
2015-09-28 16:58:33 -04:00
if (available >= add_len) // Return if there is enough space left
return;
2015-10-18 07:18:54 -04:00
void* ptr = reinterpret_cast<string::Header*>(str) - 1;
usize old_size = sizeof(string::Header) + string::length(*str) + 1;
2015-10-18 07:18:54 -04:00
usize new_size = sizeof(string::Header) + new_len + 1;
2015-09-28 16:58:33 -04:00
Allocator* a = string::header(*str)->allocator;
void* new_ptr = impl::string_realloc(a, ptr, old_size, new_size);
2015-09-28 16:58:33 -04:00
if (new_ptr == nullptr)
return;
*str = static_cast<char*>(new_ptr) + sizeof(string::Header);
2015-09-28 16:58:33 -04:00
string::header(*str)->cap = new_len;
2015-09-28 16:58:33 -04:00
}
2015-10-28 14:32:42 -04:00
usize
allocation_size(const String str)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
Size cap = string::capacity(str);
return sizeof(string::Header) + cap;
2015-09-28 16:58:33 -04:00
}
2015-10-28 14:32:42 -04:00
bool
equals(const String lhs, const String rhs)
2015-09-28 16:58:33 -04:00
{
2015-10-18 07:18:54 -04:00
Size lhs_len = string::length(lhs);
Size rhs_len = string::length(rhs);
2015-09-28 16:58:33 -04:00
if (lhs_len != rhs_len)
return false;
2015-10-18 07:18:54 -04:00
for (Size i = 0; i < lhs_len; i++)
2015-09-28 16:58:33 -04:00
{
if (lhs[i] != rhs[i])
return false;
}
return true;
}
2015-10-28 14:32:42 -04:00
int
compare(const String lhs, const String rhs) // NOTE(bill): three-way comparison
{
// Treat as cstring
const char* str1 = lhs;
const char* str2 = rhs;
int s1;
int s2;
do
{
s1 = *str1++;
s2 = *str2++;
if (s1 == 0)
break;
}
while (s1 == s2);
return (s1 < s2) ? -1 : (s1 > s2);
}
void
trim(String* str, const char* cut_set)
2015-09-28 16:58:33 -04:00
{
char* start;
char* end;
char* start_pos;
char* end_pos;
2015-10-28 14:32:42 -04:00
start_pos = start = *str;
end_pos = end = *str + string::length(*str) - 1;
2015-09-28 16:58:33 -04:00
while (start_pos <= end && strchr(cut_set, *start_pos))
start_pos++;
while (end_pos > start_pos && strchr(cut_set, *end_pos))
end_pos--;
2015-10-18 07:18:54 -04:00
Size len = static_cast<Size>((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
2015-09-28 16:58:33 -04:00
2015-10-28 14:32:42 -04:00
if (*str != start_pos)
memory::move(*str, start_pos, len);
(*str)[len] = '\0';
2015-09-28 16:58:33 -04:00
2015-10-28 14:32:42 -04:00
string::header(*str)->len = len;
2015-09-28 16:58:33 -04:00
}
2015-10-18 07:18:54 -04:00
} // namespace string
2015-09-28 16:58:33 -04:00
2015-10-28 14:32:42 -04:00
namespace strconv
2015-09-28 16:58:33 -04:00
{
2015-10-28 14:32:42 -04:00
// NOTE(bill): Inspired by the golang strconv library but not exactly due to numerous reasons
bool
parse_bool(const char* str, bool* value)
2015-09-28 16:58:33 -04:00
{
2015-10-28 14:32:42 -04:00
if (str == nullptr)
return false;
2015-09-28 16:58:33 -04:00
2015-10-28 14:32:42 -04:00
if (str[0] == '\0')
return false;
2015-09-28 16:58:33 -04:00
2015-10-28 14:32:42 -04:00
if (str[0] == '1' ||
str[0] == 't' ||
str[0] == 'T')
2015-09-28 16:58:33 -04:00
{
2015-10-28 14:32:42 -04:00
*value = true;
return true;
}
if (str[0] == '0' ||
str[0] == 'f' ||
str[0] == 'F')
{
*value = false;
return true;
}
if ((str[0] == 't' &&
str[1] == 'r' &&
str[2] == 'u' &&
str[3] == 'e') ||
(str[0] == 'T' &&
str[1] == 'R' &&
str[2] == 'U' &&
str[3] == 'E'))
{
*value = true;
return true;
2015-09-28 16:58:33 -04:00
}
2015-10-28 14:32:42 -04:00
if ((str[0] == 'f' &&
str[1] == 'a' &&
str[2] == 'l' &&
str[3] == 's' &&
str[4] == 'e') ||
(str[0] == 'F' &&
str[1] == 'A' &&
str[2] == 'L' &&
str[3] == 'S' &&
str[4] == 'E'))
{
*value = false;
return true;
}
return false;
2015-09-28 16:58:33 -04:00
}
2015-10-28 14:32:42 -04:00
bool
parse_f32(const char* str, f32* value)
{
// TODO(bill):
return false;
}
bool
parse_f64(const char* str, f64* value)
{
// TODO(bill):
return false;
}
bool
parse_int(const char* str, int base, s8* value)
{
// TODO(bill):
return false;
}
bool
parse_int(const char* str, int base, s16* value)
{
// TODO(bill):
return false;
}
bool
parse_int(const char* str, int base, s32* value)
{
// TODO(bill):
return false;
}
bool
parse_int(const char* str, int base, s64* value)
{
// TODO(bill):
return false;
}
bool
parse_uint(const char* str, int base, u8* value)
{
// TODO(bill):
return false;
}
bool
parse_uint(const char* str, int base, u16* value)
{
// TODO(bill):
return false;
}
bool
parse_uint(const char* str, int base, u32* value)
{
// TODO(bill):
return false;
}
bool
parse_uint(const char* str, int base, u64* value)
{
// TODO(bill):
return false;
}
void
format_bool(bool value, char* buffer, usize len)
{
// TODO(bill):
}
void
format_f32(f32 value, char* buffer, usize len)
{
// TODO(bill):
}
void
format_f64(f64 value, char* buffer, usize len)
{
// TODO(bill):
}
void
format_int(s64 value, char* buffer, usize len)
{
// TODO(bill):
}
void
format_uint(u64 value, char* buffer, usize len)
{
// TODO(bill):
}
} // namespace strconv
////////////////////////////////
/// ///
/// Hash ///
/// ///
////////////////////////////////
namespace hash
{
u32
adler32(const void* key, u32 num_bytes)
{
const u32 MOD_ADLER = 65521;
u32 a = 1;
u32 b = 0;
const u8* bytes = static_cast<const u8*>(key);
for (u32 i = 0; i < num_bytes; i++)
{
a = (a + bytes[i]) % MOD_ADLER;
b = (b + a) % MOD_ADLER;
}
return (b << 16) | a;
}
global const u32 GB_CRC32_TABLE[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
2015-09-28 16:58:33 -04:00
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
global const u64 GB_CRC64_TABLE[256] = {
2015-09-28 16:58:33 -04:00
0x0000000000000000ull, 0x42F0E1EBA9EA3693ull, 0x85E1C3D753D46D26ull, 0xC711223CFA3E5BB5ull,
0x493366450E42ECDFull, 0x0BC387AEA7A8DA4Cull, 0xCCD2A5925D9681F9ull, 0x8E224479F47CB76Aull,
0x9266CC8A1C85D9BEull, 0xD0962D61B56FEF2Dull, 0x17870F5D4F51B498ull, 0x5577EEB6E6BB820Bull,
0xDB55AACF12C73561ull, 0x99A54B24BB2D03F2ull, 0x5EB4691841135847ull, 0x1C4488F3E8F96ED4ull,
0x663D78FF90E185EFull, 0x24CD9914390BB37Cull, 0xE3DCBB28C335E8C9ull, 0xA12C5AC36ADFDE5Aull,
0x2F0E1EBA9EA36930ull, 0x6DFEFF5137495FA3ull, 0xAAEFDD6DCD770416ull, 0xE81F3C86649D3285ull,
0xF45BB4758C645C51ull, 0xB6AB559E258E6AC2ull, 0x71BA77A2DFB03177ull, 0x334A9649765A07E4ull,
0xBD68D2308226B08Eull, 0xFF9833DB2BCC861Dull, 0x388911E7D1F2DDA8ull, 0x7A79F00C7818EB3Bull,
0xCC7AF1FF21C30BDEull, 0x8E8A101488293D4Dull, 0x499B3228721766F8ull, 0x0B6BD3C3DBFD506Bull,
0x854997BA2F81E701ull, 0xC7B97651866BD192ull, 0x00A8546D7C558A27ull, 0x4258B586D5BFBCB4ull,
0x5E1C3D753D46D260ull, 0x1CECDC9E94ACE4F3ull, 0xDBFDFEA26E92BF46ull, 0x990D1F49C77889D5ull,
0x172F5B3033043EBFull, 0x55DFBADB9AEE082Cull, 0x92CE98E760D05399ull, 0xD03E790CC93A650Aull,
0xAA478900B1228E31ull, 0xE8B768EB18C8B8A2ull, 0x2FA64AD7E2F6E317ull, 0x6D56AB3C4B1CD584ull,
0xE374EF45BF6062EEull, 0xA1840EAE168A547Dull, 0x66952C92ECB40FC8ull, 0x2465CD79455E395Bull,
0x3821458AADA7578Full, 0x7AD1A461044D611Cull, 0xBDC0865DFE733AA9ull, 0xFF3067B657990C3Aull,
0x711223CFA3E5BB50ull, 0x33E2C2240A0F8DC3ull, 0xF4F3E018F031D676ull, 0xB60301F359DBE0E5ull,
0xDA050215EA6C212Full, 0x98F5E3FE438617BCull, 0x5FE4C1C2B9B84C09ull, 0x1D14202910527A9Aull,
0x93366450E42ECDF0ull, 0xD1C685BB4DC4FB63ull, 0x16D7A787B7FAA0D6ull, 0x5427466C1E109645ull,
0x4863CE9FF6E9F891ull, 0x0A932F745F03CE02ull, 0xCD820D48A53D95B7ull, 0x8F72ECA30CD7A324ull,
0x0150A8DAF8AB144Eull, 0x43A04931514122DDull, 0x84B16B0DAB7F7968ull, 0xC6418AE602954FFBull,
0xBC387AEA7A8DA4C0ull, 0xFEC89B01D3679253ull, 0x39D9B93D2959C9E6ull, 0x7B2958D680B3FF75ull,
0xF50B1CAF74CF481Full, 0xB7FBFD44DD257E8Cull, 0x70EADF78271B2539ull, 0x321A3E938EF113AAull,
0x2E5EB66066087D7Eull, 0x6CAE578BCFE24BEDull, 0xABBF75B735DC1058ull, 0xE94F945C9C3626CBull,
0x676DD025684A91A1ull, 0x259D31CEC1A0A732ull, 0xE28C13F23B9EFC87ull, 0xA07CF2199274CA14ull,
0x167FF3EACBAF2AF1ull, 0x548F120162451C62ull, 0x939E303D987B47D7ull, 0xD16ED1D631917144ull,
0x5F4C95AFC5EDC62Eull, 0x1DBC74446C07F0BDull, 0xDAAD56789639AB08ull, 0x985DB7933FD39D9Bull,
0x84193F60D72AF34Full, 0xC6E9DE8B7EC0C5DCull, 0x01F8FCB784FE9E69ull, 0x43081D5C2D14A8FAull,
0xCD2A5925D9681F90ull, 0x8FDAB8CE70822903ull, 0x48CB9AF28ABC72B6ull, 0x0A3B7B1923564425ull,
0x70428B155B4EAF1Eull, 0x32B26AFEF2A4998Dull, 0xF5A348C2089AC238ull, 0xB753A929A170F4ABull,
0x3971ED50550C43C1ull, 0x7B810CBBFCE67552ull, 0xBC902E8706D82EE7ull, 0xFE60CF6CAF321874ull,
0xE224479F47CB76A0ull, 0xA0D4A674EE214033ull, 0x67C58448141F1B86ull, 0x253565A3BDF52D15ull,
0xAB1721DA49899A7Full, 0xE9E7C031E063ACECull, 0x2EF6E20D1A5DF759ull, 0x6C0603E6B3B7C1CAull,
0xF6FAE5C07D3274CDull, 0xB40A042BD4D8425Eull, 0x731B26172EE619EBull, 0x31EBC7FC870C2F78ull,
0xBFC9838573709812ull, 0xFD39626EDA9AAE81ull, 0x3A28405220A4F534ull, 0x78D8A1B9894EC3A7ull,
0x649C294A61B7AD73ull, 0x266CC8A1C85D9BE0ull, 0xE17DEA9D3263C055ull, 0xA38D0B769B89F6C6ull,
0x2DAF4F0F6FF541ACull, 0x6F5FAEE4C61F773Full, 0xA84E8CD83C212C8Aull, 0xEABE6D3395CB1A19ull,
0x90C79D3FEDD3F122ull, 0xD2377CD44439C7B1ull, 0x15265EE8BE079C04ull, 0x57D6BF0317EDAA97ull,
0xD9F4FB7AE3911DFDull, 0x9B041A914A7B2B6Eull, 0x5C1538ADB04570DBull, 0x1EE5D94619AF4648ull,
0x02A151B5F156289Cull, 0x4051B05E58BC1E0Full, 0x87409262A28245BAull, 0xC5B073890B687329ull,
0x4B9237F0FF14C443ull, 0x0962D61B56FEF2D0ull, 0xCE73F427ACC0A965ull, 0x8C8315CC052A9FF6ull,
0x3A80143F5CF17F13ull, 0x7870F5D4F51B4980ull, 0xBF61D7E80F251235ull, 0xFD913603A6CF24A6ull,
0x73B3727A52B393CCull, 0x31439391FB59A55Full, 0xF652B1AD0167FEEAull, 0xB4A25046A88DC879ull,
0xA8E6D8B54074A6ADull, 0xEA16395EE99E903Eull, 0x2D071B6213A0CB8Bull, 0x6FF7FA89BA4AFD18ull,
0xE1D5BEF04E364A72ull, 0xA3255F1BE7DC7CE1ull, 0x64347D271DE22754ull, 0x26C49CCCB40811C7ull,
0x5CBD6CC0CC10FAFCull, 0x1E4D8D2B65FACC6Full, 0xD95CAF179FC497DAull, 0x9BAC4EFC362EA149ull,
0x158E0A85C2521623ull, 0x577EEB6E6BB820B0ull, 0x906FC95291867B05ull, 0xD29F28B9386C4D96ull,
0xCEDBA04AD0952342ull, 0x8C2B41A1797F15D1ull, 0x4B3A639D83414E64ull, 0x09CA82762AAB78F7ull,
0x87E8C60FDED7CF9Dull, 0xC51827E4773DF90Eull, 0x020905D88D03A2BBull, 0x40F9E43324E99428ull,
0x2CFFE7D5975E55E2ull, 0x6E0F063E3EB46371ull, 0xA91E2402C48A38C4ull, 0xEBEEC5E96D600E57ull,
0x65CC8190991CB93Dull, 0x273C607B30F68FAEull, 0xE02D4247CAC8D41Bull, 0xA2DDA3AC6322E288ull,
0xBE992B5F8BDB8C5Cull, 0xFC69CAB42231BACFull, 0x3B78E888D80FE17Aull, 0x7988096371E5D7E9ull,
0xF7AA4D1A85996083ull, 0xB55AACF12C735610ull, 0x724B8ECDD64D0DA5ull, 0x30BB6F267FA73B36ull,
0x4AC29F2A07BFD00Dull, 0x08327EC1AE55E69Eull, 0xCF235CFD546BBD2Bull, 0x8DD3BD16FD818BB8ull,
0x03F1F96F09FD3CD2ull, 0x41011884A0170A41ull, 0x86103AB85A2951F4ull, 0xC4E0DB53F3C36767ull,
0xD8A453A01B3A09B3ull, 0x9A54B24BB2D03F20ull, 0x5D45907748EE6495ull, 0x1FB5719CE1045206ull,
0x919735E51578E56Cull, 0xD367D40EBC92D3FFull, 0x1476F63246AC884Aull, 0x568617D9EF46BED9ull,
0xE085162AB69D5E3Cull, 0xA275F7C11F7768AFull, 0x6564D5FDE549331Aull, 0x279434164CA30589ull,
0xA9B6706FB8DFB2E3ull, 0xEB46918411358470ull, 0x2C57B3B8EB0BDFC5ull, 0x6EA7525342E1E956ull,
0x72E3DAA0AA188782ull, 0x30133B4B03F2B111ull, 0xF7021977F9CCEAA4ull, 0xB5F2F89C5026DC37ull,
0x3BD0BCE5A45A6B5Dull, 0x79205D0E0DB05DCEull, 0xBE317F32F78E067Bull, 0xFCC19ED95E6430E8ull,
0x86B86ED5267CDBD3ull, 0xC4488F3E8F96ED40ull, 0x0359AD0275A8B6F5ull, 0x41A94CE9DC428066ull,
0xCF8B0890283E370Cull, 0x8D7BE97B81D4019Full, 0x4A6ACB477BEA5A2Aull, 0x089A2AACD2006CB9ull,
0x14DEA25F3AF9026Dull, 0x562E43B4931334FEull, 0x913F6188692D6F4Bull, 0xD3CF8063C0C759D8ull,
0x5DEDC41A34BBEEB2ull, 0x1F1D25F19D51D821ull, 0xD80C07CD676F8394ull, 0x9AFCE626CE85B507ull,
};
2015-10-28 14:32:42 -04:00
u32
crc32(const void* key, u32 num_bytes)
2015-09-28 16:58:33 -04:00
{
2015-10-05 16:30:55 -04:00
u32 result = static_cast<u32>(~0);
const u8* c = reinterpret_cast<const u8*>(key);
2015-09-28 18:57:43 -04:00
for (u32 remaining = num_bytes; remaining--; c++)
2015-09-28 16:58:33 -04:00
result = (result >> 8) ^ (GB_CRC32_TABLE[(result ^ *c) & 0xff]);
return ~result;
}
2015-10-28 14:32:42 -04:00
u64
crc64(const void* key, usize num_bytes)
2015-09-28 16:58:33 -04:00
{
2015-10-28 14:32:42 -04:00
u64 result = static_cast<u64>(~0);
2015-10-05 16:30:55 -04:00
const u8* c = reinterpret_cast<const u8*>(key);
2015-09-28 16:58:33 -04:00
for (usize remaining = num_bytes; remaining--; c++)
result = (result >> 8) ^ (GB_CRC64_TABLE[(result ^ *c) & 0xff]);
return ~result;
}
// 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)
// {
// }
2015-10-28 14:32:42 -04:00
u32
murmur32(const void* key, u32 num_bytes, u32 seed)
2015-09-28 16:58:33 -04:00
{
local_persist const u32 c1 = 0xcc9e2d51;
local_persist const u32 c2 = 0x1b873593;
local_persist const u32 r1 = 15;
local_persist const u32 r2 = 13;
local_persist const u32 m = 5;
local_persist const u32 n = 0xe6546b64;
2015-09-28 16:58:33 -04:00
u32 hash = seed;
const usize nblocks = num_bytes / 4;
2015-10-05 16:30:55 -04:00
const u32* blocks = static_cast<const u32*>(key);
2015-09-28 16:58:33 -04:00
for (usize i = 0; i < nblocks; i++) {
u32 k = blocks[i];
k *= c1;
k = (k << r1) | (k >> (32 - r1));
k *= c2;
hash ^= k;
hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
}
2015-10-05 16:30:55 -04:00
const u8* tail = (static_cast<const u8*>(key)) + nblocks * 4;
2015-09-28 16:58:33 -04:00
u32 k1 = 0;
switch (num_bytes & 3) {
case 3:
k1 ^= tail[2] << 16;
case 2:
k1 ^= tail[1] << 8;
case 1:
k1 ^= tail[0];
k1 *= c1;
k1 = (k1 << r1) | (k1 >> (32 - r1));
k1 *= c2;
hash ^= k1;
}
hash ^= num_bytes;
hash ^= (hash >> 16);
hash *= 0x85ebca6b;
hash ^= (hash >> 13);
hash *= 0xc2b2ae35;
hash ^= (hash >> 16);
return hash;
}
2015-10-04 15:59:40 -04:00
#if defined(GB_ARCH_64_BIT)
2015-10-28 14:32:42 -04:00
u64
murmur64(const void* key, usize num_bytes, u64 seed)
2015-09-28 16:58:33 -04:00
{
local_persist const u64 m = 0xc6a4a7935bd1e995ULL;
local_persist const s32 r = 47;
2015-09-28 16:58:33 -04:00
u64 h = seed ^ (num_bytes * m);
2015-10-05 16:30:55 -04:00
const u64* data = static_cast<const u64*>(key);
2015-09-28 16:58:33 -04:00
const u64* end = data + (num_bytes / 8);
while (data != end)
{
u64 k = *data++;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
2015-10-05 16:30:55 -04:00
const u8* data2 = reinterpret_cast<const u8*>(data);
2015-09-28 16:58:33 -04:00
switch (num_bytes & 7)
{
2015-10-28 14:32:42 -04:00
case 7: h ^= static_cast<u64>(data2[6]) << 48;
case 6: h ^= static_cast<u64>(data2[5]) << 40;
case 5: h ^= static_cast<u64>(data2[4]) << 32;
case 4: h ^= static_cast<u64>(data2[3]) << 24;
case 3: h ^= static_cast<u64>(data2[2]) << 16;
case 2: h ^= static_cast<u64>(data2[1]) << 8;
case 1: h ^= static_cast<u64>(data2[0]);
2015-09-28 16:58:33 -04:00
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
#elif GB_ARCH_32_BIT
2015-10-28 14:32:42 -04:00
u64
murmur64(const void* key, usize num_bytes, u64 seed)
2015-09-28 16:58:33 -04:00
{
local_persist const u32 m = 0x5bd1e995;
local_persist const s32 r = 24;
2015-09-28 16:58:33 -04:00
2015-10-05 16:30:55 -04:00
u32 h1 = static_cast<u32>(seed) ^ static_cast<u32>(num_bytes);
u32 h2 = static_cast<u32>(seed >> 32);
2015-09-28 16:58:33 -04:00
2015-10-05 16:30:55 -04:00
const u32* data = static_cast<const u32*>(key);
2015-09-28 16:58:33 -04:00
while (num_bytes >= 8)
{
u32 k1 = *data++;
k1 *= m;
k1 ^= k1 >> r;
k1 *= m;
h1 *= m;
h1 ^= k1;
num_bytes -= 4;
u32 k2 = *data++;
k2 *= m;
k2 ^= k2 >> r;
k2 *= m;
h2 *= m;
h2 ^= k2;
num_bytes -= 4;
}
if (num_bytes >= 4)
{
u32 k1 = *data++;
k1 *= m;
k1 ^= k1 >> r;
k1 *= m;
h1 *= m;
h1 ^= k1;
num_bytes -= 4;
}
switch (num_bytes)
{
2015-10-05 16:30:55 -04:00
case 3: h2 ^= reinterpret_cast<const u8*>(data)[2] << 16;
case 2: h2 ^= reinterpret_cast<const u8*>(data)[1] << 8;
case 1: h2 ^= reinterpret_cast<const u8*>(data)[0] << 0;
2015-09-28 16:58:33 -04:00
h2 *= m;
};
h1 ^= h2 >> 18;
h1 *= m;
h2 ^= h1 >> 22;
h2 *= m;
h1 ^= h2 >> 17;
h1 *= m;
h2 ^= h1 >> 19;
h2 *= m;
u64 h = h1;
h = (h << 32) | h2;
return h;
}
#else
#error murmur64 function not supported on this architecture
#endif
} // namespace hash
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Time ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-10-18 07:18:54 -04:00
2015-10-28 14:32:42 -04:00
const Time TIME_ZERO = time::seconds(0);
2015-10-18 07:18:54 -04:00
2015-10-28 14:32:42 -04:00
namespace time
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-09-28 15:31:26 -04:00
internal LARGE_INTEGER
2015-09-28 15:31:26 -04:00
win32_get_frequency()
{
LARGE_INTEGER f;
QueryPerformanceFrequency(&f);
return f;
}
2015-10-28 14:32:42 -04:00
Time
now()
2015-09-28 15:31:26 -04:00
{
// NOTE(bill): std::chrono does not have a good enough precision in MSVC12
// and below. This may have been fixed in MSVC14 but unsure as of yet.
// Force the following code to run on first core
// NOTE(bill): See
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
HANDLE currentThread = GetCurrentThread();
DWORD_PTR previousMask = SetThreadAffinityMask(currentThread, 1);
// Get the frequency of the performance counter
// It is constant across the program's lifetime
internal LARGE_INTEGER s_frequency = win32_get_frequency();
2015-09-28 15:31:26 -04:00
// Get the current time
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
// Restore the thread affinity
SetThreadAffinityMask(currentThread, previousMask);
2015-10-28 14:32:42 -04:00
return time::microseconds(1000000ll * t.QuadPart / s_frequency.QuadPart);
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
void
sleep(Time t)
2015-09-28 15:31:26 -04:00
{
if (t.microseconds <= 0)
return;
// Get the supported timer resolutions on this system
TIMECAPS tc;
timeGetDevCaps(&tc, sizeof(TIMECAPS));
// Set the timer resolution to the minimum for the Sleep call
timeBeginPeriod(tc.wPeriodMin);
// Wait...
2015-10-28 14:32:42 -04:00
::Sleep(time::as_milliseconds(t));
2015-09-28 15:31:26 -04:00
// Reset the timer resolution back to the system default
timeBeginPeriod(tc.wPeriodMin);
}
#else
2015-10-28 14:32:42 -04:00
Time
now()
2015-09-28 15:31:26 -04:00
{
2015-10-04 15:59:40 -04:00
#if defined(GB_SYSTEM_OSX)
2015-10-05 16:30:55 -04:00
s64 t = static_cast<s64>(mach_absolute_time());
2015-10-03 10:26:29 -04:00
return microseconds(t);
#else
2015-10-02 08:11:18 -04:00
struct timeval t;
gettimeofday(&t, nullptr);
2015-09-28 15:31:26 -04:00
2015-10-02 08:11:18 -04:00
return microseconds((t.tv_sec * 1000000ll) + (t.tv_usec * 1ll));
2015-10-03 10:26:29 -04:00
#endif
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
void
sleep(Time t)
2015-09-28 15:31:26 -04:00
{
if (t.microseconds <= 0)
return;
struct timespec spec = {};
2015-10-28 14:32:42 -04:00
spec.tv_sec = static_cast<s64>(as_seconds(t));
spec.tv_nsec = 1000ll * (as_microseconds(t) % 1000000ll);
2015-09-28 15:31:26 -04:00
nanosleep(&spec, nullptr);
}
#endif
2015-10-18 07:18:54 -04:00
Time seconds(f32 s) { return {static_cast<s64>(s * 1000000ll)}; }
Time milliseconds(s32 ms) { return {static_cast<s64>(ms * 1000l)}; }
2015-09-29 10:11:18 -04:00
Time microseconds(s64 us) { return {us}; }
2015-10-28 14:32:42 -04:00
f32 as_seconds(Time t) { return static_cast<f32>(t.microseconds / 1000000.0f); }
s32 as_milliseconds(Time t) { return static_cast<s32>(t.microseconds / 1000l); }
s64 as_microseconds(Time t) { return t.microseconds; }
} // namespace time
bool operator==(Time left, Time right) { return left.microseconds == right.microseconds; }
bool operator!=(Time left, Time right) { return !operator==(left, right); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
bool operator<(Time left, Time right) { return left.microseconds < right.microseconds; }
bool operator>(Time left, Time right) { return left.microseconds > right.microseconds; }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
bool operator<=(Time left, Time right) { return left.microseconds <= right.microseconds; }
bool operator>=(Time left, Time right) { return left.microseconds >= right.microseconds; }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time operator-(Time right) { return {-right.microseconds}; }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time operator+(Time left, Time right) { return {left.microseconds + right.microseconds}; }
Time operator-(Time left, Time right) { return {left.microseconds - right.microseconds}; }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time& operator+=(Time& left, Time right) { return (left = left + right); }
Time& operator-=(Time& left, Time right) { return (left = left - right); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time operator*(Time left, f32 right) { return time::seconds(time::as_seconds(left) * right); }
Time operator*(Time left, s64 right) { return time::microseconds(time::as_microseconds(left) * right); }
Time operator*(f32 left, Time right) { return time::seconds(time::as_seconds(right) * left); }
Time operator*(s64 left, Time right) { return time::microseconds(time::as_microseconds(right) * left); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time& operator*=(Time& left, f32 right) { return (left = left * right); }
Time& operator*=(Time& left, s64 right) { return (left = left * right); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time operator/(Time left, f32 right) { return time::seconds(time::as_seconds(left) / right); }
Time operator/(Time left, s64 right) { return time::microseconds(time::as_microseconds(left) / right); }
f32 operator/(Time left, Time right) { return time::as_seconds(left) / time::as_seconds(right); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time& operator/=(Time& left, f32 right) { return (left = left / right); }
Time& operator/=(Time& left, s64 right) { return (left = left / right); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
Time operator%(Time left, Time right) { return time::microseconds(time::as_microseconds(left) % time::as_microseconds(right)); }
Time& operator%=(Time& left, Time right) { return (left = left % right); }
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
////////////////////////////////
/// ///
/// OS ///
/// ///
////////////////////////////////
#if 0
namespace file
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
internal char*
duplicate_string(const char* string)
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
usize len = strlen(string);
char* result = (char*)malloc(len + 1);
memory::copy(result, string, len);
result[len] = '\0';
return result;
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
uintptr
fd(const File* file)
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
if (file == nullptr)
return reinterpret_cast<uintptr>(INVALID_HANDLE_VALUE);
return reinterpret_cast<uintptr>(file->win32_handle);
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
bool
new_from_fd(File* file, uintptr h, const char* name)
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
GB_ASSERT(file == nullptr, "file == nullptr");
if (reinterpret_cast<HANDLE>(h) == INVALID_HANDLE_VALUE)
return false;
file->win32_handle = reinterpret_cast<HANDLE>(h);
file->name = duplicate_string(name);
// u32 m;
// file->is_console = GetConsoleMode(h, &m) != 0;
return true;
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
internal bool
win32_open_file(File* file, const char* name, u32 flag, u32 perm)
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
// TODO(bill):
return false;
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
bool
open(File* file, const char* name, u32 flag, u32 perm)
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
if (name == nullptr || name[0] == '\0') {
return false;
}
bool b = win32_open_file(file, name, flag, perm);
if (b)
{
file->mutex = mutex::make();
return true;
}
// TODO(bill): If directory
return false;
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
bool
close(File* file)
2015-09-28 15:31:26 -04:00
{
2015-10-28 14:32:42 -04:00
if (!file)
return false;
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
// TODO(bill): Handle directory
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
bool b = CloseHandle(file->win32_handle) != 0;
if (b)
{
free(file->name); // TODO(bill): When should this be freed?
mutex::destroy(&file->mutex);
return true;
}
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
return false;
2015-09-28 15:31:26 -04:00
}
2015-10-28 14:32:42 -04:00
// internal bool
// win32_pread(File* file, void* buffer, u32 bytes_to_read, s64 offset)
// {
// mutex::lock(&file->mutex);
// defer (mutex::unlock(&file->mutex));
2015-09-28 15:31:26 -04:00
2015-10-28 14:32:42 -04:00
// return true;
// }
2015-09-27 14:03:47 -04:00
2015-10-28 14:32:42 -04:00
// bool
// open(File* file, const char* filename, u32 flags)
// {
// u32 win32_flags = 0;
// if (flags & file::READ)
// win32_flags |= GENERIC_READ;
// if (flags & file::WRITE)
// win32_flags |= GENERIC_WRITE;
// file->win32_handle = CreateFileA(filename, win32_flags, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0);
// return (file->win32_handle != INVALID_HANDLE_VALUE);
// }
// bool
// create(File* file, const char* filename, u32 flags)
// {
// // TODO(bill):
// return false;
// }
// bool
// close(File* file)
// {
// return (CloseHandle(file->win32_handle) != 0);
// }
// bool
// read(File* file, void* buffer, u32 bytes_to_read)
// {
// DWORD win32_bytes_written;
// BOOL b = ReadFile(file->win32_handle, buffer, bytes_to_read, &win32_bytes_written, nullptr);
// if (!b || (bytes_to_read != win32_bytes_written))
// return false;
// return true;
// }
// bool
// write(File* file, const void* memory, u32 bytes_to_write)
// {
// DWORD win32_bytes_written;
// BOOL b = WriteFile(file->win32_handle, memory, bytes_to_write, &win32_bytes_written, nullptr);
// if (!b || (bytes_to_write != win32_bytes_written))
// return false;
// return true;
// }
// bool read_at(File* file, void* buffer, u32 bytes_to_read, s64 offset)
// {
// file::set_pos(file, offset);
// bool b = read(file, buffer, bytes_to_reads);
// return b;
// }
// bool write_at(File* file, const void* memory, u32 bytes_to_write, s64 offset)
// {
// file::set_pos(file, offset);
// bool b = write(file, memory, bytes_to_write);
// return b;
// }
// s64
// size(File* file)
// {
// LARGE_INTEGER file_size;
// BOOL b = GetFileSizeEx(file->win32_handle, &file_size);
// if (b)
// return static_cast<s64>(file_size.QuadPart);
// return -1;
// }
#else
#error Implement file system
#endif
} // namespace file
#endif
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
/// Math ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-28 15:31:26 -04:00
////////////////////////////////
2015-09-27 14:03:47 -04:00
2015-10-04 15:59:40 -04:00
const Vector2 VECTOR2_ZERO = {0, 0};
const Vector3 VECTOR3_ZERO = {0, 0, 0};
const Vector4 VECTOR4_ZERO = {0, 0, 0, 0};
const Complex COMPLEX_ZERO = {0, 0};
const Quaternion QUATERNION_IDENTITY = {0, 0, 0, 1};
const Matrix2 MATRIX2_IDENTITY = {1, 0,
2015-10-05 16:30:55 -04:00
0, 1};
2015-10-04 15:59:40 -04:00
const Matrix3 MATRIX3_IDENTITY = {1, 0, 0,
2015-10-05 16:30:55 -04:00
0, 1, 0,
0, 0, 1};
2015-10-04 15:59:40 -04:00
const Matrix4 MATRIX4_IDENTITY = {1, 0, 0, 0,
2015-10-05 16:30:55 -04:00
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1};
2015-10-04 15:59:40 -04:00
const Euler_Angles EULER_ANGLES_ZERO = {0, 0, 0};
const Transform TRANSFORM_IDENTITY = Transform{};
2015-09-27 14:03:47 -04:00
////////////////////////////////
/// Math Type Op Overloads ///
////////////////////////////////
// Vector2 Operators
bool operator==(const Vector2& a, const Vector2& b)
{
return (a.x == b.x) && (a.y == b.y);
}
bool operator!=(const Vector2& a, const Vector2& b)
{
return !operator==(a, b);
}
Vector2 operator-(const Vector2& a)
{
return {-a.x, -a.y};
}
Vector2 operator+(const Vector2& a, const Vector2& b)
{
return {a.x + b.x, a.y + b.y};
}
Vector2 operator-(const Vector2& a, const Vector2& b)
{
return {a.x - b.x, a.y - b.y};
}
Vector2 operator*(const Vector2& a, f32 scalar)
{
return {a.x * scalar, a.y * scalar};
}
Vector2 operator*(f32 scalar, const Vector2& a)
{
return {a.x * scalar, a.y * scalar};
}
Vector2 operator/(const Vector2& a, f32 scalar)
{
return {a.x / scalar, a.y / scalar};
}
Vector2 operator*(const Vector2& a, const Vector2& b) // Hadamard Product
{
return {a.x * b.x, a.y * b.y};
}
Vector2 operator/(const Vector2& a, const Vector2& b) // Hadamard Product
{
return {a.x / b.x, a.y / b.y};
}
Vector2& operator+=(Vector2& a, const Vector2& b)
{
a.x += b.x;
a.y += b.y;
return a;
}
Vector2& operator-=(Vector2& a, const Vector2& b)
{
a.x -= b.x;
a.y -= b.y;
return a;
}
Vector2& operator*=(Vector2& a, f32 scalar)
{
a.x *= scalar;
a.y *= scalar;
return a;
}
Vector2& operator/=(Vector2& a, f32 scalar)
{
a.x /= scalar;
a.y /= scalar;
return a;
}
// Vector3 Operators
bool operator==(const Vector3& a, const Vector3& b)
{
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
}
bool operator!=(const Vector3& a, const Vector3& b)
{
return !operator==(a, b);
}
Vector3 operator-(const Vector3& a)
{
return {-a.x, -a.y, -a.z};
}
Vector3 operator+(const Vector3& a, const Vector3& b)
{
return {a.x + b.x, a.y + b.y, a.z + b.z};
}
Vector3 operator-(const Vector3& a, const Vector3& b)
{
return {a.x - b.x, a.y - b.y, a.z - b.z};
}
Vector3 operator*(const Vector3& a, f32 scalar)
{
return {a.x * scalar, a.y * scalar, a.z * scalar};
}
Vector3 operator*(f32 scalar, const Vector3& a)
{
return {a.x * scalar, a.y * scalar, a.z * scalar};
}
Vector3 operator/(const Vector3& a, f32 scalar)
{
return {a.x / scalar, a.y / scalar, a.z / scalar};
}
Vector3 operator*(const Vector3& a, const Vector3& b) // Hadamard Product
{
return {a.x * b.x, a.y * b.y, a.z * b.z};
}
Vector3 operator/(const Vector3& a, const Vector3& b) // Hadamard Product
{
return {a.x / b.x, a.y / b.y, a.z / b.z};
}
Vector3& operator+=(Vector3& a, const Vector3& b)
{
a.x += b.x;
a.y += b.y;
a.z += b.z;
return a;
}
Vector3& operator-=(Vector3& a, const Vector3& b)
{
a.x -= b.x;
a.y -= b.y;
a.z -= b.z;
return a;
}
Vector3& operator*=(Vector3& a, f32 scalar)
{
a.x *= scalar;
a.y *= scalar;
a.z *= scalar;
return a;
}
Vector3& operator/=(Vector3& a, f32 scalar)
{
a.x /= scalar;
a.y /= scalar;
a.z /= scalar;
return a;
}
// Vector4 Operators
bool operator==(const Vector4& a, const Vector4& b)
{
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
}
bool operator!=(const Vector4& a, const Vector4& b)
{
return !operator==(a, b);
}
Vector4 operator-(const Vector4& a)
{
return {-a.x, -a.y, -a.z, -a.w};
}
Vector4 operator+(const Vector4& a, const Vector4& b)
{
return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
}
Vector4 operator-(const Vector4& a, const Vector4& b)
{
return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
}
Vector4 operator*(const Vector4& a, f32 scalar)
{
return {a.x * scalar, a.y * scalar, a.z * scalar, a.w * scalar};
}
Vector4 operator*(f32 scalar, const Vector4& a)
{
return {a.x * scalar, a.y * scalar, a.z * scalar, a.w * scalar};
}
Vector4 operator/(const Vector4& a, f32 scalar)
{
return {a.x / scalar, a.y / scalar, a.z / scalar, a.w / scalar};
}
Vector4 operator*(const Vector4& a, const Vector4& b) // Hadamard Product
{
return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
}
Vector4 operator/(const Vector4& a, const Vector4& b) // Hadamard Product
{
return {a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w};
}
Vector4& operator+=(Vector4& a, const Vector4& b)
{
a.x += b.x;
a.y += b.y;
a.z += b.z;
a.w += b.w;
return a;
}
Vector4& operator-=(Vector4& a, const Vector4& b)
{
a.x -= b.x;
a.y -= b.y;
a.z -= b.z;
a.w -= b.w;
return a;
}
Vector4& operator*=(Vector4& a, f32 scalar)
{
a.x *= scalar;
a.y *= scalar;
a.z *= scalar;
a.w *= scalar;
return a;
}
Vector4& operator/=(Vector4& a, f32 scalar)
{
a.x /= scalar;
a.y /= scalar;
a.z /= scalar;
a.w /= scalar;
return a;
}
2015-10-04 15:59:40 -04:00
// Complex Operators
bool operator==(const Complex& a, const Complex& b)
{
return (a.x == b.x) && (a.y == b.y);
}
bool operator!=(const Complex& a, const Complex& b)
{
return !operator==(a, b);
}
Complex operator-(const Complex& a)
{
return {-a.x, -a.y};
}
Complex operator+(const Complex& a, const Complex& b)
{
return {a.x + b.x, a.y + b.y};
}
Complex operator-(const Complex& a, const Complex& b)
{
return {a.x - b.x, a.y - b.y};
}
Complex operator*(const Complex& a, const Complex& b)
{
Complex c = {};
c.x = a.x * b.x - a.y * b.y;
c.y = a.y * b.x - a.y * b.x;
return c;
}
Complex operator*(const Complex& a, f32 s)
{
return {a.x * s, a.y * s};
}
Complex operator*(f32 s, const Complex& a)
{
return {a.x * s, a.y * s};
}
Complex operator/(const Complex& a, f32 s)
{
return {a.x / s, a.y / s};
}
2015-09-27 14:03:47 -04:00
// Quaternion Operators
bool operator==(const Quaternion& a, const Quaternion& b)
{
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w);
}
bool operator!=(const Quaternion& a, const Quaternion& b)
{
return !operator==(a, b);
}
Quaternion operator-(const Quaternion& a)
{
return {-a.x, -a.y, -a.z, -a.w};
}
Quaternion operator+(const Quaternion& a, const Quaternion& b)
{
return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
}
Quaternion operator-(const Quaternion& a, const Quaternion& b)
{
return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
}
Quaternion operator*(const Quaternion& a, const Quaternion& b)
{
Quaternion q = {};
q.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
q.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
q.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
q.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
return q;
}
Quaternion operator*(const Quaternion& a, f32 s)
{
return {a.x * s, a.y * s, a.z * s, a.w * s};
}
Quaternion operator*(f32 s, const Quaternion& a)
{
return {a.x * s, a.y * s, a.z * s, a.w * s};
}
Quaternion operator/(const Quaternion& a, f32 s)
{
return {a.x / s, a.y / s, a.z / s, a.w / s};
}
Vector3 operator*(const Quaternion& a, const Vector3& v) // Rotate v by q
{
// return (q * Quaternion{v.x, v.y, v.z, 0} * math::conjugate(q)).xyz; // More Expensive
const Vector3 t = 2.0f * math::cross(a.xyz, v);
return (v + a.w * t + math::cross(a.xyz, t));
}
2015-09-30 17:12:16 -04:00
// Matrix2 Operators
bool operator==(const Matrix2& a, const Matrix2& b)
{
for (usize i = 0; i < 4; i++)
{
if (a[i] != b[i])
return false;
}
return true;
}
bool operator!=(const Matrix2& a, const Matrix2& b)
{
return !operator==(a, b);
}
Matrix2 operator+(const Matrix2& a, const Matrix2& b)
{
Matrix2 mat;
mat[0] = a[0] + b[0];
mat[1] = a[1] + b[1];
return mat;
}
Matrix2 operator-(const Matrix2& a, const Matrix2& b)
{
Matrix2 mat;
mat[0] = a[0] - b[0];
mat[1] = a[1] - b[1];
return mat;
}
Matrix2 operator*(const Matrix2& a, const Matrix2& b)
{
Matrix2 result;
result[0] = a[0] * b[0][0] + a[1] * b[0][1];
result[1] = a[0] * b[1][0] + a[1] * b[1][1];
return result;
}
Vector2 operator*(const Matrix2& a, const Vector2& v)
{
2015-10-04 15:59:40 -04:00
return Vector2{a[0][0] * v.x + a[1][0] * v.y,
2015-10-05 16:30:55 -04:00
a[0][1] * v.x + a[1][1] * v.y};
2015-09-30 17:12:16 -04:00
}
Matrix2 operator*(const Matrix2& a, f32 scalar)
{
Matrix2 mat;
mat[0] = a[0] * scalar;
mat[1] = a[1] * scalar;
return mat;
}
Matrix2 operator*(f32 scalar, const Matrix2& a)
{
Matrix2 mat;
mat[0] = a[0] * scalar;
mat[1] = a[1] * scalar;
return mat;
}
Matrix2 operator/(const Matrix2& a, f32 scalar)
{
Matrix2 mat;
mat[0] = a[0] / scalar;
mat[1] = a[1] / scalar;
return mat;
}
Matrix2& operator+=(Matrix2& a, const Matrix2& b)
{
return (a = a + b);
}
Matrix2& operator-=(Matrix2& a, const Matrix2& b)
{
return (a = a - b);
}
Matrix2& operator*=(Matrix2& a, const Matrix2& b)
{
return (a = a * b);
}
// Matrix3 Operators
bool operator==(const Matrix3& a, const Matrix3& b)
{
for (usize i = 0; i < 3; i++)
{
if (a[i] != b[i])
return false;
}
return true;
}
bool operator!=(const Matrix3& a, const Matrix3& b)
{
return !operator==(a, b);
}
Matrix3 operator+(const Matrix3& a, const Matrix3& b)
{
Matrix3 mat;
mat[0] = a[0] + b[0];
mat[1] = a[1] + b[1];
mat[2] = a[2] + b[2];
return mat;
}
Matrix3 operator-(const Matrix3& a, const Matrix3& b)
{
Matrix3 mat;
mat[0] = a[0] - b[0];
mat[1] = a[1] - b[1];
mat[2] = a[2] - b[2];
return mat;
}
Matrix3 operator*(const Matrix3& a, const Matrix3& b)
{
Matrix3 result;
result[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2];
result[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2];
result[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2];
return result;
}
Vector3 operator*(const Matrix3& a, const Vector3& v)
{
2015-10-04 15:59:40 -04:00
return Vector3{a[0][0] * v.x + a[1][0] * v.y + a[2][0] * v.z,
2015-10-05 16:30:55 -04:00
a[0][1] * v.x + a[1][1] * v.y + a[2][1] * v.z,
a[0][2] * v.x + a[1][2] * v.y + a[2][2] * v.z};
2015-09-30 17:12:16 -04:00
}
Matrix3 operator*(const Matrix3& a, f32 scalar)
{
Matrix3 mat;
mat[0] = a[0] * scalar;
mat[1] = a[1] * scalar;
mat[2] = a[2] * scalar;
return mat;
}
Matrix3 operator*(f32 scalar, const Matrix3& a)
{
Matrix3 mat;
mat[0] = a[0] * scalar;
mat[1] = a[1] * scalar;
mat[2] = a[2] * scalar;
return mat;
}
Matrix3 operator/(const Matrix3& a, f32 scalar)
{
Matrix3 mat;
mat[0] = a[0] / scalar;
mat[1] = a[1] / scalar;
mat[2] = a[2] / scalar;
return mat;
}
Matrix3& operator+=(Matrix3& a, const Matrix3& b)
{
return (a = a + b);
}
Matrix3& operator-=(Matrix3& a, const Matrix3& b)
{
return (a = a - b);
}
Matrix3& operator*=(Matrix3& a, const Matrix3& b)
{
return (a = a * b);
}
2015-09-27 14:03:47 -04:00
// Matrix4 Operators
bool operator==(const Matrix4& a, const Matrix4& b)
{
for (usize i = 0; i < 4; i++)
{
if (a[i] != b[i])
return false;
}
return true;
}
bool operator!=(const Matrix4& a, const Matrix4& b)
{
return !operator==(a, b);
}
Matrix4 operator+(const Matrix4& a, const Matrix4& b)
{
Matrix4 mat;
2015-09-30 17:12:16 -04:00
mat[0] = a[0] + b[0];
mat[1] = a[1] + b[1];
mat[2] = a[2] + b[2];
mat[3] = a[3] + b[3];
2015-09-27 14:03:47 -04:00
return mat;
}
Matrix4 operator-(const Matrix4& a, const Matrix4& b)
{
Matrix4 mat;
2015-09-30 17:12:16 -04:00
mat[0] = a[0] - b[0];
mat[1] = a[1] - b[1];
mat[2] = a[2] - b[2];
mat[3] = a[3] - b[3];
2015-09-27 14:03:47 -04:00
return mat;
}
Matrix4 operator*(const Matrix4& a, const Matrix4& b)
{
Matrix4 result;
result[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2] + a[3] * b[0][3];
result[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2] + a[3] * b[1][3];
result[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2] + a[3] * b[2][3];
result[3] = a[0] * b[3][0] + a[1] * b[3][1] + a[2] * b[3][2] + a[3] * b[3][3];
return result;
}
Vector4 operator*(const Matrix4& a, const Vector4& v)
{
2015-10-04 15:59:40 -04:00
return Vector4{a[0][0] * v.x + a[1][0] * v.y + a[2][0] * v.z + a[3][0] * v.w,
2015-10-05 16:30:55 -04:00
a[0][1] * v.x + a[1][1] * v.y + a[2][1] * v.z + a[3][1] * v.w,
a[0][2] * v.x + a[1][2] * v.y + a[2][2] * v.z + a[3][2] * v.w,
a[0][3] * v.x + a[1][3] * v.y + a[2][3] * v.z + a[3][3] * v.w};
2015-09-27 14:03:47 -04:00
}
Matrix4 operator*(const Matrix4& a, f32 scalar)
{
Matrix4 mat;
2015-09-30 17:12:16 -04:00
mat[0] = a[0] * scalar;
mat[1] = a[1] * scalar;
mat[2] = a[2] * scalar;
mat[3] = a[3] * scalar;
2015-09-27 14:03:47 -04:00
return mat;
}
Matrix4 operator*(f32 scalar, const Matrix4& a)
{
Matrix4 mat;
2015-09-30 17:12:16 -04:00
mat[0] = a[0] * scalar;
mat[1] = a[1] * scalar;
mat[2] = a[2] * scalar;
mat[3] = a[3] * scalar;
2015-09-27 14:03:47 -04:00
return mat;
}
Matrix4 operator/(const Matrix4& a, f32 scalar)
{
Matrix4 mat;
2015-09-30 17:12:16 -04:00
mat[0] = a[0] / scalar;
mat[1] = a[1] / scalar;
mat[2] = a[2] / scalar;
mat[3] = a[3] / scalar;
2015-09-27 14:03:47 -04:00
return mat;
}
Matrix4& operator+=(Matrix4& a, const Matrix4& b)
{
return (a = a + b);
}
Matrix4& operator-=(Matrix4& a, const Matrix4& b)
{
return (a = a - b);
}
Matrix4& operator*=(Matrix4& a, const Matrix4& b)
{
return (a = a * b);
}
// Transform Operators
// World = Parent * Local
Transform operator*(const Transform& ps, const Transform& ls)
{
Transform ws;
ws.position = ps.position + ps.orientation * (ps.scale * ls.position);
ws.orientation = ps.orientation * ls.orientation;
ws.scale = ps.scale * (ps.orientation * ls.scale);
return ws;
}
Transform& operator*=(Transform& ps, const Transform& ls)
{
return (ps = ps * ls);
}
// Local = World / Parent
Transform operator/(const Transform& ws, const Transform& ps)
{
Transform ls;
const Quaternion ps_conjugate = math::conjugate(ps.orientation);
ls.position = (ps_conjugate * (ws.position - ps.position)) / ps.scale;
ls.orientation = ps_conjugate * ws.orientation;
ls.scale = ps_conjugate * (ws.scale / ps.scale);
return ls;
}
Transform& operator/=(Transform& ws, const Transform& ps)
{
return (ws = ws / ps);
}
2015-09-27 14:03:47 -04:00
////////////////////////////////
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
/// Math Functions ///
2015-09-30 17:12:16 -04:00
/// ///
2015-09-27 14:03:47 -04:00
////////////////////////////////
namespace math
{
2015-10-03 10:26:29 -04:00
const f32 ZERO = 0.0f;
const f32 ONE = 1.0f;
const f32 THIRD = 0.33333333f;
const f32 TWO_THIRDS = 0.66666667f;
const f32 E = 2.718281828f;
const f32 PI = 3.141592654f;
const f32 TAU = 6.283185307f;
const f32 SQRT_2 = 1.414213562f;
const f32 SQRT_3 = 1.732050808f;
2015-10-05 13:17:30 -04:00
const f32 F32_PRECISION = 1.0e-7f;
2015-09-27 14:03:47 -04:00
// Power
2015-09-28 15:31:26 -04:00
inline f32 sqrt(f32 x) { return ::sqrtf(x); }
2015-09-27 14:03:47 -04:00
inline f32 pow(f32 x, f32 y) { return (f32)::powf(x, y); }
2015-09-28 15:31:26 -04:00
inline f32 cbrt(f32 x) { return (f32)::cbrtf(x); }
2015-09-27 14:03:47 -04:00
2015-10-04 15:59:40 -04:00
inline f32
fast_inv_sqrt(f32 x)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
const f32 THREE_HALFS = 1.5f;
2015-09-27 14:03:47 -04:00
2015-10-04 15:59:40 -04:00
const f32 x2 = x * 0.5f;
2015-09-27 14:03:47 -04:00
f32 y = x;
2015-10-18 07:18:54 -04:00
u32 i = bit_cast<u32>(y); // Evil floating point bit level hacking
2015-09-27 14:03:47 -04:00
// i = 0x5f3759df - (i >> 1); // What the fuck? Old
i = 0x5f375a86 - (i >> 1); // What the fuck? Improved!
2015-10-18 07:18:54 -04:00
y = bit_cast<f32>(i);
2015-10-04 15:59:40 -04:00
y = y * (THREE_HALFS - (x2 * y * y)); // 1st iteration
// y = y * (THREE_HALFS - (x2 * y * y)); // 2nd iteration, this can be removed
2015-09-27 14:03:47 -04:00
return y;
}
// Trigonometric
inline f32 sin(f32 radians) { return ::sinf(radians); }
inline f32 cos(f32 radians) { return ::cosf(radians); }
inline f32 tan(f32 radians) { return ::tanf(radians); }
2015-09-28 15:31:26 -04:00
inline f32 asin(f32 x) { return ::asinf(x); }
inline f32 acos(f32 x) { return ::acosf(x); }
inline f32 atan(f32 x) { return ::atanf(x); }
2015-09-27 14:03:47 -04:00
inline f32 atan2(f32 y, f32 x) { return ::atan2f(y, x); }
inline f32 radians(f32 degrees) { return TAU * degrees / 360.0f; }
inline f32 degrees(f32 radians) { return 360.0f * radians / TAU; }
// Hyperbolic
inline f32 sinh(f32 x) { return ::sinhf(x); }
inline f32 cosh(f32 x) { return ::coshf(x); }
inline f32 tanh(f32 x) { return ::tanhf(x); }
inline f32 asinh(f32 x) { return ::asinhf(x); }
inline f32 acosh(f32 x) { return ::acoshf(x); }
inline f32 atanh(f32 x) { return ::atanhf(x); }
// Rounding
2015-09-28 15:31:26 -04:00
inline f32 ceil(f32 x) { return ::ceilf(x); }
inline f32 floor(f32 x) { return ::floorf(x); }
2015-09-27 14:03:47 -04:00
inline f32 mod(f32 x, f32 y) { return ::fmodf(x, y); }
2015-09-28 15:31:26 -04:00
inline f32 truncate(f32 x) { return ::truncf(x); }
inline f32 round(f32 x) { return ::roundf(x); }
2015-09-27 14:03:47 -04:00
inline s32 sign(s32 x) { return x >= 0 ? +1 : -1; }
inline s64 sign(s64 x) { return x >= 0 ? +1 : -1; }
2015-09-29 10:11:18 -04:00
inline f32 sign(f32 x) { return x >= 0.0f ? +1.0f : -1.0f; }
2015-09-27 14:03:47 -04:00
// Other
2015-10-04 15:59:40 -04:00
inline f32
abs(f32 x)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
u32 i = bit_cast<u32>(x);
2015-09-27 14:03:47 -04:00
i &= 0x7FFFFFFFul;
2015-10-18 07:18:54 -04:00
return bit_cast<f32>(i);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline s8
abs(s8 x)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
u8 i = bit_cast<u8>(x);
2015-09-27 14:03:47 -04:00
i &= 0x7Fu;
2015-10-18 07:18:54 -04:00
return bit_cast<s8>(i);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline s16
abs(s16 x)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
u16 i = bit_cast<u16>(x);
2015-09-27 14:03:47 -04:00
i &= 0x7FFFu;
2015-10-18 07:18:54 -04:00
return bit_cast<s16>(i);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline s32
abs(s32 x)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
u32 i = bit_cast<u32>(x);
2015-09-27 14:03:47 -04:00
i &= 0x7FFFFFFFul;
2015-10-18 07:18:54 -04:00
return bit_cast<s32>(i);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline s64
abs(s64 x)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
u64 i = bit_cast<u64>(x);
2015-09-27 14:03:47 -04:00
i &= 0x7FFFFFFFFFFFFFFFull;
2015-10-18 07:18:54 -04:00
return bit_cast<s64>(i);
2015-09-27 14:03:47 -04:00
}
2015-10-05 13:17:30 -04:00
inline bool
is_infinite(f32 x)
{
return isinf(x);
}
inline bool
is_nan(f32 x)
{
return isnan(x);
}
2015-09-27 14:03:47 -04:00
inline s32 min(s32 a, s32 b) { return a < b ? a : b; }
inline s64 min(s64 a, s64 b) { return a < b ? a : b; }
inline f32 min(f32 a, f32 b) { return a < b ? a : b; }
inline s32 max(s32 a, s32 b) { return a > b ? a : b; }
inline s64 max(s64 a, s64 b) { return a > b ? a : b; }
inline f32 max(f32 a, f32 b) { return a > b ? a : b; }
2015-10-04 15:59:40 -04:00
inline s32
clamp(s32 x, s32 min, s32 max)
{
if (x < min)
return min;
if (x > max)
return max;
return x;
}
2015-10-04 15:59:40 -04:00
inline s64
clamp(s64 x, s64 min, s64 max)
{
if (x < min)
return min;
if (x > max)
return max;
return x;
}
2015-10-04 15:59:40 -04:00
inline f32
clamp(f32 x, f32 min, f32 max)
{
if (x < min)
return min;
if (x > max)
return max;
return x;
}
2015-10-03 10:26:29 -04:00
template <typename T>
inline T
2015-10-18 07:18:54 -04:00
lerp(const T& x, const T& y, f32 t)
{
2015-10-03 10:26:29 -04:00
return x + (y - x) * t;
}
2015-10-03 10:26:29 -04:00
inline bool
equals(f32 a, f32 b, f32 precision)
{
return ((b <= (a + precision)) && (b >= (a - precision)));
}
2015-10-03 10:26:29 -04:00
template <typename T>
inline void
2015-10-28 14:32:42 -04:00
swap(T* a, T* b)
2015-10-03 10:26:29 -04:00
{
2015-10-28 14:32:42 -04:00
T c = gb::move(*a);
*a = gb::move(*b);
*b = gb::move(c);
2015-10-03 10:26:29 -04:00
}
2015-09-27 14:03:47 -04:00
2015-10-03 10:26:29 -04:00
template <typename T, usize N>
2015-10-04 15:59:40 -04:00
inline void
swap(T (& a)[N], T (& b)[N])
2015-10-03 10:26:29 -04:00
{
for (usize i = 0; i < N; i++)
2015-10-28 14:32:42 -04:00
math::swap(&a[i], &b[i]);
2015-10-03 10:26:29 -04:00
}
2015-09-27 14:03:47 -04:00
// Vector2 functions
2015-10-04 15:59:40 -04:00
inline f32
dot(const Vector2& a, const Vector2& b)
2015-09-27 14:03:47 -04:00
{
return a.x * b.x + a.y * b.y;
}
2015-10-04 15:59:40 -04:00
inline f32
cross(const Vector2& a, const Vector2& b)
2015-09-27 14:03:47 -04:00
{
return a.x * b.y - a.y * b.x;
}
2015-10-04 15:59:40 -04:00
inline f32
magnitude(const Vector2& a)
2015-09-27 14:03:47 -04:00
{
return math::sqrt(math::dot(a, a));
}
2015-10-04 15:59:40 -04:00
inline Vector2
normalize(const Vector2& a)
2015-09-27 14:03:47 -04:00
{
2015-10-02 08:11:18 -04:00
f32 m = magnitude(a);
if (m > 0)
return a * (1.0f / m);
return {};
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline Vector2
hadamard(const Vector2& a, const Vector2& b)
2015-09-27 14:03:47 -04:00
{
return {a.x * b.x, a.y * b.y};
}
2015-10-04 15:59:40 -04:00
inline Matrix4
matrix2_to_matrix4(const Matrix2& m)
{
Matrix4 result = MATRIX4_IDENTITY;
result[0][0] = m[0][0];
result[0][1] = m[0][1];
result[1][0] = m[1][0];
result[1][1] = m[1][1];
return result;
}
2015-09-27 14:03:47 -04:00
// Vector3 functions
2015-10-04 15:59:40 -04:00
inline f32
dot(const Vector3& a, const Vector3& b)
2015-09-27 14:03:47 -04:00
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
2015-10-04 15:59:40 -04:00
inline Vector3
cross(const Vector3& a, const Vector3& b)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
return Vector3{
2015-10-05 16:30:55 -04:00
a.y * b.z - b.y * a.z, // x
a.z * b.x - b.z * a.x, // y
a.x * b.y - b.x * a.y // z
2015-09-27 14:03:47 -04:00
};
}
2015-10-04 15:59:40 -04:00
inline f32
magnitude(const Vector3& a)
2015-09-27 14:03:47 -04:00
{
return math::sqrt(math::dot(a, a));
}
2015-10-04 15:59:40 -04:00
inline Vector3
normalize(const Vector3& a)
2015-09-27 14:03:47 -04:00
{
2015-10-02 08:11:18 -04:00
f32 m = magnitude(a);
if (m > 0)
return a * (1.0f / m);
return {};
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline Vector3
hadamard(const Vector3& a, const Vector3& b)
2015-09-27 14:03:47 -04:00
{
return {a.x * b.x, a.y * b.y, a.z * b.z};
}
2015-10-04 15:59:40 -04:00
inline Matrix4
matrix3_to_matrix4(const Matrix3& m)
{
Matrix4 result = MATRIX4_IDENTITY;
result[0][0] = m[0][0];
result[0][1] = m[0][1];
result[0][2] = m[0][2];
result[1][0] = m[1][0];
result[1][1] = m[1][1];
result[1][2] = m[1][2];
result[2][0] = m[2][0];
result[2][1] = m[2][1];
result[2][2] = m[2][2];
return result;
}
2015-09-27 14:03:47 -04:00
// Vector4 functions
2015-10-04 15:59:40 -04:00
inline f32
dot(const Vector4& a, const Vector4& b)
2015-09-27 14:03:47 -04:00
{
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
}
2015-10-04 15:59:40 -04:00
inline f32
magnitude(const Vector4& a)
2015-09-27 14:03:47 -04:00
{
return math::sqrt(math::dot(a, a));
}
2015-10-04 15:59:40 -04:00
inline Vector4
normalize(const Vector4& a)
2015-09-27 14:03:47 -04:00
{
2015-10-02 08:11:18 -04:00
f32 m = magnitude(a);
if (m > 0)
return a * (1.0f / m);
return {};
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline Vector4
hadamard(const Vector4& a, const Vector4& b)
2015-09-27 14:03:47 -04:00
{
return {a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
}
2015-10-04 15:59:40 -04:00
// Complex Functions
inline f32
dot(const Complex& a, const Complex& b)
{
return a.real * b.real + a.imag * b.imag;
}
inline f32
magnitude(const Complex& a)
{
return math::sqrt(norm(a));
}
inline f32
norm(const Complex& a)
{
return math::dot(a, a);
}
inline Complex
normalize(const Complex& a)
{
f32 m = magnitude(a);
if (m > 0)
return a / magnitude(a);
return COMPLEX_ZERO;
}
inline Complex
conjugate(const Complex& a)
{
return {a.real, -a.imag};
}
inline Complex
inverse(const Complex& a)
{
f32 m = norm(a);
if (m > 0)
return conjugate(a) / norm(a);
return COMPLEX_ZERO;
}
inline f32
complex_angle(const Complex& a)
{
return atan2(a.imag, a.real);
}
inline Complex
magnitude_angle(f32 magnitude, f32 radians)
{
f32 real = magnitude * cos(radians);
f32 imag = magnitude * sin(radians);
return {real, imag};
}
2015-09-27 14:03:47 -04:00
// Quaternion functions
2015-10-04 15:59:40 -04:00
inline f32
dot(const Quaternion& a, const Quaternion& b)
2015-09-27 14:03:47 -04:00
{
return math::dot(a.xyz, b.xyz) + a.w*b.w;
}
2015-10-04 15:59:40 -04:00
inline Quaternion
cross(const Quaternion& a, const Quaternion& b)
2015-09-27 14:03:47 -04:00
{
2015-10-04 15:59:40 -04:00
return Quaternion{a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
2015-10-05 16:30:55 -04:00
a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z,
a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x,
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z};
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline f32
magnitude(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return math::sqrt(math::dot(a, a));
}
2015-10-04 15:59:40 -04:00
inline f32
norm(const Quaternion& a)
{
return math::dot(a, a);
}
inline Quaternion
normalize(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
2015-10-02 08:11:18 -04:00
f32 m = magnitude(a);
if (m > 0)
return a * (1.0f / m);
return {};
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline Quaternion
conjugate(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return {-a.x, -a.y, -a.z, a.w};
}
2015-10-04 15:59:40 -04:00
inline Quaternion
inverse(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
f32 m = 1.0f / dot(a, a);
return math::conjugate(a) * m;
}
2015-10-04 15:59:40 -04:00
inline f32
quaternion_angle(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return 2.0f * math::acos(a.w);
}
2015-10-04 15:59:40 -04:00
inline Vector3
quaternion_axis(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
f32 s2 = 1.0f - a.w * a.w;
if (s2 <= 0.0f)
return {0, 0, 1};
f32 invs2 = 1.0f / math::sqrt(s2);
return a.xyz * invs2;
}
2015-10-04 15:59:40 -04:00
inline Quaternion
axis_angle(const Vector3& axis, f32 radians)
2015-09-27 14:03:47 -04:00
{
Vector3 a = math::normalize(axis);
f32 s = math::sin(0.5f * radians);
Quaternion q;
q.xyz = a * s;
q.w = math::cos(0.5f * radians);
return q;
}
2015-10-04 15:59:40 -04:00
inline f32
quaternion_roll(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return math::atan2(2.0f * a.x * a.y + a.z * a.w,
2015-10-05 16:30:55 -04:00
a.x * a.x + a.w * a.w - a.y * a.y - a.z * a.z);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline f32
quaternion_pitch(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return math::atan2(2.0f * a.y * a.z + a.w * a.x,
2015-10-05 16:30:55 -04:00
a.w * a.w - a.x * a.x - a.y * a.y + a.z * a.z);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline f32
quaternion_yaw(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return math::asin(-2.0f * (a.x * a.z - a.w * a.y));
}
2015-10-03 10:26:29 -04:00
inline Euler_Angles
quaternion_to_euler_angles(const Quaternion& a)
2015-09-27 14:03:47 -04:00
{
return {quaternion_pitch(a), quaternion_yaw(a), quaternion_roll(a)};
}
2015-10-03 10:26:29 -04:00
inline Quaternion
euler_angles_to_quaternion(const Euler_Angles& e,
2015-10-05 16:30:55 -04:00
const Vector3& x_axis,
const Vector3& y_axis,
const Vector3& z_axis)
2015-09-27 14:03:47 -04:00
{
Quaternion p = axis_angle(x_axis, e.pitch);
Quaternion y = axis_angle(y_axis, e.yaw);
Quaternion r = axis_angle(z_axis, e.roll);
return y * p * r;
}
// Spherical Linear Interpolation
2015-10-03 10:26:29 -04:00
inline Quaternion
slerp(const Quaternion& x, const Quaternion& y, f32 t)
{
Quaternion z = y;
f32 cos_theta = dot(x, y);
if (cos_theta < 0.0f)
{
z = -y;
cos_theta = -cos_theta;
}
if (cos_theta > 1.0f)
{
return Quaternion{lerp(x.x, y.x, t),
2015-10-05 16:30:55 -04:00
lerp(x.y, y.y, t),
lerp(x.z, y.z, t),
lerp(x.w, y.w, t)};
}
f32 angle = math::acos(cos_theta);
Quaternion result = math::sin(1.0f - (t * angle)) * x + math::sin(t * angle) * z;
return result * (1.0f / math::sin(angle));
}
// Shoemake's Quaternion Curves
// Sqherical Cubic Interpolation
2015-10-04 15:59:40 -04:00
inline Quaternion
squad(const Quaternion& p,
2015-10-05 16:30:55 -04:00
const Quaternion& a,
const Quaternion& b,
const Quaternion& q,
f32 t)
{
return slerp(slerp(p, q, t), slerp(a, b, t), 2.0f * t * (1.0f - t));
}
2015-09-30 17:12:16 -04:00
// Matrix2 functions
2015-10-04 15:59:40 -04:00
inline Matrix2
transpose(const Matrix2& m)
2015-09-30 17:12:16 -04:00
{
Matrix2 result;
for (usize i = 0; i < 2; i++)
{
for (usize j = 0; j < 2; j++)
result[i][j] = m[j][i];
}
return result;
}
2015-10-04 15:59:40 -04:00
inline f32
determinant(const Matrix2& m)
2015-09-30 17:12:16 -04:00
{
return m[0][0] * m[1][1] - m[1][0] * m[0][1];
}
2015-10-04 15:59:40 -04:00
inline Matrix2
inverse(const Matrix2& m)
2015-09-30 17:12:16 -04:00
{
f32 inv_det = 1.0f / (m[0][0] * m[1][1] - m[1][0] * m[0][1]);
Matrix2 result;
result[0][0] = m[1][1] * inv_det;
result[0][1] = -m[0][1] * inv_det;
result[1][0] = -m[1][0] * inv_det;
result[1][1] = m[0][0] * inv_det;
return result;
}
2015-10-04 15:59:40 -04:00
inline Matrix2
hadamard(const Matrix2& a, const Matrix2&b)
2015-09-30 17:12:16 -04:00
{
Matrix2 result;
result[0] = a[0] * b[0];
result[1] = a[1] * b[1];
return result;
}
// Matrix3 functions
2015-10-04 15:59:40 -04:00
inline Matrix3
transpose(const Matrix3& m)
2015-09-30 17:12:16 -04:00
{
Matrix3 result;
for (usize i = 0; i < 3; i++)
{
for (usize j = 0; j < 3; j++)
result[i][j] = m[j][i];
}
return result;
}
2015-10-04 15:59:40 -04:00
inline f32
determinant(const Matrix3& m)
2015-09-30 17:12:16 -04:00
{
return ( m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
2015-10-05 16:30:55 -04:00
-m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
+m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
2015-09-30 17:12:16 -04:00
}
2015-10-04 15:59:40 -04:00
inline Matrix3
inverse(const Matrix3& m)
2015-09-30 17:12:16 -04:00
{
f32 inv_det = 1.0f / (
+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
Matrix3 result;
result[0][0] = +(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * inv_det;
result[1][0] = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]) * inv_det;
result[2][0] = +(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * inv_det;
result[0][1] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * inv_det;
result[1][1] = +(m[0][0] * m[2][2] - m[2][0] * m[0][2]) * inv_det;
result[2][1] = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]) * inv_det;
result[0][2] = +(m[0][1] * m[1][2] - m[1][1] * m[0][2]) * inv_det;
result[1][2] = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]) * inv_det;
result[2][2] = +(m[0][0] * m[1][1] - m[1][0] * m[0][1]) * inv_det;
return result;
}
2015-10-05 13:17:30 -04:00
inline Matrix3
2015-10-04 15:59:40 -04:00
hadamard(const Matrix3& a, const Matrix3&b)
2015-09-30 17:12:16 -04:00
{
Matrix3 result;
result[0] = a[0] * b[0];
result[1] = a[1] * b[1];
result[2] = a[2] * b[2];
return result;
}
2015-09-27 14:03:47 -04:00
// Matrix4 functions
2015-10-04 15:59:40 -04:00
inline Matrix4
transpose(const Matrix4& m)
2015-09-27 14:03:47 -04:00
{
Matrix4 result;
for (usize i = 0; i < 4; i++)
{
for (usize j = 0; j < 4; j++)
result[i][j] = m[j][i];
}
return result;
}
2015-10-04 15:59:40 -04:00
f32
determinant(const Matrix4& m)
2015-09-27 14:03:47 -04:00
{
f32 coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
f32 coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
f32 coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
f32 coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
f32 coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
f32 coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
f32 coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
f32 coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
f32 coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
f32 coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
f32 coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
f32 coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
f32 coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
f32 coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
f32 coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
f32 coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
f32 coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
f32 coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
Vector4 fac0 = {coef00, coef00, coef02, coef03};
Vector4 fac1 = {coef04, coef04, coef06, coef07};
Vector4 fac2 = {coef08, coef08, coef10, coef11};
Vector4 fac3 = {coef12, coef12, coef14, coef15};
Vector4 fac4 = {coef16, coef16, coef18, coef19};
Vector4 fac5 = {coef20, coef20, coef22, coef23};
Vector4 vec0 = {m[1][0], m[0][0], m[0][0], m[0][0]};
Vector4 vec1 = {m[1][1], m[0][1], m[0][1], m[0][1]};
Vector4 vec2 = {m[1][2], m[0][2], m[0][2], m[0][2]};
Vector4 vec3 = {m[1][3], m[0][3], m[0][3], m[0][3]};
Vector4 inv0 = vec1 * fac0 - vec2 * fac1 + vec3 * fac2;
Vector4 inv1 = vec0 * fac0 - vec2 * fac3 + vec3 * fac4;
Vector4 inv2 = vec0 * fac1 - vec1 * fac3 + vec3 * fac5;
Vector4 inv3 = vec0 * fac2 - vec1 * fac4 + vec2 * fac5;
Vector4 signA = {+1, -1, +1, -1};
Vector4 signB = {-1, +1, -1, +1};
Matrix4 inverse = {inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB};
Vector4 row0 = {inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0]};
Vector4 dot0 = m[0] * row0;
f32 dot1 = (dot0[0] + dot0[1]) + (dot0[2] + dot0[3]);
return dot1;
}
2015-10-04 15:59:40 -04:00
Matrix4
inverse(const Matrix4& m)
2015-09-27 14:03:47 -04:00
{
f32 coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
f32 coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
f32 coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
f32 coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
f32 coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
f32 coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
f32 coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
f32 coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
f32 coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
f32 coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
f32 coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
f32 coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
f32 coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
f32 coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
f32 coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
f32 coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
f32 coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
f32 coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
Vector4 fac0 = {coef00, coef00, coef02, coef03};
Vector4 fac1 = {coef04, coef04, coef06, coef07};
Vector4 fac2 = {coef08, coef08, coef10, coef11};
Vector4 fac3 = {coef12, coef12, coef14, coef15};
Vector4 fac4 = {coef16, coef16, coef18, coef19};
Vector4 fac5 = {coef20, coef20, coef22, coef23};
Vector4 vec0 = {m[1][0], m[0][0], m[0][0], m[0][0]};
Vector4 vec1 = {m[1][1], m[0][1], m[0][1], m[0][1]};
Vector4 vec2 = {m[1][2], m[0][2], m[0][2], m[0][2]};
Vector4 vec3 = {m[1][3], m[0][3], m[0][3], m[0][3]};
Vector4 inv0 = vec1 * fac0 - vec2 * fac1 + vec3 * fac2;
Vector4 inv1 = vec0 * fac0 - vec2 * fac3 + vec3 * fac4;
Vector4 inv2 = vec0 * fac1 - vec1 * fac3 + vec3 * fac5;
Vector4 inv3 = vec0 * fac2 - vec1 * fac4 + vec2 * fac5;
Vector4 signA = {+1, -1, +1, -1};
Vector4 signB = {-1, +1, -1, +1};
Matrix4 inverse = {inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB};
Vector4 row0 = {inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0]};
Vector4 dot0 = m[0] * row0;
f32 dot1 = (dot0[0] + dot0[1]) + (dot0[2] + dot0[3]);
f32 oneOverDeterminant = 1.0f / dot1;
return inverse * oneOverDeterminant;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
hadamard(const Matrix4& a, const Matrix4& b)
2015-09-27 14:03:47 -04:00
{
Matrix4 result;
2015-09-30 17:12:16 -04:00
result[0] = a[0] * b[0];
result[1] = a[1] * b[1];
result[2] = a[2] * b[2];
result[3] = a[3] * b[3];
2015-09-27 14:03:47 -04:00
return result;
}
2015-10-05 13:17:30 -04:00
inline bool
is_affine(const Matrix4& m)
{
2015-10-05 16:30:55 -04:00
// E.g. No translation
2015-10-05 13:17:30 -04:00
return (equals(m.columns[3].x, 0)) &
2015-10-05 16:30:55 -04:00
(equals(m.columns[3].y, 0)) &
(equals(m.columns[3].z, 0)) &
(equals(m.columns[3].w, 1.0f));
2015-10-05 13:17:30 -04:00
}
2015-10-04 15:59:40 -04:00
inline Matrix4
quaternion_to_matrix4(const Quaternion& q)
2015-09-27 14:03:47 -04:00
{
Matrix4 mat = MATRIX4_IDENTITY;
Quaternion a = math::normalize(q);
f32 xx = a.x * a.x;
f32 yy = a.y * a.y;
f32 zz = a.z * a.z;
f32 xy = a.x * a.y;
f32 xz = a.x * a.z;
f32 yz = a.y * a.z;
f32 wx = a.w * a.x;
f32 wy = a.w * a.y;
f32 wz = a.w * a.z;
mat[0][0] = 1.0f - 2.0f * (yy + zz);
2015-09-28 15:31:26 -04:00
mat[0][1] = 2.0f * (xy + wz);
mat[0][2] = 2.0f * (xz - wy);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
mat[1][0] = 2.0f * (xy - wz);
2015-09-27 14:03:47 -04:00
mat[1][1] = 1.0f - 2.0f * (xx + zz);
2015-09-28 15:31:26 -04:00
mat[1][2] = 2.0f * (yz + wx);
2015-09-27 14:03:47 -04:00
2015-09-28 15:31:26 -04:00
mat[2][0] = 2.0f * (xz + wy);
mat[2][1] = 2.0f * (yz - wx);
2015-09-27 14:03:47 -04:00
mat[2][2] = 1.0f - 2.0f * (xx + yy);
return mat;
}
2015-10-04 15:59:40 -04:00
Quaternion
matrix4_to_quaternion(const Matrix4& m)
2015-09-27 14:03:47 -04:00
{
f32 four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
f32 four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
f32 four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
f32 four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
s32 biggestIndex = 0;
f32 four_biggest_squared_minus_1 = four_w_squared_minus_1;
if (four_x_squared_minus_1 > four_biggest_squared_minus_1)
{
four_biggest_squared_minus_1 = four_x_squared_minus_1;
2015-09-28 15:31:26 -04:00
biggestIndex = 1;
2015-09-27 14:03:47 -04:00
}
if (four_y_squared_minus_1 > four_biggest_squared_minus_1)
{
four_biggest_squared_minus_1 = four_y_squared_minus_1;
2015-09-28 15:31:26 -04:00
biggestIndex = 2;
2015-09-27 14:03:47 -04:00
}
if (four_z_squared_minus_1 > four_biggest_squared_minus_1)
{
four_biggest_squared_minus_1 = four_z_squared_minus_1;
2015-09-28 15:31:26 -04:00
biggestIndex = 3;
2015-09-27 14:03:47 -04:00
}
f32 biggestVal = math::sqrt(four_biggest_squared_minus_1 + 1.0f) * 0.5f;
f32 mult = 0.25f / biggestVal;
Quaternion q = QUATERNION_IDENTITY;
switch (biggestIndex)
{
case 0:
{
q.w = biggestVal;
q.x = (m[1][2] - m[2][1]) * mult;
q.y = (m[2][0] - m[0][2]) * mult;
q.z = (m[0][1] - m[1][0]) * mult;
}
break;
case 1:
{
q.w = (m[1][2] - m[2][1]) * mult;
q.x = biggestVal;
q.y = (m[0][1] + m[1][0]) * mult;
q.z = (m[2][0] + m[0][2]) * mult;
}
break;
case 2:
{
q.w = (m[2][0] - m[0][2]) * mult;
q.x = (m[0][1] + m[1][0]) * mult;
q.y = biggestVal;
q.z = (m[1][2] + m[2][1]) * mult;
}
break;
case 3:
{
q.w = (m[0][1] - m[1][0]) * mult;
q.x = (m[2][0] + m[0][2]) * mult;
q.y = (m[1][2] + m[2][1]) * mult;
q.z = biggestVal;
}
break;
default: // Should never actually get here. Just for sanities sake.
{
GB_ASSERT(false, "How did you get here?!");
}
break;
}
return q;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
translate(const Vector3& v)
2015-09-27 14:03:47 -04:00
{
Matrix4 result = MATRIX4_IDENTITY;
result[3].xyz = v;
result[3].w = 1;
return result;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
rotate(const Vector3& v, f32 radians)
2015-09-27 14:03:47 -04:00
{
const f32 c = math::cos(radians);
const f32 s = math::sin(radians);
const Vector3 axis = math::normalize(v);
const Vector3 t = (1.0f - c) * axis;
Matrix4 rot = MATRIX4_IDENTITY;
2015-09-28 15:31:26 -04:00
rot[0][0] = c + t.x * axis.x;
rot[0][1] = 0 + t.x * axis.y + s * axis.z;
rot[0][2] = 0 + t.x * axis.z - s * axis.y;
rot[0][3] = 0;
2015-09-27 14:03:47 -04:00
rot[1][0] = 0 + t.y * axis.x - s * axis.z;
rot[1][1] = c + t.y * axis.y;
rot[1][2] = 0 + t.y * axis.z + s * axis.x;
rot[1][3] = 0;
rot[2][0] = 0 + t.z * axis.x + s * axis.y;
rot[2][1] = 0 + t.z * axis.y - s * axis.x;
rot[2][2] = c + t.z * axis.z;
rot[2][3] = 0;
return rot;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
scale(const Vector3& v)
2015-09-27 14:03:47 -04:00
{
return { v.x, 0, 0, 0,
2015-10-05 16:30:55 -04:00
0, v.y, 0, 0,
0, 0, v.z, 0,
0, 0, 0, 1 };
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline Matrix4
ortho(f32 left, f32 right, f32 bottom, f32 top)
2015-09-27 14:03:47 -04:00
{
2015-10-18 07:18:54 -04:00
return ortho(left, right, bottom, top, -1.0f, 1.0f);
2015-09-27 14:03:47 -04:00
}
2015-10-04 15:59:40 -04:00
inline Matrix4
ortho(f32 left, f32 right, f32 bottom, f32 top, f32 z_near, f32 z_far)
2015-09-27 14:03:47 -04:00
{
Matrix4 result = MATRIX4_IDENTITY;
result[0][0] = 2.0f / (right - left);
result[1][1] = 2.0f / (top - bottom);
result[2][2] = -2.0f / (z_far - z_near);
result[3][0] = -(right + left) / (right - left);
result[3][1] = -(top + bottom) / (top - bottom);
result[3][2] = -(z_far + z_near) / (z_far - z_near);
return result;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
perspective(f32 fovy_radians, f32 aspect, f32 z_near, f32 z_far)
2015-09-27 14:03:47 -04:00
{
GB_ASSERT(math::abs(aspect) > 0.0f,
2015-10-05 16:30:55 -04:00
"math::perspective `fovy_radians` is %f", fovy_radians);
2015-09-27 14:03:47 -04:00
f32 tan_half_fovy = math::tan(0.5f * fovy_radians);
Matrix4 result = {};
result[0][0] = 1.0f / (aspect * tan_half_fovy);
result[1][1] = 1.0f / (tan_half_fovy);
result[2][2] = -(z_far + z_near) / (z_far - z_near);
result[2][3] = -1.0f;
result[3][2] = -2.0f * z_far * z_near / (z_far - z_near);
return result;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
infinite_perspective(f32 fovy_radians, f32 aspect, f32 z_near)
2015-09-27 14:03:47 -04:00
{
f32 range = math::tan(0.5f * fovy_radians) * z_near;
f32 left = -range * aspect;
f32 right = range * aspect;
f32 bottom = -range;
f32 top = range;
Matrix4 result = {};
result[0][0] = (2.0f * z_near) / (right - left);
result[1][1] = (2.0f * z_near) / (top - bottom);
result[2][2] = -1.0f;
result[2][3] = -1.0f;
result[3][2] = -2.0f * z_near;
return result;
}
2015-10-04 15:59:40 -04:00
inline Matrix4
2015-09-27 14:03:47 -04:00
look_at_matrix4(const Vector3& eye, const Vector3& center, const Vector3& up)
{
const Vector3 f = math::normalize(center - eye);
const Vector3 s = math::normalize(math::cross(f, up));
const Vector3 u = math::cross(s, f);
Matrix4 result = MATRIX4_IDENTITY;
2015-09-28 15:31:26 -04:00
result[0][0] = +s.x;
result[1][0] = +s.y;
result[2][0] = +s.z;
2015-09-27 14:03:47 -04:00
result[0][1] = +u.x;
result[1][1] = +u.y;
result[2][1] = +u.z;
result[0][2] = -f.x;
result[1][2] = -f.y;
result[2][2] = -f.z;
result[3][0] = -math::dot(s, eye);
result[3][1] = -math::dot(u, eye);
result[3][2] = +math::dot(f, eye);
return result;
}
2015-10-04 15:59:40 -04:00
inline Quaternion
2015-09-27 14:03:47 -04:00
look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up)
{
2015-10-18 07:18:54 -04:00
if (math::equals(math::magnitude(center - eye), 0, 0.001f))
2015-09-27 14:03:47 -04:00
return QUATERNION_IDENTITY; // You cannot look at where you are!
2015-10-28 14:32:42 -04:00
#if 1
2015-09-27 14:03:47 -04:00
return matrix4_to_quaternion(look_at_matrix4(eye, center, up));
2015-10-18 07:18:54 -04:00
#else
// TODO(bill): Thoroughly test this look_at_quaternion!
// Is it more efficient that that a converting a Matrix4 to a Quaternion?
Vector3 forward_l = math::normalize(center - eye);
Vector3 forward_w = {1, 0, 0};
Vector3 axis = math::cross(forward_l, forward_w);
f32 angle = math::acos(math::dot(forward_l, forward_w));
Vector3 third = math::cross(axis, forward_w);
if (math::dot(third, forward_l) < 0)
angle = -angle;
Quaternion q1 = math::axis_angle(axis, angle);
Vector3 up_l = q1 * math::normalize(up);
Vector3 right = math::normalize(math::cross(forward_l, up));
Vector3 up_w = math::normalize(math::cross(right, forward_l));
Vector3 axis2 = math::cross(up_l, up_w);
f32 angle2 = math::acos(math::dot(up_l, up_w));
Quaternion q2 = math::axis_angle(axis2, angle2);
return q2 * q1;
#endif
2015-09-27 14:03:47 -04:00
}
// Transform Functions
2015-10-04 15:59:40 -04:00
inline Vector3
transform_point(const Transform& transform, const Vector3& point)
{
return (math::conjugate(transform.orientation) * (transform.position - point)) / transform.scale;
}
2015-10-04 15:59:40 -04:00
inline Transform
inverse(const Transform& t)
{
const Quaternion inv_orientation = math::conjugate(t.orientation);
Transform inv_transform;
inv_transform.position = (inv_orientation * -t.position) / t.scale;
inv_transform.orientation = inv_orientation;
inv_transform.scale = inv_orientation * (Vector3{1, 1, 1} / t.scale);
return inv_transform;
}
2015-10-03 10:26:29 -04:00
inline Matrix4
transform_to_matrix4(const Transform& t)
{
return math::translate(t.position) * //
2015-10-05 16:30:55 -04:00
math::quaternion_to_matrix4(t.orientation) * //
math::scale(t.scale); //
}
2015-10-28 14:32:42 -04:00
global s32 g_perlin_randtab[512] =
{
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
// Copy
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
};
internal f32
perlin_grad(s32 hash, f32 x, f32 y, f32 z)
{
local_persist f32 basis[12][4] =
{
{ 1, 1, 0},
{-1, 1, 0},
{ 1,-1, 0},
{-1,-1, 0},
{ 1, 0, 1},
{-1, 0, 1},
{ 1, 0,-1},
{-1, 0,-1},
{ 0, 1, 1},
{ 0,-1, 1},
{ 0, 1,-1},
{ 0,-1,-1},
};
local_persist u8 indices[64] =
{
0,1,2,3,4,5,6,7,8,9,10,11,
0,9,1,11,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
};
f32* grad = basis[indices[hash & 63]];
return grad[0]*x + grad[1]*y + grad[2]*z;
}
inline f32
perlin_noise3(f32 x, f32 y, f32 z, s32 x_wrap, s32 y_wrap, s32 z_wrap)
{
u32 x_mask = (x_wrap-1) & 255;
u32 y_mask = (y_wrap-1) & 255;
u32 z_mask = (z_wrap-1) & 255;
s32 px = (s32)math::floor(x);
s32 py = (s32)math::floor(y);
s32 pz = (s32)math::floor(z);
s32 x0 = px & x_mask, x1 = (px+1) & x_mask;
s32 y0 = py & y_mask, y1 = (py+1) & y_mask;
s32 z0 = pz & z_mask, z1 = (pz+1) & z_mask;
#define GB__PERLIN_EASE(t) (((t*6-15)*t + 10) *t*t*t)
x -= px; f32 u = GB__PERLIN_EASE(x);
y -= py; f32 v = GB__PERLIN_EASE(y);
z -= pz; f32 w = GB__PERLIN_EASE(z);
#undef GB__PERLIN_EASE
s32 r0 = g_perlin_randtab[x0];
s32 r1 = g_perlin_randtab[x1];
s32 r00 = g_perlin_randtab[r0+y0];
s32 r01 = g_perlin_randtab[r0+y1];
s32 r10 = g_perlin_randtab[r1+y0];
s32 r11 = g_perlin_randtab[r1+y1];
f32 n000 = perlin_grad(g_perlin_randtab[r00+z0], x , y , z );
f32 n001 = perlin_grad(g_perlin_randtab[r00+z1], x , y , z-1 );
f32 n010 = perlin_grad(g_perlin_randtab[r01+z0], x , y-1, z );
f32 n011 = perlin_grad(g_perlin_randtab[r01+z1], x , y-1, z-1 );
f32 n100 = perlin_grad(g_perlin_randtab[r10+z0], x-1, y , z );
f32 n101 = perlin_grad(g_perlin_randtab[r10+z1], x-1, y , z-1 );
f32 n110 = perlin_grad(g_perlin_randtab[r11+z0], x-1, y-1, z );
f32 n111 = perlin_grad(g_perlin_randtab[r11+z1], x-1, y-1, z-1 );
f32 n00 = math::lerp(n000,n001,w);
f32 n01 = math::lerp(n010,n011,w);
f32 n10 = math::lerp(n100,n101,w);
f32 n11 = math::lerp(n110,n111,w);
f32 n0 = math::lerp(n00,n01,v);
f32 n1 = math::lerp(n10,n11,v);
return math::lerp(n0,n1,u);
}
} // namespace math
namespace aabb
{
2015-10-05 13:17:30 -04:00
inline Aabb
2015-10-28 14:32:42 -04:00
calculate(const void* vertices, usize num_vertices, usize stride, usize offset)
2015-10-05 13:17:30 -04:00
{
Vector3 min;
Vector3 max;
2015-10-05 16:30:55 -04:00
const u8* vertex = reinterpret_cast<const u8*>(vertices);
2015-10-05 13:17:30 -04:00
vertex += offset;
2015-10-05 16:30:55 -04:00
Vector3 position = pseudo_cast<Vector3>(vertex);
2015-10-05 13:17:30 -04:00
min.x = max.x = position.x;
min.y = max.y = position.y;
min.z = max.z = position.z;
vertex += stride;
for (usize i = 1; i < num_vertices; i++)
{
2015-10-05 16:30:55 -04:00
position = pseudo_cast<Vector3>(vertex);
2015-10-05 13:17:30 -04:00
vertex += stride;
Vector3 p = position;
min.x = math::min(p.x, min.x);
min.y = math::min(p.y, min.y);
min.z = math::min(p.z, min.z);
max.x = math::max(p.x, max.x);
max.y = math::max(p.y, max.y);
max.z = math::max(p.z, max.z);
}
Aabb aabb;
aabb.center = 0.5f * (min + max);
aabb.half_size = 0.5f * (max - min);
return aabb;
}
inline f32
2015-10-28 14:32:42 -04:00
surface_area(const Aabb& aabb)
2015-10-05 13:17:30 -04:00
{
Vector3 h = aabb.half_size * 2.0f;
f32 s = 0.0f;
s += h.x * h.y;
s += h.y * h.z;
s += h.z * h.x;
s *= 3.0f;
return s;
}
2015-10-03 10:26:29 -04:00
inline f32
2015-10-28 14:32:42 -04:00
volume(const Aabb& aabb)
2015-10-03 10:26:29 -04:00
{
2015-10-05 13:17:30 -04:00
Vector3 h = aabb.half_size * 2.0f;
return h.x * h.y * h.z;
}
inline Sphere
2015-10-28 14:32:42 -04:00
to_sphere(const Aabb& aabb)
2015-10-05 13:17:30 -04:00
{
Sphere s;
s.center = aabb.center;
s.radius = math::magnitude(aabb.half_size);
return s;
2015-10-03 10:26:29 -04:00
}
2015-10-05 13:17:30 -04:00
2015-10-03 10:26:29 -04:00
inline bool
2015-10-05 13:17:30 -04:00
contains(const Aabb& aabb, const Vector3& point)
2015-10-03 10:26:29 -04:00
{
Vector3 distance = aabb.center - point;
2015-10-05 13:17:30 -04:00
// NOTE(bill): & is faster than &&
2015-10-03 10:26:29 -04:00
return (math::abs(distance.x) <= aabb.half_size.x) &
2015-10-05 16:30:55 -04:00
(math::abs(distance.y) <= aabb.half_size.y) &
(math::abs(distance.z) <= aabb.half_size.z);
2015-10-03 10:26:29 -04:00
}
2015-10-05 13:17:30 -04:00
inline bool
contains(const Aabb& a, const Aabb& b)
2015-10-03 10:26:29 -04:00
{
2015-10-05 13:17:30 -04:00
Vector3 dist = a.center - b.center;
// NOTE(bill): & is faster than &&
return (math::abs(dist.x) + b.half_size.x <= a.half_size.x) &
2015-10-05 16:30:55 -04:00
(math::abs(dist.y) + b.half_size.y <= a.half_size.y) &
(math::abs(dist.z) + b.half_size.z <= a.half_size.z);
2015-10-05 13:17:30 -04:00
}
inline bool
intersects(const Aabb& a, const Aabb& b)
{
Vector3 dist = a.center - b.center;
Vector3 sum_half_sizes = a.half_size + b.half_size;
// NOTE(bill): & is faster than &&
return (math::abs(dist.x) <= sum_half_sizes.x) &
2015-10-05 16:30:55 -04:00
(math::abs(dist.y) <= sum_half_sizes.y) &
(math::abs(dist.z) <= sum_half_sizes.z);
2015-10-05 13:17:30 -04:00
}
inline Aabb
2015-10-28 14:32:42 -04:00
transform_affine(const Aabb& aabb, const Matrix4& m)
2015-10-05 13:17:30 -04:00
{
GB_ASSERT(math::is_affine(m),
2015-10-05 16:30:55 -04:00
"Passed Matrix4 must be an affine matrix");
2015-10-05 13:17:30 -04:00
Aabb result;
Vector4 ac;
ac.xyz = aabb.center;
ac.w = 1;
result.center = (m * ac).xyz;
Vector3 hs = aabb.half_size;
f32 x = math::abs(m[0][0] * hs.x + math::abs(m[0][1]) * hs.y + math::abs(m[0][2]) * hs.z);
f32 y = math::abs(m[1][0] * hs.x + math::abs(m[1][1]) * hs.y + math::abs(m[1][2]) * hs.z);
f32 z = math::abs(m[2][0] * hs.x + math::abs(m[2][1]) * hs.y + math::abs(m[2][2]) * hs.z);
result.half_size.x = math::is_infinite(math::abs(hs.x)) ? hs.x : x;
result.half_size.y = math::is_infinite(math::abs(hs.y)) ? hs.y : y;
result.half_size.z = math::is_infinite(math::abs(hs.z)) ? hs.z : z;
return result;
2015-10-03 10:26:29 -04:00
}
2015-10-28 14:32:42 -04:00
} // namespace aabb
2015-10-03 10:26:29 -04:00
2015-10-28 14:32:42 -04:00
namespace sphere
{
2015-10-05 13:17:30 -04:00
inline Sphere
2015-10-28 14:32:42 -04:00
calculate_min_bounding(const void* vertices, usize num_vertices, usize stride, usize offset, f32 step)
2015-10-05 13:17:30 -04:00
{
auto ran_gen = random::make_random_device();
auto gen = random::make_mt19937_64(random::next(&ran_gen));
2015-10-05 13:17:30 -04:00
2015-10-05 16:30:55 -04:00
const u8* vertex = reinterpret_cast<const u8*>(vertices);
2015-10-05 13:17:30 -04:00
vertex += offset;
2015-10-05 16:30:55 -04:00
Vector3 position = pseudo_cast<Vector3>(vertex[0]);
2015-10-05 13:17:30 -04:00
Vector3 center = position;
2015-10-05 16:30:55 -04:00
center += pseudo_cast<Vector3>(vertex[1 * stride]);
2015-10-05 13:17:30 -04:00
center *= 0.5f;
Vector3 d = position - center;
f32 max_dist_sq = math::dot(d, d);
f32 radius_step = step * 0.37f;
bool done;
do
{
done = true;
for (usize i = 0, index = random::uniform_usize_distribution(&gen, 0, num_vertices-1);
2015-10-05 16:30:55 -04:00
i < num_vertices;
i++, index = (index + 1)%num_vertices)
2015-10-05 13:17:30 -04:00
{
2015-10-05 16:30:55 -04:00
Vector3 position = pseudo_cast<Vector3>(vertex[index * stride]);
2015-10-05 13:17:30 -04:00
d = position - center;
f32 dist_sq = math::dot(d, d);
if (dist_sq > max_dist_sq)
{
done = false;
center = d * radius_step;
max_dist_sq = math::lerp(max_dist_sq, dist_sq, step);
break;
}
}
}
while (!done);
Sphere result;
result.center = center;
result.radius = math::sqrt(max_dist_sq);
return result;
}
inline Sphere
2015-10-28 14:32:42 -04:00
calculate_max_bounding(const void* vertices, usize num_vertices, usize stride, usize offset)
2015-10-05 13:17:30 -04:00
{
2015-10-28 14:32:42 -04:00
Aabb aabb = aabb::calculate(vertices, num_vertices, stride, offset);
2015-10-05 13:17:30 -04:00
Vector3 center = aabb.center;
f32 max_dist_sq = 0.0f;
2015-10-05 16:30:55 -04:00
const u8* vertex = reinterpret_cast<const u8*>(vertices);
2015-10-05 13:17:30 -04:00
vertex += offset;
for (usize i = 0; i < num_vertices; i++)
{
2015-10-05 16:30:55 -04:00
Vector3 position = pseudo_cast<Vector3>(vertex);
2015-10-05 13:17:30 -04:00
vertex += stride;
Vector3 d = position - center;
f32 dist_sq = math::dot(d, d);
max_dist_sq = math::max(dist_sq, max_dist_sq);
}
Sphere sphere;
sphere.center = center;
sphere.radius = math::sqrt(max_dist_sq);
return sphere;
}
inline f32
2015-10-28 14:32:42 -04:00
surface_area(const Sphere& s)
2015-10-05 13:17:30 -04:00
{
2015-10-28 14:32:42 -04:00
return 2.0f * math::TAU * s.radius * s.radius;
2015-10-05 13:17:30 -04:00
}
2015-10-03 10:26:29 -04:00
inline f32
2015-10-28 14:32:42 -04:00
volume(const Sphere& s)
2015-10-03 10:26:29 -04:00
{
2015-10-28 14:32:42 -04:00
return math::TWO_THIRDS * math::TAU * s.radius * s.radius * s.radius;
2015-10-03 10:26:29 -04:00
}
2015-10-05 13:17:30 -04:00
inline Aabb
2015-10-28 14:32:42 -04:00
to_aabb(const Sphere& s)
2015-10-05 13:17:30 -04:00
{
2015-10-05 16:58:47 -04:00
Aabb a;
a.center = s.center;
2015-10-28 14:32:42 -04:00
a.half_size.x = s.radius * math::SQRT_3;
a.half_size.y = s.radius * math::SQRT_3;
a.half_size.z = s.radius * math::SQRT_3;
2015-10-05 16:58:47 -04:00
return a;
2015-10-05 13:17:30 -04:00
}
2015-10-03 10:26:29 -04:00
inline bool
2015-10-28 14:32:42 -04:00
contains_point(const Sphere& s, const Vector3& point)
2015-10-03 10:26:29 -04:00
{
Vector3 dr = point - s.center;
f32 distance = math::dot(dr, dr);
return distance < s.radius * s.radius;
}
inline f32
2015-10-28 14:32:42 -04:00
ray_intersection(const Vector3& from, const Vector3& dir, const Sphere& s)
{
Vector3 v = s.center - from;
f32 b = math::dot(v, dir);
f32 det = (s.radius * s.radius) - math::dot(v, v) + (b * b);
if (det < 0.0 || b < s.radius)
return -1.0f;
return b - math::sqrt(det);
}
} // namespace sphere
namespace plane
{
inline f32
ray_intersection(const Vector3& from, const Vector3& dir, const Plane& p)
2015-10-03 10:26:29 -04:00
{
f32 nd = math::dot(dir, p.normal);
f32 orpn = math::dot(from, p.normal);
f32 dist = -1.0f;
if (nd < 0.0f)
dist = (-p.distance - orpn) / nd;
return dist > 0.0f ? dist : -1.0f;
}
inline bool
2015-10-28 14:32:42 -04:00
intersection3(const Plane& p1, const Plane& p2, const Plane& p3, Vector3* ip)
2015-10-03 10:26:29 -04:00
{
const Vector3& n1 = p1.normal;
const Vector3& n2 = p2.normal;
const Vector3& n3 = p3.normal;
f32 den = -math::dot(math::cross(n1, n2), n3);
if (math::equals(den, 0.0f))
return false;
Vector3 res = p1.distance * math::cross(n2, n3)
2015-10-05 16:30:55 -04:00
+ p2.distance * math::cross(n3, n1)
+ p3.distance * math::cross(n1, n2);
2015-10-28 14:32:42 -04:00
*ip = res / den;
2015-10-03 10:26:29 -04:00
return true;
}
2015-10-28 14:32:42 -04:00
} // namespace plane
2015-10-05 13:17:30 -04:00
namespace random
{
2015-10-05 16:30:55 -04:00
inline Mt19937_32::Result_Type
Mt19937_32::next()
2015-10-05 13:17:30 -04:00
{
if (index >= 624)
{
for (u32 i = 0; i < 624; i++)
{
2015-10-05 16:30:55 -04:00
s32 y = ((mt[i] & 0x80000000) + (mt[(i + 1) % 624] & 0x7fffffff)) & 0xffffffff;
2015-10-05 13:17:30 -04:00
mt[i] = mt[(i + 397) % 624] ^ y >> 1;
if (y % 2 != 0)
mt[i] = mt[i] ^ 0x9908b0df;
}
index = 0;
}
s32 y = mt[index];
y ^= (y >> 11);
y ^= (y << 7) & 2636928640;
y ^= (y << 15) & 4022730752;
y ^= (y >> 18);
index++;
return y;
}
2015-10-18 07:18:54 -04:00
inline u32 Mt19937_32::entropy() { return 32; }
2015-10-05 16:30:55 -04:00
inline u32
Mt19937_32::next_u32()
2015-10-05 13:17:30 -04:00
{
s32 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<u32>(n);
2015-10-05 13:17:30 -04:00
}
inline s32
2015-10-05 16:30:55 -04:00
Mt19937_32::next_s32()
2015-10-05 13:17:30 -04:00
{
return next();
}
inline u64
2015-10-05 16:30:55 -04:00
Mt19937_32::next_u64()
2015-10-05 13:17:30 -04:00
{
s32 n = next();
2015-10-05 16:30:55 -04:00
u64 a = n;
2015-10-28 14:32:42 -04:00
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
2015-10-05 13:17:30 -04:00
return a;
}
inline s64
2015-10-05 16:30:55 -04:00
Mt19937_32::next_s64()
2015-10-05 13:17:30 -04:00
{
s32 n = next();
2015-10-05 16:30:55 -04:00
u64 a = n;
2015-10-28 14:32:42 -04:00
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
2015-10-18 07:18:54 -04:00
return bit_cast<s64>(a);
2015-10-05 13:17:30 -04:00
}
inline f32
2015-10-05 16:30:55 -04:00
Mt19937_32::next_f32()
2015-10-05 13:17:30 -04:00
{
s32 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<f32>(n);
2015-10-05 13:17:30 -04:00
}
inline f64
2015-10-05 16:30:55 -04:00
Mt19937_32::next_f64()
2015-10-05 13:17:30 -04:00
{
s32 n = next();
2015-10-05 16:30:55 -04:00
u64 a = n;
2015-10-28 14:32:42 -04:00
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
2015-10-18 07:18:54 -04:00
return bit_cast<f64>(a);
2015-10-05 13:17:30 -04:00
}
2015-10-05 16:30:55 -04:00
inline Mt19937_64::Result_Type
Mt19937_64::next()
2015-10-05 13:17:30 -04:00
{
2015-10-18 07:18:54 -04:00
const u64 MAG01[2] = {0ull, 0xB5026F5AA96619E9ull};
2015-10-05 13:17:30 -04:00
u64 x;
if (index > 312)
{
u32 i = 0;
for (; i < 312-156; i++)
{
x = (mt[i] & 0xffffffff80000000ull) | (mt[i+1] & 0x7fffffffull);
2015-10-18 07:18:54 -04:00
mt[i] = mt[i+156] ^ (x>>1) ^ MAG01[(u32)(x & 1ull)];
2015-10-05 13:17:30 -04:00
}
for (; i < 312-1; i++)
{
x = (mt[i] & 0xffffffff80000000ull) | (mt[i+1] & 0x7fffffffull);
2015-10-18 07:18:54 -04:00
mt[i] = mt[i + (312-156)] ^ (x >> 1) ^ MAG01[(u32)(x & 1ull)];
2015-10-05 13:17:30 -04:00
}
x = (mt[312-1] & 0xffffffff80000000ull) | (mt[0] & 0x7fffffffull);
2015-10-18 07:18:54 -04:00
mt[312-1] = mt[156-1] ^ (x>>1) ^ MAG01[(u32)(x & 1ull)];
2015-10-05 13:17:30 -04:00
index = 0;
}
x = mt[index++];
x ^= (x >> 29) & 0x5555555555555555ull;
x ^= (x << 17) & 0x71d67fffeda60000ull;
x ^= (x << 37) & 0xfff7eee000000000ull;
x ^= (x >> 43);
2015-10-05 16:30:55 -04:00
return x;
}
2015-10-18 07:18:54 -04:00
inline u32 Mt19937_64::entropy() { return 64; }
2015-10-05 13:17:30 -04:00
inline u32
2015-10-05 16:30:55 -04:00
Mt19937_64::next_u32()
2015-10-05 13:17:30 -04:00
{
s64 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<u32>(n);
2015-10-05 13:17:30 -04:00
}
inline s32
2015-10-05 16:30:55 -04:00
Mt19937_64::next_s32()
2015-10-05 13:17:30 -04:00
{
s64 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<s32>(n);
2015-10-05 13:17:30 -04:00
}
inline u64
2015-10-05 16:30:55 -04:00
Mt19937_64::next_u64()
2015-10-05 13:17:30 -04:00
{
s64 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<u64>(n);
2015-10-05 13:17:30 -04:00
}
inline s64
2015-10-05 16:30:55 -04:00
Mt19937_64::next_s64()
2015-10-05 13:17:30 -04:00
{
s64 n = next();
return n;
}
inline f32
2015-10-05 16:30:55 -04:00
Mt19937_64::next_f32()
2015-10-05 13:17:30 -04:00
{
s64 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<f32>(n);
2015-10-05 13:17:30 -04:00
}
inline f64
2015-10-05 16:30:55 -04:00
Mt19937_64::next_f64()
2015-10-05 13:17:30 -04:00
{
s64 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<f64>(n);
2015-10-05 16:30:55 -04:00
}
inline Random_Device::Result_Type
Random_Device::next()
{
u32 result = 0;
2015-10-18 07:18:54 -04:00
#if defined(GB_SYSTEM_WINDOWS)
2015-10-28 14:32:42 -04:00
// rand_s(&result); // TODO(bill): fix this
2015-10-18 07:18:54 -04:00
#else
#error Implement Random_Device::next() for this platform
#endif
2015-10-05 16:58:47 -04:00
// IMPORTANT TODO(bill): Implenent Random_Device::next()
2015-10-05 16:30:55 -04:00
return result;
}
2015-10-18 07:18:54 -04:00
inline u32 Random_Device::entropy() { return 32; }
2015-10-05 16:30:55 -04:00
inline u32
Random_Device::next_u32()
{
s32 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<u32>(n);
2015-10-05 13:17:30 -04:00
}
2015-10-05 16:30:55 -04:00
inline s32
Random_Device::next_s32()
{
return next();
}
inline u64
Random_Device::next_u64()
{
s32 n = next();
u64 a = n;
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
return a;
}
inline s64
Random_Device::next_s64()
{
s32 n = next();
u64 a = n;
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
2015-10-18 07:18:54 -04:00
return bit_cast<s64>(a);
2015-10-05 16:30:55 -04:00
}
inline f32
Random_Device::next_f32()
{
s32 n = next();
2015-10-18 07:18:54 -04:00
return bit_cast<f32>(n);
2015-10-05 16:30:55 -04:00
}
inline f64
Random_Device::next_f64()
{
s32 n = next();
u64 a = n;
a = static_cast<u64>(a << 32) | static_cast<u64>(next());
2015-10-18 07:18:54 -04:00
return bit_cast<f64>(a);
2015-10-05 16:30:55 -04:00
}
2015-10-05 13:17:30 -04:00
} // namespace random
2015-10-18 07:18:54 -04:00
__GB_NAMESPACE_END
2015-09-27 14:03:47 -04:00
#endif // GB_IMPLEMENTATION