Nick Hayashi 2 years ago
parent
commit
530f85cf12
  1. 48
      README.md
  2. 42
      alloc.cpp
  3. 5
      alloc.h
  4. 71
      array.hpp
  5. 15
      config.h
  6. 4
      cpuid.cpp
  7. 6
      cpuid.h
  8. 24
      file.cpp
  9. 5
      file.h
  10. 89
      print.cpp
  11. 7
      print.h
  12. 111
      serialize.cpp
  13. 17
      serialize.h
  14. 9
      signal-handler.h
  15. 710
      sse_mathfun.h
  16. 204
      string.h
  17. 62
      table.hpp
  18. 30
      types.h
  19. 4
      util.h

48
README.md

@ -0,0 +1,48 @@
This is a library of C++ code which I use as a standard library wrapper, supplement, and in some cases, replacement.
If you want to use it, you can add all of the source files to your source tree, configure the `#define`'s in `config.h` to suit your needs, and it should just work.
The exceptions are the files `config.h` and `types.h` which are required by every other file.
- Stack, Scratch, and Block-based allocators as well as memory-leak checking mechanism and OS allocator wrappers in `alloc.h/.cpp`
- Heap-friendly String type, including format strings and StringBuffers/Builders, as well as `<string.h>` function replacements as static methods in single-header `string.h`
- Instrusive serialization mechanism in `serialize.h/.cpp` for complex types and primitives (no reflection though)
- A few hash functions, HashTable and CacheTable (hash table that can forget its keys) implementations in `table.hpp`
- A dynamic/growing array implementation in `array.hpp`
- Common file operations, `<stdio>` wrapper in `file.h/.cpp`
And some more stuff that is TODO:
- `cpuid` x86 instruction wrapper
- `glm` replacement - vector, matrix, and quaternion types and some common operations involving them
# Licenses & Other Code
## fast_float
Our serialization code uses `fast_float` library by Daniel Lemire et al, provided simultaneously under the [Apache License, Version 2.0](https://github.com/fastfloat/fast_float/blob/main/LICENSE-APACHE), the [MIT license](https://github.com/fastfloat/fast_float/blob/main/LICENSE-MIT) and/or the [BOOST license](https://github.com/fastfloat/fast_float/blob/main/LICENSE-BOOST). The `fast_float` library itself uses code originally published the Apache 2.0 license.
## sse_mathfun.h
The `sin`, `cos`, `exp`, and `log` replacements used by this library are provided by a single-header library written by Julien Pommier under the zlib license:
```
Copyright (C) 2007 Julien Pommier
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
(this is the zlib license)
```

42
alloc.cpp

@ -7,22 +7,22 @@
#if false
static void* leakcheckMalloc(size_t size, const char* file, s32 line) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return malloc(size);
}
static void* leakcheckCalloc(size_t maxNumOfElements, size_t elementSize, const char* file, s32 line) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return calloc(maxNumOfElements, elementSize);
}
static void* leakcheckRealloc(void* buffer, size_t newSize, const char* file, s32 line) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return realloc(buffer, newSize);
}
static void leakcheckFree(void* ptr, const char* file, s32 line) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
free(ptr);
}
@ -45,7 +45,7 @@ static void dumpLeaks() {
// system allocators
void* pMalloc(size_t size) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
void* p = malloc(size);
if (!p) {
@ -55,12 +55,12 @@ void* pMalloc(size_t size) {
return p;
}
void* pMalloc(size_t size, void* allocatorState) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return pMalloc(size);
}
void* pCalloc(size_t maxNumOfElements, size_t elementSize) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
void* p = calloc(maxNumOfElements, elementSize);
if (!p) {
@ -70,12 +70,12 @@ void* pCalloc(size_t maxNumOfElements, size_t elementSize) {
return p;
}
void* pCalloc(size_t maxNumOfElements, size_t elementSize, void* allocatorState) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return pCalloc(maxNumOfElements, elementSize);
}
void* pRealloc(void* buffer, size_t newSize) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
void* p = realloc(buffer, newSize);
if (!p) {
@ -86,25 +86,25 @@ void* pRealloc(void* buffer, size_t newSize) {
return p;
}
void* pRealloc(void* buffer, size_t newSize, void* allocatorState) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return pRealloc(buffer, newSize);
}
void pFree(void* ptr) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
free(ptr);
}
void pFree(void* ptr, void* allocatorState) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
pFree(ptr);
}
void pFree(const void* ptr) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
pFree((void*) ptr);
}
void pFree(const void* ptr, void* allocatorState) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
pFree((void*) ptr, allocatorState);
}
@ -124,7 +124,7 @@ void pFree(const void* ptr, void* allocatorState) {
static bool DefaultAllocatorInited = false;
static Allocator DefaultAllocator;
static void defaultAllocatorInit() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
DefaultAllocator.state = null;
DefaultAllocator.mallocate = pMalloc;
DefaultAllocator.callocate = pCalloc;
@ -134,7 +134,7 @@ static void defaultAllocatorInit() {
}
Allocator* Allocator::GetDefault() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (!DefaultAllocatorInited) defaultAllocatorInit();
return &DefaultAllocator;
}
@ -142,7 +142,7 @@ Allocator* Allocator::GetDefault() {
//================================================================================
// alignment should be a power of 2
static u64 alignForward2(u64 ptr, size_t alignment) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
u64 p, a, modulo;
p = ptr;
@ -156,14 +156,14 @@ static u64 alignForward2(u64 ptr, size_t alignment) {
return p;
}
static u64 alignForward(u64 ptr, size_t alignment) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return ((ptr + alignment - 1) / alignment) * alignment;
}
//================================================================================
// Scratch/Arena
Arena* Arena::Init(u32 sizeInBytes) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
Arena* arena = (Arena*) pMalloc(sizeof(Arena));
arena->index = 0;
arena->buffer = (u8*) pMalloc(sizeof(u8) * sizeInBytes);
@ -171,7 +171,7 @@ Arena* Arena::Init(u32 sizeInBytes) {
return arena;
}
void* Arena::Alloc(u32 sizeInBytes) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
u8* p = this->buffer + this->index;
u32 offset = (u32) alignForward2((u64) p, 64);
@ -187,7 +187,7 @@ void* Arena::Alloc(u32 sizeInBytes) {
return null;
}
void Arena::Clear() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->index = 0;
}
//================================================================================

5
alloc.h

@ -1,7 +1,8 @@
#ifndef ALLOC_H
#define ALLOC_H
#ifndef ULE_ALLOC_H
#define ULE_ALLOC_H
#include "config.h"
#include "types.h"

71
array.hpp

@ -1,9 +1,10 @@
#ifndef ARRAY_H
#define ARRAY_H
#ifndef ULE_ARRAY_H
#define ULE_ARRAY_H
#include <new> // operator new, operator delete
#include "config.h"
#include "alloc.h" // allocators...
#include "serialize.h" // serialization
#include "string.h" // String::memcpy
@ -32,21 +33,28 @@ struct Array {
T* data;
Array<T>(u32 _capacity = 8) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->length = 0;
this->capacity = _capacity;
this->data = (T*) pCalloc(sizeof (T), _capacity);
}
void* operator new(size_t size) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return pMalloc((u32) size);
}
void checkIfShouldGrow() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (this->isFull()) {
// optimal number as you approach infinite elements approaches PHI, but 1.5 sometimes works better for finite sizes
// more testing is probably needed
//
// it seems, that a commonly chosen growth rate of '2' is perhaps the worst possible choice.
// if you grow at a rate of 2x, you end up (likely) never being able to re-use the freed 'hole' in the heap
// for a future allocation of the same kind.
// useful reading for those interested in their own dynamic array implementations:
// (facebook's vector impl, a strictly better std::vector)
// https://github.com/facebook/folly/blob/main/folly/docs/FBVector.md
//
this->capacity = (u32) (this->capacity * 1.5);
this->data = (T*) pRealloc(data, sizeof(T) * this->capacity);
}
@ -54,7 +62,7 @@ struct Array {
// for when the order in the array doesn't matter, move the end of the array into the removed slot
void removeSwapWithEnd(u32 index) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (this->isEmpty()) return; // overhead, maybe assert instead?
u32 end = this->length - 1;
@ -65,7 +73,7 @@ struct Array {
}
void removeSwapWithEnd(T* addr) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
for (u32 i = 0; i < this->length; i++) {
if ((this->data + i) == addr) {
removeSwapWithEnd(i);
@ -75,7 +83,7 @@ struct Array {
}
void removeAndShrink(u32 index) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
for (u32 i = index + 1; i < this->length; i++) {
String::memcpy(this->data[i - 1], this->data[i], sizeof(T));
}
@ -83,7 +91,7 @@ struct Array {
}
void removeAndShrink(T* elementAddr) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
s32 index = -1;
for (u32 i = 0; i < this->length; i++) {
if ((this->data + i) == elementAddr) {
@ -103,7 +111,7 @@ struct Array {
}
T pop() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (this->isEmpty()) {
die("empty");
}
@ -114,7 +122,7 @@ struct Array {
// sometimes, you want to copy some POD data on the stack to the next position in the internal array
// that's what this does
u32 pushCopy(T* e) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->checkIfShouldGrow();
String::memcpy((void*) &this->data[this->length++], e, sizeof(T));
@ -126,14 +134,14 @@ struct Array {
// it is irresponsible to call this and then not store a T in that address. this increments length,
// reserving the next spot for you.
T* pushNextAddrPromise() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->checkIfShouldGrow();
return &this->data[this->length++];
}
u32 push(T e) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->checkIfShouldGrow();
this->data[this->length++] = e;
@ -142,7 +150,7 @@ struct Array {
}
u32 pushMany(T* elements, u32 count) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
// ensure we have capacity. if we have to realloc multiple times that can suck,
// but should be avoidable in practice by having an appropriately large initial capacity
while (this->capacity < (this->length + count)) {
@ -159,7 +167,7 @@ struct Array {
}
void reverse() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
u32 count = this->length / 2;
for (u32 i = 0; i < count; i++) {
@ -172,7 +180,7 @@ struct Array {
}
T shift() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (this->length == 0) {
return null;
}
@ -188,7 +196,7 @@ struct Array {
}
T unshift(T e) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->checkIfShouldGrow();
for (u32 i = 0; i < this->length; i++) {
@ -202,7 +210,7 @@ struct Array {
}
T peek() const {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (this->isEmpty()) {
return null;
}
@ -211,24 +219,25 @@ struct Array {
}
bool isEmpty() const {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return this->length == 0;
}
bool isFull() const {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return this->length == this->capacity;
}
void clear() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
this->length = 0;
}
};
template <typename T>
#ifdef ULE_CONFIG_OPTION_SERIALIZATION
extern template <typename T>
static void serialize(String* str, Array<T> array) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
serialize(str, array.length);
serialize(str, array.capacity);
for (u32 i = 0; i < array.length; i++) {
@ -236,9 +245,9 @@ static void serialize(String* str, Array<T> array) {
}
}
template <typename T>
extern template <typename T>
static void serialize(String* str, Array<T>* array) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
SERIALIZE_HANDLE_NULL(str, array);
serialize(str, array->length);
serialize(str, array->capacity);
@ -247,9 +256,9 @@ static void serialize(String* str, Array<T>* array) {
}
}
template <typename T>
extern template <typename T>
static void deserialize(char** buffer, Array<T>* array) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
deserialize(buffer, &array->length);
deserialize(buffer, &array->capacity);
for (u32 i = 0; i < array->length; i++) {
@ -257,9 +266,9 @@ static void deserialize(char** buffer, Array<T>* array) {
}
}
template <typename T>
extern template <typename T>
static void deserialize(char** buffer, Array<T>** array) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
DESERIALIZE_HANDLE_NULL(buffer, array);
u32 length, capacity;
deserialize(buffer, &length);
@ -271,5 +280,7 @@ static void deserialize(char** buffer, Array<T>** array) {
}
*array = _array;
}
#endif // ULE_CONFIG_OPTION_SERIALIZATION
#endif

15
config.h

@ -0,0 +1,15 @@
#pragma once
#ifndef ULE_CONFIG_H
#define ULE_CONFIG_H
// define this macro to include the serialization code `serialize.h/.cpp`, as well as serialization
// for the hashtable(s) and array implementations.
//#define ULE_CONFIG_OPTION_SERIALIZATION
// all functions in the library will invoke a semicolon-terminated macro as their first line of execution.
// this is for use by an instrusive profiler, though could be used for whatever purpose.
//#define ULE_CONFIG_OPTION_FTAG ZoneScoped
#endif

4
cpuid.cpp

@ -45,7 +45,7 @@ static const char* szFeatures[] = {
// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/hskdteyh(v=vs.90)?redirectedfrom=MSDN
#include <intrin.h>
void cpuid() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
int nSteppingID = 0;
int nModel = 0;
int nFamily = 0;
@ -142,7 +142,7 @@ void cpuid() {
#else
void cpuid() {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
}
#endif

6
cpuid.h

@ -1,6 +1,8 @@
#ifndef CPUID_H
#define CPUID_H
#ifndef ULE_CPUID_H
#define ULE_CPUID_H
#include "config.h"
void cpuid();

24
file.cpp

@ -11,11 +11,11 @@
FILE* File::Open(const char* path, const char* mode) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return fopen(path, mode);
}
FILE* File::Open(const char* path, size_t* outSize, const char* mode) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
FILE* fp = File::Open(path, mode);
if (fp == null) {
@ -34,7 +34,7 @@ void File::Close(FILE* file) {
}
size_t File::Size(const char* path) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
FILE* fp = File::Open(path);
// get the file's size in bytes
fseek(fp, 0, SEEK_END);
@ -44,7 +44,7 @@ size_t File::Size(const char* path) {
return size;
}
size_t File::Size(FILE* fp) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
@ -52,7 +52,7 @@ size_t File::Size(FILE* fp) {
}
u8* File::Read(const char* path) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
FILE* fp = File::Open(path, "rb");
if (fp == null) {
@ -73,7 +73,7 @@ u8* File::Read(const char* path) {
return (u8*) buffer;
}
u8* File::Read(const char* path, size_t* outSize) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
FILE* fp = File::Open(path, "rb");
if (fp == null) {
@ -98,7 +98,7 @@ u8* File::Read(const char* path, size_t* outSize) {
return (u8*) buffer;
}
size_t File::Read(FILE* fp, void* destination) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
@ -108,12 +108,12 @@ size_t File::Read(FILE* fp, void* destination) {
return size;
}
size_t File::Read(FILE* fp, void* destination, size_t size) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
return fread(destination, sizeof (char), size + 1, fp);
}
s32 File::Write(const char* path, char* data, u32 count) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
FILE* fp = File::Open(path, "wb");
if (fp == null) {
@ -134,7 +134,7 @@ s32 File::Write(const char* path, char* data, u32 count) {
#include <windows.h>
// writes the filenames into the provided array |outFileNames|, must be allocated ahead of time.
void File::GetFileNamesInFolder(const char* path, Array<char*>* outFileNames) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
massert(path != null, "provided 'null' for path argument");
massert(outFileNames != null, "provided 'null' for array argument");
WIN32_FIND_DATAA findData;
@ -160,7 +160,7 @@ void File::GetFileNamesInFolder(const char* path, Array<char*>* outFileNames) {
#else
#include <dirent.h>
void File::GetFileNamesInFolder(const char* path, Array<char*>* outFileNames) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
massert(path != null, "provided 'null' for path argument");
massert(outFileNames != null, "provided 'null' for array argument");
DIR* dir = opendir(path);
@ -189,7 +189,7 @@ void File::GetFileNamesInFolder(const char* path, Array<char*>* outFileNames) {
#endif
time_t File::LastModified(const char* path) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
struct stat result;
if (stat(path, &result) == 0) {
return result.st_mtime;

5
file.h

@ -1,10 +1,11 @@
#ifndef FILE_H
#define FILE_H
#ifndef ULE_FILE_H
#define ULE_FILE_H
#include <stdio.h> // FILE
#include <sys/types.h> // time_t
#include "config.h"
#include "array.hpp"

89
print.cpp

@ -10,12 +10,12 @@
void vprint(const char* format, va_list args) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
vfprintf(stdout, format, args);
}
void vprintln(const char* format, va_list args) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
vprint(format, args);
print("\n");
}
@ -25,7 +25,7 @@ void vprintln(const char* format, va_list args) {
* +we intend to replace printf at some point with this
*/
void print(const char* format, ...) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (format == null) { print("null"); return; }
va_list args;
@ -37,7 +37,7 @@ void print(const char* format, ...) {
}
void println(const char* format, ...) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (format == null) { print("null\n"); return; }
va_list args;
@ -58,7 +58,7 @@ void println(const char* format, ...) {
#include <dbghelp.h>
// if |string| is non-null, then the stack trace will be concatenated to it instead of being printed to stdout.
void trace(String* string) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
#define BACKTRACE_MAX_FUNCTION_NAME_LENGTH 1024
HANDLE processHandle = GetCurrentProcess();
@ -105,7 +105,7 @@ void trace(String* string) {
#include <cxxabi.h> // abi::__cxa_demangle
// if |string| is non-null, then the stack trace will be concatenated to it instead of being printed to stdout.
void trace(String* string) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
void* stack[BACKTRACE_MAX_FRAMES];
u32 stackSize = backtrace(stack, BACKTRACE_MAX_FRAMES);
@ -156,7 +156,7 @@ void trace(String* string) {
#endif
void _debug(const char* format, ...) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (format == null) {
print("%sdebug:%s null\n", ANSI_BLUE, ANSI_RESET);
return;
@ -172,7 +172,7 @@ void _debug(const char* format, ...) {
}
void _warn(const char* format, ...) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (format == null) {
print("%swarning:%s null\n", ANSI_YELLOW, ANSI_RESET);
return;
@ -198,7 +198,7 @@ void setCustomDieBehavior(void (*dieBehavior)(const char* string)) {
// if a fatal error should not occur at runtime on a release binary, consider preferring 'massert'
// it's unclear when you should use asserts vs. die actually. idk man
void die(const char* format, ...) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (format == null) {
if (customDie == null) {
print("%serror:%s (unspecified error)\n", ANSI_RED, ANSI_RESET);
@ -239,42 +239,43 @@ void die(const char* format, ...) {
}
}
void print(bool b) { TYPES_H_FTAG; print("%s", b ? "true" : "false"); }
void print(char c) { TYPES_H_FTAG; print("%c", c); }
void print(signed int i) { TYPES_H_FTAG; print("%d", i); }
void print(unsigned int i) { TYPES_H_FTAG; print("%u", i); }
void print(float f) { TYPES_H_FTAG; print("%.14g", f); }
void print(double d) { TYPES_H_FTAG; print("%.14g", d); }
void print(void* p) { TYPES_H_FTAG; print("%p", p); }
void print(char* s) { TYPES_H_FTAG; print("%s", s); }
void print(bool b) { ULE_TYPES_H_FTAG; print("%s", b ? "true" : "false"); }
void print(char c) { ULE_TYPES_H_FTAG; print("%c", c); }
void print(signed int i) { ULE_TYPES_H_FTAG; print("%d", i); }
void print(unsigned int i) { ULE_TYPES_H_FTAG; print("%u", i); }
void print(float f) { ULE_TYPES_H_FTAG; print("%.14g", f); }
void print(double d) { ULE_TYPES_H_FTAG; print("%.14g", d); }
void print(void* p) { ULE_TYPES_H_FTAG; print("%p", p); }
void print(char* s) { ULE_TYPES_H_FTAG; print("%s", s); }
#ifndef _WIN32
void print(size_t i) { TYPES_H_FTAG; print("%u", i); }
void println(size_t i) { TYPES_H_FTAG; print(i); print("\n"); }
void print(size_t i) { ULE_TYPES_H_FTAG; print("%u", i); }
void println(size_t i) { ULE_TYPES_H_FTAG; print(i); print("\n"); }
#endif
void println(bool b) { TYPES_H_FTAG; print(b); print("\n"); }
void println(char c) { TYPES_H_FTAG; print(c); print("\n"); }
void println(signed int i) { TYPES_H_FTAG; print(i); print("\n"); }
void println(unsigned int i) { TYPES_H_FTAG; print(i); print("\n"); }
void println(float f) { TYPES_H_FTAG; print(f); print("\n"); }
void println(double d) { TYPES_H_FTAG; print(d); print("\n"); }
void println(void* p) { TYPES_H_FTAG; print(p); print("\n"); }
void println(char* s) { TYPES_H_FTAG; print(s); print("\n"); }
void println() { TYPES_H_FTAG; print("\n"); }
#ifdef _USING_GLM_TYPES__
void print(glm::vec<2, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; print("vec2: %.14g,%.14g", v.x, v.y); }
void print(glm::vec<3, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; print("vec3: %.14g,%.14g,%.14g", v.x, v.y, v.z); }
void print(glm::vec<4, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; print("vec4: %.14g,%.14g,%.14g,%.14g", v.x, v.y, v.z, v.w); }
void print(glm::mat<2, 2, float, (glm::qualifier) 3> m) { TYPES_H_FTAG; print("mat2: "); print(m[0]); print(m[1]); }
void print(glm::mat<3, 3, float, (glm::qualifier) 3> m) { TYPES_H_FTAG; print("mat3: "); print(m[0]); print(m[1]); print(m[2]); }
void print(glm::mat<4, 4, float, (glm::qualifier) 3> m) { TYPES_H_FTAG; print("mat4: "); print(m[0]); print(m[1]); print(m[2]); print(m[3]); }
void println(glm::vec<2, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; print(v); print("\n"); }
void println(glm::vec<3, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; print(v); print("\n"); }
void println(glm::vec<4, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; print(v); print("\n"); }
void println(glm::mat<2, 2, float, (glm::qualifier) 3> m) { TYPES_H_FTAG; print(m); print("\n"); }
void println(glm::mat<3, 3, float, (glm::qualifier) 3> m) { TYPES_H_FTAG; print(m); print("\n"); }
void println(glm::mat<4, 4, float, (glm::qualifier) 3> m) { TYPES_H_FTAG; print(m); print("\n"); }
#endif
void println(bool b) { ULE_TYPES_H_FTAG; print(b); print("\n"); }
void println(char c) { ULE_TYPES_H_FTAG; print(c); print("\n"); }
void println(signed int i) { ULE_TYPES_H_FTAG; print(i); print("\n"); }
void println(unsigned int i) { ULE_TYPES_H_FTAG; print(i); print("\n"); }
void println(float f) { ULE_TYPES_H_FTAG; print(f); print("\n"); }
void println(double d) { ULE_TYPES_H_FTAG; print(d); print("\n"); }
void println(void* p) { ULE_TYPES_H_FTAG; print(p); print("\n"); }
void println(char* s) { ULE_TYPES_H_FTAG; print(s); print("\n"); }
void println() { ULE_TYPES_H_FTAG; print("\n"); }
#ifdef ULE_CONFIG_OPTION_USE_GLM
void print(glm::vec<2, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; print("vec2: %.14g,%.14g", v.x, v.y); }
void print(glm::vec<3, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; print("vec3: %.14g,%.14g,%.14g", v.x, v.y, v.z); }
void print(glm::vec<4, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; print("vec4: %.14g,%.14g,%.14g,%.14g", v.x, v.y, v.z, v.w); }
void print(glm::mat<2, 2, float, (glm::qualifier) 3> m) { ULE_TYPES_H_FTAG; print("mat2: "); print(m[0]); print(m[1]); }
void print(glm::mat<3, 3, float, (glm::qualifier) 3> m) { ULE_TYPES_H_FTAG; print("mat3: "); print(m[0]); print(m[1]); print(m[2]); }
void print(glm::mat<4, 4, float, (glm::qualifier) 3> m) { ULE_TYPES_H_FTAG; print("mat4: "); print(m[0]); print(m[1]); print(m[2]); print(m[3]); }
void println(glm::vec<2, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; print(v); print("\n"); }
void println(glm::vec<3, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; print(v); print("\n"); }
void println(glm::vec<4, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; print(v); print("\n"); }
void println(glm::mat<2, 2, float, (glm::qualifier) 3> m) { ULE_TYPES_H_FTAG; print(m); print("\n"); }
void println(glm::mat<3, 3, float, (glm::qualifier) 3> m) { ULE_TYPES_H_FTAG; print(m); print("\n"); }
void println(glm::mat<4, 4, float, (glm::qualifier) 3> m) { ULE_TYPES_H_FTAG; print(m); print("\n"); }
#endif // ULE_CONFIG_OPTION_USE_GLM

7
print.h

@ -1,9 +1,10 @@
#ifndef PRINT_H
#define PRINT_H
#ifndef ULE_PRINT_H
#define ULE_PRINT_H
#include <stdarg.h> // va_list
#include "config.h"
#include "string.h"
#include "types.h"
@ -135,7 +136,7 @@ extern void println(void* p);
extern void println(char* s);
extern void println();
#ifdef _USING_GLM_TYPES__
#ifdef ULE_CONFIG_OPTION_USE_GLM
extern void print(glm::vec<2, float, (glm::qualifier) 3>);
extern void print(glm::vec<3, float, (glm::qualifier) 3>);
extern void print(glm::vec<4, float, (glm::qualifier) 3>);

111
serialize.cpp

@ -1,4 +1,6 @@
#ifdef ULE_CONFIG_OPTION_SERIALIZATION
#include <fast_float/fast_float.h>
#include "types.h"
@ -7,52 +9,52 @@
#include "print.h"
static inline const char* getFormatStringOut(u8 v) { TYPES_H_FTAG; return "%hu\n"; }
static inline const char* getFormatStringOut(u16 v) { TYPES_H_FTAG; return "%hu\n"; }
static inline const char* getFormatStringOut(u32 v) { TYPES_H_FTAG; return "%u\n"; }
static inline const char* getFormatStringOut(u64 v) { TYPES_H_FTAG; return "%llu\n"; }
static inline const char* getFormatStringOut(u8 v) { ULE_TYPES_H_FTAG; return "%hu\n"; }
static inline const char* getFormatStringOut(u16 v) { ULE_TYPES_H_FTAG; return "%hu\n"; }
static inline const char* getFormatStringOut(u32 v) { ULE_TYPES_H_FTAG; return "%u\n"; }
static inline const char* getFormatStringOut(u64 v) { ULE_TYPES_H_FTAG; return "%llu\n"; }
static inline const char* getFormatStringOut(s8 v) { TYPES_H_FTAG; return "%hd\n"; }
static inline const char* getFormatStringOut(s16 v) { TYPES_H_FTAG; return "%hd\n"; }
static inline const char* getFormatStringOut(s32 v) { TYPES_H_FTAG; return "%d\n"; }
static inline const char* getFormatStringOut(s64 v) { TYPES_H_FTAG; return "%lld\n"; }
static inline const char* getFormatStringOut(s8 v) { ULE_TYPES_H_FTAG; return "%hd\n"; }
static inline const char* getFormatStringOut(s16 v) { ULE_TYPES_H_FTAG; return "%hd\n"; }
static inline const char* getFormatStringOut(s32 v) { ULE_TYPES_H_FTAG; return "%d\n"; }
static inline const char* getFormatStringOut(s64 v) { ULE_TYPES_H_FTAG; return "%lld\n"; }
static inline const char* getFormatStringOut(float v) { TYPES_H_FTAG; return "%f\n"; }
static inline const char* getFormatStringOut(double v) { TYPES_H_FTAG; return "%f\n"; }
static inline const char* getFormatStringOut(float v) { ULE_TYPES_H_FTAG; return "%f\n"; }
static inline const char* getFormatStringOut(double v) { ULE_TYPES_H_FTAG; return "%f\n"; }
// important constraint - strings need to be wrapped in double-quotes.
// the sentinel value 'null' without quotations is used to denote null values, which means
// if strings were not wrapped in double quotes, you would not be able to distinguish null
// values from the literal string "null".
static inline const char* getFormatStringOut(char* v) { TYPES_H_FTAG; return "\"%s\"\n"; }
static inline const char* getFormatStringOut(const char* v) { TYPES_H_FTAG; return "\"%s\"\n"; }
static inline const char* getFormatStringOut(char* v) { ULE_TYPES_H_FTAG; return "\"%s\"\n"; }
static inline const char* getFormatStringOut(const char* v) { ULE_TYPES_H_FTAG; return "\"%s\"\n"; }
#ifdef _USING_GLM_TYPES__
static inline const char* getFormatStringOut(glm::vec<2, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; return "%f %f\n"; }
static inline const char* getFormatStringOut(glm::vec<3, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; return "%f %f %f\n"; }
static inline const char* getFormatStringOut(glm::vec<4, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; return "%f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::vec<2, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f\n"; }
static inline const char* getFormatStringOut(glm::vec<3, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f\n"; }
static inline const char* getFormatStringOut(glm::vec<4, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::mat<2, 2, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; return "%f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::mat<3, 3, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; return "%f %f %f %f %f %f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::mat<4, 4, float, (glm::qualifier) 3> v) { TYPES_H_FTAG; return "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::mat<2, 2, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::mat<3, 3, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f %f %f %f %f %f\n"; }
static inline const char* getFormatStringOut(glm::mat<4, 4, float, (glm::qualifier) 3> v) { ULE_TYPES_H_FTAG; return "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n"; }
#endif
#define SERIALIZE_H_FUNC_BODY str->appendf(getFormatStringOut(v), v);
void serialize(String* str, u8 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, u16 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, u32 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, u64 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s8 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s16 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s32 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s64 v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, float v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, double v) { TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
template<typename T> // do I really need a template for this?
void serialize(String* str, u8 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, u16 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, u32 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, u64 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s8 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s16 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s32 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, s64 v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, float v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
void serialize(String* str, double v) { ULE_TYPES_H_FTAG; SERIALIZE_H_FUNC_BODY }
extern template<typename T> // @TODO do not use a template for this.
static inline void deserializeInteger(char** buffer, T* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
char* _buffer = *buffer;
T value = 0;
@ -107,7 +109,7 @@ static const u32 BINARY32_MAX_CHARS = 14;
static const u32 BINARY64_MAX_CHARS = 24;
void deserialize(char** buffer, float* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
char* _buffer = *buffer;
while (String::isAsciiWhitespace(*_buffer)) _buffer++;
fast_float::from_chars_result result = fast_float::from_chars(_buffer, _buffer + BINARY32_MAX_CHARS, *v);
@ -115,7 +117,7 @@ void deserialize(char** buffer, float* v) {
*buffer = (char*) result.ptr;
}
void deserialize(char** buffer, double* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
char* _buffer = *buffer;
while (String::isAsciiWhitespace(*_buffer)) _buffer++;
fast_float::from_chars_result result = fast_float::from_chars(_buffer, _buffer + BINARY64_MAX_CHARS, *v);
@ -125,19 +127,19 @@ void deserialize(char** buffer, double* v) {
#ifndef _WIN32
// win32 doesn't treat size_t as different than a u64, which causes ambiguous function calls
static inline const char* getFormatStringOut(size_t v) { TYPES_H_FTAG; return "%lu\n"; }
static inline const char* getFormatStringOut(size_t v) { ULE_TYPES_H_FTAG; return "%lu\n"; }
void serialize(String* str, size_t v) { SERIALIZE_H_FUNC_BODY }
void deserialize(char** buffer, size_t* v) { SERIALIZE_H_DESERIALIZE_FUNC_BODY }
#endif
// STRING STUFF
void serialize(String* str, char* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
SERIALIZE_HANDLE_NULL(str, v);
SERIALIZE_H_FUNC_BODY;
}
void serialize(String* str, const char* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
SERIALIZE_HANDLE_NULL(str, v);
SERIALIZE_H_FUNC_BODY;
}
@ -160,7 +162,7 @@ void serialize(String* str, const char* v) {
static char SERIALIZE_SCRATCH_BUFFER[SERIALIZE_SCRATCH_BUFFER_SIZE];
static s32 deserializeString(char** buffer, char* v, s32 vSize) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
char* _buffer = *buffer;
while (String::isAsciiWhitespace(*_buffer)) _buffer++;
@ -181,7 +183,7 @@ static s32 deserializeString(char** buffer, char* v, s32 vSize) {
return i;
}
static s32 deserializeString(char** buffer, char* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
char* _buffer = *buffer;
while (String::isAsciiWhitespace(*_buffer)) _buffer++;
massert(_buffer[0] == '"', "expecting to deserialize a string, but found something other than a double quote");
@ -199,15 +201,15 @@ static s32 deserializeString(char** buffer, char* v) {
return i;
}
void deserialize(char** buffer, char* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
deserializeString(buffer, v);
}
void deserialize(char** buffer, const char* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
deserializeString(buffer, (char*) v);
}
void deserialize(char** buffer, char** v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
DESERIALIZE_HANDLE_NULL(buffer, v);
@ -216,7 +218,7 @@ void deserialize(char** buffer, char** v) {
*v = String::cpy(SERIALIZE_SCRATCH_BUFFER, (u32) i);
}
void deserialize(char** buffer, const char** v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
DESERIALIZE_HANDLE_NULL(buffer, (char*) v); // error: readonly variable is not assignable
@ -231,33 +233,33 @@ void deserialize(char** buffer, const char** v) {
// have that template parameter == 3, so everything below becomes unresolved symbols if
// I don't do the nasty template garbage here
void serialize(String* str, glm::vec<2, float, (glm::qualifier) (glm::qualifier) 3> v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
str->appendf(getFormatStringOut(v), v[0], v[1]);
}
void serialize(String* str, glm::vec<3, float, (glm::qualifier) (glm::qualifier) 3> v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
str->appendf(getFormatStringOut(v), v[0], v[1], v[2]);
}
void serialize(String* str, glm::vec<4, float, (glm::qualifier) 3> v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
str->appendf(getFormatStringOut(v), v[0], v[1], v[2], v[3]);
}
void serialize(String* str, glm::mat<2, 2, float, (glm::qualifier) 3> v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
str->appendf(getFormatStringOut(v)
, v[0][0], v[0][1]
, v[1][0], v[1][1]);
}
void serialize(String* str, glm::mat<3, 3, float, (glm::qualifier) 3> v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
str->appendf(getFormatStringOut(v)
, v[0][0], v[0][1], v[0][2]
, v[1][0], v[1][1], v[1][2]
, v[2][0], v[2][1], v[2][2]);
}
void serialize(String* str, glm::mat<4, 4, float, (glm::qualifier) 3> v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
str->appendf(getFormatStringOut(v)
, v[0][0], v[0][1], v[0][2], v[0][3]
, v[1][0], v[1][1], v[1][2], v[1][3]
@ -266,21 +268,21 @@ void serialize(String* str, glm::mat<4, 4, float, (glm::qualifier) 3> v) {
}
void deserialize(char** buffer, glm::vec<2, float, (glm::qualifier) 3>* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
float* _v = (float*) v;
for (u32 i = 0; i < 2; i++) {
deserialize(buffer, _v + i);
}
}
void deserialize(char** buffer, glm::vec<3, float, (glm::qualifier) 3>* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
float* _v = (float*) v;
for (u32 i = 0; i < 3; i++) {
deserialize(buffer, _v + i);
}
}
void deserialize(char** buffer, glm::vec<4, float, (glm::qualifier) 3>* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
float* _v = (float*) v;
for (u32 i = 0; i < 4; i++) {
deserialize(buffer, _v + i);
@ -288,21 +290,21 @@ void deserialize(char** buffer, glm::vec<4, float, (glm::qualifier) 3>* v) {
}
void deserialize(char** buffer, glm::mat<2, 2, float, (glm::qualifier) 3>* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
float* m = (float*) v;
for (u32 i = 0; i < 4; i++) {
deserialize(buffer, m + i);
}
}
void deserialize(char** buffer, glm::mat<3, 3, float, (glm::qualifier) 3>* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
float* m = (float*) v;
for (u32 i = 0; i < 9; i++) {
deserialize(buffer, m + i);
}
}
void deserialize(char** buffer, glm::mat<4, 4, float, (glm::qualifier) 3>* v) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
float* m = (float*) v;
for (u32 i = 0; i < 16; i++) {
deserialize(buffer, m + i);
@ -313,4 +315,5 @@ void deserialize(char** buffer, glm::mat<4, 4, float, (glm::qualifier) 3>* v) {
#undef SERIALIZE_H_DESERIALIZE_FUNC_BODY
#endif
#endif

17
serialize.h

@ -1,12 +1,15 @@
#ifndef SERIALIZE_H
#define SERIALIZE_H
#ifdef ULE_CONFIG_OPTION_SERIALIZATION
#ifndef ULE_SERIALIZE_H
#define ULE_SERIALIZE_H
#include "config.h"
#include "print.h"
#include "types.h"
#include "string.h"
/*
NOTES ON SERIALIZATION
after wrestling with various reflection libraries for a week, I decided to use none of them.
@ -72,13 +75,13 @@ extern void serialize(String* str, T v); \
extern void deserialize(char** buffer, T* v); \
extern void deserialize(char** buffer, T** v); \
static void serializePrint(T* v) { \
TYPES_H_FTAG; \
ULE_TYPES_H_FTAG; \
String str = String(""); \
serialize(&str, v); \
println(str.c_str()); \
} \
static bool serializeEquals(T* t1, T* t2) { \
TYPES_H_FTAG; \
ULE_TYPES_H_FTAG; \
String s1 = String128f(""); \
String s2 = String128f(""); \
serialize(&s1, t1); \
@ -89,7 +92,7 @@ static bool serializeEquals(T* t1, T* t2) { \
// if you implement deserialize with a T*.
#define SERIALIZE_H_HELPER_CLONE_T_POINTER(T) \
static void serializeClone(T* orig, T* destination) { \
TYPES_H_FTAG; \
ULE_TYPES_H_FTAG; \
String str = String128f(""); \
serialize(&str, orig); \
char* buffer = str.c_str(); \
@ -99,7 +102,7 @@ static void serializeClone(T* orig, T* destination) { \
// if you implement deserialize with a T**.
#define SERIALIZE_H_HELPER_CLONE_T_DOUBLE_POINTER(T) \
static void serializeClone(T* orig, T** destination) { \
TYPES_H_FTAG; \
ULE_TYPES_H_FTAG; \
String str = String128f(""); \
serialize(&str, orig); \
char* buffer = str.c_str(); \
@ -206,3 +209,5 @@ extern void deserialize(char** buffer, glm::mat<4, 4, float, (glm::qualifier) 3>
#endif
#endif

9
signal-handler.h

@ -1,9 +1,10 @@
#ifndef SIGNAL_HANDLER_H
#define SIGNAL_HANDLER_H
#ifndef ULE_SIGNAL_HANDLER_H
#define ULE_SIGNAL_HANDLER_H
#include <signal.h> // for signal() and the SIG macros
#include "config.h"
#include "types.h"
#include "print.h"
@ -11,7 +12,7 @@
// the running process can receive and respond to a variety of platform-dependent 'signals' during runtime from the OS.
// freebsd has something like 30 signals, windows has a subset, just 6. we'll just deal with 6.
static inline void defaultHandler(s32 signal) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
switch (signal) {
case SIGSEGV:
case SIGABRT:
@ -37,7 +38,7 @@ static inline void defaultHandler(s32 signal) {
}
static void setSignalHandlers(void(*handler)(s32 signal) = defaultHandler) {
TYPES_H_FTAG;
ULE_TYPES_H_FTAG;
if (signal(SIGSEGV, handler) == SIG_ERR) die("failed to set SIGSEGV handler... zzz...\n");
if (signal(SIGABRT, handler) == SIG_ERR) die("failed to set SIGABRT handler... zzz...\n");
if (signal(SIGFPE, handler) == SIG_ERR) die("failed to set SIGFPE handler... zzz...\n");

710
sse_mathfun.h

@ -0,0 +1,710 @@
/* SIMD (SSE1+MMX or SSE2) implementation of sin, cos, exp and log
Inspired by Intel Approximate Math library, and based on the
corresponding algorithms of the cephes math library
The default is to use the SSE1 version. If you define USE_SSE2 the
the SSE2 intrinsics will be used in place of the MMX intrinsics. Do
not expect any significant performance improvement with SSE2.
*/
/* Copyright (C) 2007 Julien Pommier
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
(this is the zlib license)
*/
#include <xmmintrin.h>
/* yes I know, the top of this file is quite ugly */
#ifdef _MSC_VER /* visual c++ */
# define ALIGN16_BEG __declspec(align(16))
# define ALIGN16_END
#else /* gcc or icc */
# define ALIGN16_BEG
# define ALIGN16_END __attribute__((aligned(16)))
#endif
/* __m128 is ugly to write */
typedef __m128 v4sf; // vector of 4 float (sse1)
#ifdef USE_SSE2
# include <emmintrin.h>
typedef __m128i v4si; // vector of 4 int (sse2)
#else
typedef __m64 v2si; // vector of 2 int (mmx)
#endif
/* declare some SSE constants -- why can't I figure a better way to do that? */
#define _PS_CONST(Name, Val) \
static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
#define _PI32_CONST(Name, Val) \
static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
#define _PS_CONST_TYPE(Name, Type, Val) \
static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
_PS_CONST(1 , 1.0f);
_PS_CONST(0p5, 0.5f);
/* the smallest non denormalized float number */
_PS_CONST_TYPE(min_norm_pos, int, 0x00800000);
_PS_CONST_TYPE(mant_mask, int, 0x7f800000);
_PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000);
_PS_CONST_TYPE(sign_mask, int, (int)0x80000000);
_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000);
_PI32_CONST(1, 1);
_PI32_CONST(inv1, ~1);
_PI32_CONST(2, 2);
_PI32_CONST(4, 4);
_PI32_CONST(0x7f, 0x7f);
_PS_CONST(cephes_SQRTHF, 0.707106781186547524);
_PS_CONST(cephes_log_p0, 7.0376836292E-2);
_PS_CONST(cephes_log_p1, - 1.1514610310E-1);
_PS_CONST(cephes_log_p2, 1.1676998740E-1);
_PS_CONST(cephes_log_p3, - 1.2420140846E-1);
_PS_CONST(cephes_log_p4, + 1.4249322787E-1);
_PS_CONST(cephes_log_p5, - 1.6668057665E-1);
_PS_CONST(cephes_log_p6, + 2.0000714765E-1);
_PS_CONST(cephes_log_p7, - 2.4999993993E-1);
_PS_CONST(cephes_log_p8, + 3.3333331174E-1);
_PS_CONST(cephes_log_q1, -2.12194440e-4);
_PS_CONST(cephes_log_q2, 0.693359375);
#ifndef USE_SSE2
typedef union xmm_mm_union {
__m128 xmm;
__m64 mm[2];
} xmm_mm_union;
#define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \
xmm_mm_union u; u.xmm = xmm_; \
mm0_ = u.mm[0]; \
mm1_ = u.mm[1]; \
}
#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \
xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \
}
#endif // USE_SSE2
/* natural logarithm computed for 4 simultaneous float
return NaN for x <= 0
*/
v4sf log_ps(v4sf x) {
#ifdef USE_SSE2
v4si emm0;
#else
v2si mm0, mm1;
#endif
v4sf one = *(v4sf*)_ps_1;
v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps());
x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */
#ifndef USE_SSE2
/* part 1: x = frexpf(x, &e); */
COPY_XMM_TO_MM(x, mm0, mm1);
mm0 = _mm_srli_pi32(mm0, 23);
mm1 = _mm_srli_pi32(mm1, 23);
#else
emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23);
#endif
/* keep only the fractional part */
x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask);
x = _mm_or_ps(x, *(v4sf*)_ps_0p5);
#ifndef USE_SSE2
/* now e=mm0:mm1 contain the really base-2 exponent */
mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f);
mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f);
v4sf e = _mm_cvtpi32x2_ps(mm0, mm1);
_mm_empty(); /* bye bye mmx */
#else
emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f);