summaryrefslogtreecommitdiff
path: root/thirdparty/thekla_atlas/nvcore
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/thekla_atlas/nvcore')
-rw-r--r--thirdparty/thekla_atlas/nvcore/Array.h182
-rw-r--r--thirdparty/thekla_atlas/nvcore/Array.inl452
-rw-r--r--thirdparty/thekla_atlas/nvcore/BitArray.h250
-rw-r--r--thirdparty/thekla_atlas/nvcore/Debug.cpp1347
-rw-r--r--thirdparty/thekla_atlas/nvcore/Debug.h246
-rw-r--r--thirdparty/thekla_atlas/nvcore/DefsGnucDarwin.h57
-rw-r--r--thirdparty/thekla_atlas/nvcore/DefsGnucLinux.h59
-rw-r--r--thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h65
-rw-r--r--thirdparty/thekla_atlas/nvcore/DefsVcWin32.h94
-rw-r--r--thirdparty/thekla_atlas/nvcore/FileSystem.cpp75
-rw-r--r--thirdparty/thekla_atlas/nvcore/FileSystem.h24
-rw-r--r--thirdparty/thekla_atlas/nvcore/ForEach.h71
-rw-r--r--thirdparty/thekla_atlas/nvcore/Hash.h83
-rw-r--r--thirdparty/thekla_atlas/nvcore/HashMap.h174
-rw-r--r--thirdparty/thekla_atlas/nvcore/HashMap.inl550
-rw-r--r--thirdparty/thekla_atlas/nvcore/Memory.cpp153
-rw-r--r--thirdparty/thekla_atlas/nvcore/Memory.h72
-rw-r--r--thirdparty/thekla_atlas/nvcore/Ptr.h322
-rw-r--r--thirdparty/thekla_atlas/nvcore/RadixSort.cpp285
-rw-r--r--thirdparty/thekla_atlas/nvcore/RadixSort.h75
-rw-r--r--thirdparty/thekla_atlas/nvcore/RefCounted.h149
-rw-r--r--thirdparty/thekla_atlas/nvcore/StdStream.h474
-rw-r--r--thirdparty/thekla_atlas/nvcore/StrLib.cpp796
-rw-r--r--thirdparty/thekla_atlas/nvcore/StrLib.h433
-rw-r--r--thirdparty/thekla_atlas/nvcore/Stream.h164
-rw-r--r--thirdparty/thekla_atlas/nvcore/Utils.h315
-rw-r--r--thirdparty/thekla_atlas/nvcore/nvcore.h357
-rw-r--r--thirdparty/thekla_atlas/nvcore/scanf.c641
28 files changed, 7965 insertions, 0 deletions
diff --git a/thirdparty/thekla_atlas/nvcore/Array.h b/thirdparty/thekla_atlas/nvcore/Array.h
new file mode 100644
index 0000000000..b295cb2b0c
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Array.h
@@ -0,0 +1,182 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_ARRAY_H
+#define NV_CORE_ARRAY_H
+
+/*
+This array class requires the elements to be relocable; it uses memmove and realloc. Ideally I should be
+using swap, but I honestly don't care. The only thing that you should be aware of is that internal pointers
+are not supported.
+
+Note also that push_back and resize does not support inserting arguments elements that are in the same
+container. This is forbidden to prevent an extra copy.
+*/
+
+
+#include "Memory.h"
+#include "Debug.h"
+#include "ForEach.h" // PseudoIndex
+
+
+namespace nv
+{
+ class Stream;
+
+ /**
+ * Replacement for std::vector that is easier to debug and provides
+ * some nice foreach enumerators.
+ */
+ template<typename T>
+ class NVCORE_CLASS Array {
+ public:
+ typedef uint size_type;
+
+ // Default constructor.
+ NV_FORCEINLINE Array() : m_buffer(NULL), m_capacity(0), m_size(0) {}
+
+ // Copy constructor.
+ NV_FORCEINLINE Array(const Array & a) : m_buffer(NULL), m_capacity(0), m_size(0) {
+ copy(a.m_buffer, a.m_size);
+ }
+
+ // Constructor that initializes the vector with the given elements.
+ NV_FORCEINLINE Array(const T * ptr, uint num) : m_buffer(NULL), m_capacity(0), m_size(0) {
+ copy(ptr, num);
+ }
+
+ // Allocate array.
+ NV_FORCEINLINE explicit Array(uint capacity) : m_buffer(NULL), m_capacity(0), m_size(0) {
+ setArrayCapacity(capacity);
+ }
+
+ // Destructor.
+ NV_FORCEINLINE ~Array() {
+ clear();
+ free<T>(m_buffer);
+ }
+
+
+ /// Const element access.
+ NV_FORCEINLINE const T & operator[]( uint index ) const
+ {
+ nvDebugCheck(index < m_size);
+ return m_buffer[index];
+ }
+ NV_FORCEINLINE const T & at( uint index ) const
+ {
+ nvDebugCheck(index < m_size);
+ return m_buffer[index];
+ }
+
+ /// Element access.
+ NV_FORCEINLINE T & operator[] ( uint index )
+ {
+ nvDebugCheck(index < m_size);
+ return m_buffer[index];
+ }
+ NV_FORCEINLINE T & at( uint index )
+ {
+ nvDebugCheck(index < m_size);
+ return m_buffer[index];
+ }
+
+ /// Get vector size.
+ NV_FORCEINLINE uint size() const { return m_size; }
+
+ /// Get vector size.
+ NV_FORCEINLINE uint count() const { return m_size; }
+
+ /// Get vector capacity.
+ NV_FORCEINLINE uint capacity() const { return m_capacity; }
+
+ /// Get const vector pointer.
+ NV_FORCEINLINE const T * buffer() const { return m_buffer; }
+
+ /// Get vector pointer.
+ NV_FORCEINLINE T * buffer() { return m_buffer; }
+
+ /// Provide begin/end pointers for C++11 range-based for loops.
+ NV_FORCEINLINE T * begin() { return m_buffer; }
+ NV_FORCEINLINE T * end() { return m_buffer + m_size; }
+ NV_FORCEINLINE const T * begin() const { return m_buffer; }
+ NV_FORCEINLINE const T * end() const { return m_buffer + m_size; }
+
+ /// Is vector empty.
+ NV_FORCEINLINE bool isEmpty() const { return m_size == 0; }
+
+ /// Is a null vector.
+ NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; }
+
+
+ T & append();
+ void push_back( const T & val );
+ void pushBack( const T & val );
+ Array<T> & append( const T & val );
+ Array<T> & operator<< ( T & t );
+ void pop_back();
+ void popBack(uint count = 1);
+ void popFront(uint count = 1);
+ const T & back() const;
+ T & back();
+ const T & front() const;
+ T & front();
+ bool contains(const T & e) const;
+ bool find(const T & element, uint * indexPtr) const;
+ bool find(const T & element, uint begin, uint end, uint * indexPtr) const;
+ void removeAt(uint index);
+ bool remove(const T & element);
+ void insertAt(uint index, const T & val = T());
+ void append(const Array<T> & other);
+ void append(const T other[], uint count);
+ void replaceWithLast(uint index);
+ void resize(uint new_size);
+ void resize(uint new_size, const T & elem);
+ void fill(const T & elem);
+ void clear();
+ void shrink();
+ void reserve(uint desired_size);
+ void copy(const T * data, uint count);
+ Array<T> & operator=( const Array<T> & a );
+ T * release();
+
+
+ // Array enumerator.
+ typedef uint PseudoIndex;
+
+ NV_FORCEINLINE PseudoIndex start() const { return 0; }
+ NV_FORCEINLINE bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); return i == this->m_size; }
+ NV_FORCEINLINE void advance(PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); i++; }
+
+#if NV_NEED_PSEUDOINDEX_WRAPPER
+ NV_FORCEINLINE T & operator[]( const PseudoIndexWrapper & i ) {
+ return m_buffer[i(this)];
+ }
+ NV_FORCEINLINE const T & operator[]( const PseudoIndexWrapper & i ) const {
+ return m_buffer[i(this)];
+ }
+#endif
+
+ // Friends.
+ template <typename Typ>
+ friend Stream & operator<< ( Stream & s, Array<Typ> & p );
+
+ template <typename Typ>
+ friend void swap(Array<Typ> & a, Array<Typ> & b);
+
+
+ protected:
+
+ void setArraySize(uint new_size);
+ void setArrayCapacity(uint new_capacity);
+
+ T * m_buffer;
+ uint m_capacity;
+ uint m_size;
+
+ };
+
+
+} // nv namespace
+
+#endif // NV_CORE_ARRAY_H
diff --git a/thirdparty/thekla_atlas/nvcore/Array.inl b/thirdparty/thekla_atlas/nvcore/Array.inl
new file mode 100644
index 0000000000..0b4de28ba9
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Array.inl
@@ -0,0 +1,452 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_ARRAY_INL
+#define NV_CORE_ARRAY_INL
+
+#include "Array.h"
+
+#include "Stream.h"
+#include "Utils.h" // swap
+
+#include <string.h> // memmove
+#include <new> // for placement new
+
+
+
+namespace nv
+{
+ template <typename T>
+ NV_FORCEINLINE T & Array<T>::append()
+ {
+ uint old_size = m_size;
+ uint new_size = m_size + 1;
+
+ setArraySize(new_size);
+
+ construct_range(m_buffer, new_size, old_size);
+
+ return m_buffer[old_size]; // Return reference to last element.
+ }
+
+ // Push an element at the end of the vector.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::push_back( const T & val )
+ {
+#if 1
+ nvDebugCheck(&val < m_buffer || &val >= m_buffer+m_size);
+
+ uint old_size = m_size;
+ uint new_size = m_size + 1;
+
+ setArraySize(new_size);
+
+ construct_range(m_buffer, new_size, old_size, val);
+#else
+ uint new_size = m_size + 1;
+
+ if (new_size > m_capacity)
+ {
+ // @@ Is there any way to avoid this copy?
+ // @@ Can we create a copy without side effects? Ie. without calls to constructor/destructor. Use alloca + memcpy?
+ // @@ Assert instead of copy?
+ const T copy(val); // create a copy in case value is inside of this array.
+
+ setArraySize(new_size);
+
+ new (m_buffer+new_size-1) T(copy);
+ }
+ else
+ {
+ m_size = new_size;
+ new(m_buffer+new_size-1) T(val);
+ }
+#endif // 0/1
+ }
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::pushBack( const T & val )
+ {
+ push_back(val);
+ }
+ template <typename T>
+ NV_FORCEINLINE Array<T> & Array<T>::append( const T & val )
+ {
+ push_back(val);
+ return *this;
+ }
+
+ // Qt like push operator.
+ template <typename T>
+ NV_FORCEINLINE Array<T> & Array<T>::operator<< ( T & t )
+ {
+ push_back(t);
+ return *this;
+ }
+
+ // Pop the element at the end of the vector.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::pop_back()
+ {
+ nvDebugCheck( m_size > 0 );
+ resize( m_size - 1 );
+ }
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::popBack(uint count)
+ {
+ nvDebugCheck(m_size >= count);
+ resize(m_size - count);
+ }
+
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::popFront(uint count)
+ {
+ nvDebugCheck(m_size >= count);
+ //resize(m_size - count);
+
+ if (m_size == count) {
+ clear();
+ }
+ else {
+ destroy_range(m_buffer, 0, count);
+
+ memmove(m_buffer, m_buffer + count, sizeof(T) * (m_size - count));
+
+ m_size -= count;
+ }
+
+ }
+
+
+ // Get back element.
+ template <typename T>
+ NV_FORCEINLINE const T & Array<T>::back() const
+ {
+ nvDebugCheck( m_size > 0 );
+ return m_buffer[m_size-1];
+ }
+
+ // Get back element.
+ template <typename T>
+ NV_FORCEINLINE T & Array<T>::back()
+ {
+ nvDebugCheck( m_size > 0 );
+ return m_buffer[m_size-1];
+ }
+
+ // Get front element.
+ template <typename T>
+ NV_FORCEINLINE const T & Array<T>::front() const
+ {
+ nvDebugCheck( m_size > 0 );
+ return m_buffer[0];
+ }
+
+ // Get front element.
+ template <typename T>
+ NV_FORCEINLINE T & Array<T>::front()
+ {
+ nvDebugCheck( m_size > 0 );
+ return m_buffer[0];
+ }
+
+ // Check if the given element is contained in the array.
+ template <typename T>
+ NV_FORCEINLINE bool Array<T>::contains(const T & e) const
+ {
+ return find(e, NULL);
+ }
+
+ // Return true if element found.
+ template <typename T>
+ NV_FORCEINLINE bool Array<T>::find(const T & element, uint * indexPtr) const
+ {
+ return find(element, 0, m_size, indexPtr);
+ }
+
+ // Return true if element found within the given range.
+ template <typename T>
+ NV_FORCEINLINE bool Array<T>::find(const T & element, uint begin, uint end, uint * indexPtr) const
+ {
+ return ::nv::find(element, m_buffer, begin, end, indexPtr);
+ }
+
+
+ // Remove the element at the given index. This is an expensive operation!
+ template <typename T>
+ void Array<T>::removeAt(uint index)
+ {
+ nvDebugCheck(index >= 0 && index < m_size);
+
+ if (m_size == 1) {
+ clear();
+ }
+ else {
+ m_buffer[index].~T();
+
+ memmove(m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index));
+ m_size--;
+ }
+ }
+
+ // Remove the first instance of the given element.
+ template <typename T>
+ bool Array<T>::remove(const T & element)
+ {
+ uint index;
+ if (find(element, &index)) {
+ removeAt(index);
+ return true;
+ }
+ return false;
+ }
+
+ // Insert the given element at the given index shifting all the elements up.
+ template <typename T>
+ void Array<T>::insertAt(uint index, const T & val/*=T()*/)
+ {
+ nvDebugCheck( index >= 0 && index <= m_size );
+
+ setArraySize(m_size + 1);
+
+ if (index < m_size - 1) {
+ memmove(m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index));
+ }
+
+ // Copy-construct into the newly opened slot.
+ new(m_buffer+index) T(val);
+ }
+
+ // Append the given data to our vector.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::append(const Array<T> & other)
+ {
+ append(other.m_buffer, other.m_size);
+ }
+
+ // Append the given data to our vector.
+ template <typename T>
+ void Array<T>::append(const T other[], uint count)
+ {
+ if (count > 0) {
+ const uint old_size = m_size;
+
+ setArraySize(m_size + count);
+
+ for (uint i = 0; i < count; i++ ) {
+ new(m_buffer + old_size + i) T(other[i]);
+ }
+ }
+ }
+
+
+ // Remove the given element by replacing it with the last one.
+ template <typename T>
+ void Array<T>::replaceWithLast(uint index)
+ {
+ nvDebugCheck( index < m_size );
+ nv::swap(m_buffer[index], back()); // @@ Is this OK when index == size-1?
+ (m_buffer+m_size-1)->~T();
+ m_size--;
+ }
+
+ // Resize the vector preserving existing elements.
+ template <typename T>
+ void Array<T>::resize(uint new_size)
+ {
+ uint old_size = m_size;
+
+ // Destruct old elements (if we're shrinking).
+ destroy_range(m_buffer, new_size, old_size);
+
+ setArraySize(new_size);
+
+ // Call default constructors
+ construct_range(m_buffer, new_size, old_size);
+ }
+
+
+ // Resize the vector preserving existing elements and initializing the
+ // new ones with the given value.
+ template <typename T>
+ void Array<T>::resize(uint new_size, const T & elem)
+ {
+ nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size);
+
+ uint old_size = m_size;
+
+ // Destruct old elements (if we're shrinking).
+ destroy_range(m_buffer, new_size, old_size);
+
+ setArraySize(new_size);
+
+ // Call copy constructors
+ construct_range(m_buffer, new_size, old_size, elem);
+ }
+
+ // Fill array with the given value.
+ template <typename T>
+ void Array<T>::fill(const T & elem)
+ {
+ fill(m_buffer, m_size, elem);
+ }
+
+ // Clear the buffer.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::clear()
+ {
+ nvDebugCheck(isValidPtr(m_buffer));
+
+ // Destruct old elements
+ destroy_range(m_buffer, 0, m_size);
+
+ m_size = 0;
+ }
+
+ // Shrink the allocated vector.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::shrink()
+ {
+ if (m_size < m_capacity) {
+ setArrayCapacity(m_size);
+ }
+ }
+
+ // Preallocate space.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::reserve(uint desired_size)
+ {
+ if (desired_size > m_capacity) {
+ setArrayCapacity(desired_size);
+ }
+ }
+
+ // Copy elements to this array. Resizes it if needed.
+ template <typename T>
+ NV_FORCEINLINE void Array<T>::copy(const T * data, uint count)
+ {
+#if 1 // More simple, but maybe not be as efficient?
+ destroy_range(m_buffer, 0, m_size);
+
+ setArraySize(count);
+
+ construct_range(m_buffer, count, 0, data);
+#else
+ const uint old_size = m_size;
+
+ destroy_range(m_buffer, count, old_size);
+
+ setArraySize(count);
+
+ copy_range(m_buffer, data, old_size);
+
+ construct_range(m_buffer, count, old_size, data);
+#endif
+ }
+
+ // Assignment operator.
+ template <typename T>
+ NV_FORCEINLINE Array<T> & Array<T>::operator=( const Array<T> & a )
+ {
+ copy(a.m_buffer, a.m_size);
+ return *this;
+ }
+
+ // Release ownership of allocated memory and returns pointer to it.
+ template <typename T>
+ T * Array<T>::release() {
+ T * tmp = m_buffer;
+ m_buffer = NULL;
+ m_capacity = 0;
+ m_size = 0;
+ return tmp;
+ }
+
+
+
+ // Change array size.
+ template <typename T>
+ inline void Array<T>::setArraySize(uint new_size) {
+ m_size = new_size;
+
+ if (new_size > m_capacity) {
+ uint new_buffer_size;
+ if (m_capacity == 0) {
+ // first allocation is exact
+ new_buffer_size = new_size;
+ }
+ else {
+ // following allocations grow array by 25%
+ new_buffer_size = new_size + (new_size >> 2);
+ }
+
+ setArrayCapacity( new_buffer_size );
+ }
+ }
+
+ // Change array capacity.
+ template <typename T>
+ inline void Array<T>::setArrayCapacity(uint new_capacity) {
+ nvDebugCheck(new_capacity >= m_size);
+
+ if (new_capacity == 0) {
+ // free the buffer.
+ if (m_buffer != NULL) {
+ free<T>(m_buffer);
+ m_buffer = NULL;
+ }
+ }
+ else {
+ // realloc the buffer
+ m_buffer = realloc<T>(m_buffer, new_capacity);
+ }
+
+ m_capacity = new_capacity;
+ }
+
+ // Array serialization.
+ template <typename Typ>
+ inline Stream & operator<< ( Stream & s, Array<Typ> & p )
+ {
+ if (s.isLoading()) {
+ uint size;
+ s << size;
+ p.resize( size );
+ }
+ else {
+ s << p.m_size;
+ }
+
+ for (uint i = 0; i < p.m_size; i++) {
+ s << p.m_buffer[i];
+ }
+
+ return s;
+ }
+
+ // Swap the members of the two given vectors.
+ template <typename Typ>
+ inline void swap(Array<Typ> & a, Array<Typ> & b)
+ {
+ nv::swap(a.m_buffer, b.m_buffer);
+ nv::swap(a.m_capacity, b.m_capacity);
+ nv::swap(a.m_size, b.m_size);
+ }
+
+
+} // nv namespace
+
+// IC: These functions are for compatibility with the Foreach macro in The Witness.
+template <typename T> inline int item_count(const nv::Array<T> & array) { return array.count(); }
+template <typename T> inline const T & item_at(const nv::Array<T> & array, int i) { return array.at(i); }
+template <typename T> inline T & item_at(nv::Array<T> & array, int i) { return array.at(i); }
+template <typename T> inline int item_advance(const nv::Array<T> & array, int i) { return ++i; }
+template <typename T> inline int item_remove(nv::Array<T> & array, int i) { array.replaceWithLast(i); return i - 1; }
+
+template <typename T> inline int item_count(const nv::Array<T> * array) { return array->count(); }
+template <typename T> inline const T & item_at(const nv::Array<T> * array, int i) { return array->at(i); }
+template <typename T> inline T & item_at(nv::Array<T> * array, int i) { return array->at(i); }
+template <typename T> inline int item_advance(const nv::Array<T> * array, int i) { return ++i; }
+template <typename T> inline int item_remove(nv::Array<T> * array, int i) { array->replaceWithLast(i); return i - 1; }
+
+
+#endif // NV_CORE_ARRAY_INL
diff --git a/thirdparty/thekla_atlas/nvcore/BitArray.h b/thirdparty/thekla_atlas/nvcore/BitArray.h
new file mode 100644
index 0000000000..23cf880694
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/BitArray.h
@@ -0,0 +1,250 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_BITARRAY_H
+#define NV_CORE_BITARRAY_H
+
+#include "nvcore.h"
+#include "Array.inl"
+
+namespace nv
+{
+
+ // @@ Uh, this could be much faster.
+ inline uint countSetBits(uint32 x) {
+ uint count = 0;
+ for(; x != 0; x >>= 1) {
+ count += (x & 1);
+ }
+ return count;
+ }
+
+ // @@ This is even more lame. What was I thinking?
+ inline uint countSetBits(uint32 x, int bits) {
+ uint count = 0;
+ for(; x != 0 && bits != 0; x >>= 1, bits--) {
+ count += (x & 1);
+ }
+ return count;
+ }
+
+ // See "Conditionally set or clear bits without branching" at http://graphics.stanford.edu/~seander/bithacks.html
+ inline uint setBits(uint w, uint m, bool b) {
+ return (w & ~m) | (-int(b) & m);
+ }
+
+
+
+ // Simple bit array.
+ class BitArray
+ {
+ public:
+
+ BitArray() {}
+ BitArray(uint sz) {
+ resize(sz);
+ }
+
+ uint size() const { return m_size; }
+ void clear() { resize(0); }
+
+ void resize(uint new_size)
+ {
+ m_size = new_size;
+ m_wordArray.resize( (m_size + 31) >> 5 );
+ }
+
+ void resize(uint new_size, bool init)
+ {
+ //if (new_size == m_size) return;
+
+ uint old_size = m_size;
+ uint size_mod_32 = old_size & 31;
+ uint last_word_index = ((old_size + 31) >> 5) - 1;
+ uint mask = (1 << size_mod_32) - 1;
+
+ uint init_dword;
+ if (init) {
+ if (size_mod_32) m_wordArray[last_word_index] |= ~mask;
+ init_dword = ~0;
+ }
+ else {
+ if (size_mod_32) m_wordArray[last_word_index] &= mask;
+ init_dword = 0;
+ }
+
+ m_size = new_size;
+ m_wordArray.resize((new_size + 31) >> 5, init_dword);
+
+ // Make sure new bits are initialized correctly.
+ /*for (uint i = old_size; i < new_size; i++) {
+ nvCheck(bitAt(i) == init);
+ }*/
+ }
+
+
+ /// Get bit.
+ bool bitAt(uint b) const
+ {
+ nvDebugCheck( b < m_size );
+ return (m_wordArray[b >> 5] & (1 << (b & 31))) != 0;
+ }
+
+ // It may be useful to pack mulitple bit arrays together interleaving their bits.
+ uint bitsAt(uint idx, uint count) const
+ {
+ //nvDebugCheck(count == 2 || count == 4 || count == 8 || count == 16 || count == 32);
+ nvDebugCheck(count == 2); // @@ Hardcoded for two.
+ uint b = idx * count;
+ nvDebugCheck(b < m_size);
+ return (m_wordArray[b >> 5] & (0x3 << (b & 31))) >> (b & 31);
+ }
+
+ // It would be useful to have a function to set two bits simultaneously.
+ /*void setBitsAt(uint idx, uint count, uint bits) const
+ {
+ //nvDebugCheck(count == 2 || count == 4 || count == 8 || count == 16 || count == 32);
+ nvDebugCheck(count == 2); // @@ Hardcoded for two.
+ uint b = idx * count;
+ nvDebugCheck(b < m_size);
+ return (m_wordArray[b >> 5] & (0x3 << (b & 31))) >> (b & 31);
+ }*/
+
+
+
+ // Set a bit.
+ void setBitAt(uint idx)
+ {
+ nvDebugCheck(idx < m_size);
+ m_wordArray[idx >> 5] |= (1 << (idx & 31));
+ }
+
+ // Clear a bit.
+ void clearBitAt(uint idx)
+ {
+ nvDebugCheck(idx < m_size);
+ m_wordArray[idx >> 5] &= ~(1 << (idx & 31));
+ }
+
+ // Toggle a bit.
+ void toggleBitAt(uint idx)
+ {
+ nvDebugCheck(idx < m_size);
+ m_wordArray[idx >> 5] ^= (1 << (idx & 31));
+ }
+
+ // Set a bit to the given value. @@ Rename modifyBitAt?
+ void setBitAt(uint idx, bool b)
+ {
+ nvDebugCheck(idx < m_size);
+ m_wordArray[idx >> 5] = setBits(m_wordArray[idx >> 5], 1 << (idx & 31), b);
+ nvDebugCheck(bitAt(idx) == b);
+ }
+
+ void append(bool value)
+ {
+ resize(m_size + 1);
+ setBitAt(m_size - 1, value);
+ }
+
+
+ // Clear all the bits.
+ void clearAll()
+ {
+ memset(m_wordArray.buffer(), 0, m_wordArray.size() * sizeof(uint));
+ }
+
+ // Set all the bits.
+ void setAll()
+ {
+ memset(m_wordArray.buffer(), 0xFF, m_wordArray.size() * sizeof(uint));
+ }
+
+ // Toggle all the bits.
+ void toggleAll()
+ {
+ const uint wordCount = m_wordArray.count();
+ for(uint b = 0; b < wordCount; b++) {
+ m_wordArray[b] ^= 0xFFFFFFFF;
+ }
+ }
+
+ // Count the number of bits set.
+ uint countSetBits() const
+ {
+ const uint num = m_wordArray.size();
+ if( num == 0 ) {
+ return 0;
+ }
+
+ uint count = 0;
+ for(uint i = 0; i < num - 1; i++) {
+ count += nv::countSetBits(m_wordArray[i]);
+ }
+ count += nv::countSetBits(m_wordArray[num - 1], m_size & 31);
+
+ //piDebugCheck(count + countClearBits() == m_size);
+ return count;
+ }
+
+ // Count the number of bits clear.
+ uint countClearBits() const {
+
+ const uint num = m_wordArray.size();
+ if( num == 0 ) {
+ return 0;
+ }
+
+ uint count = 0;
+ for(uint i = 0; i < num - 1; i++) {
+ count += nv::countSetBits(~m_wordArray[i]);
+ }
+ count += nv::countSetBits(~m_wordArray[num - 1], m_size & 31);
+
+ //piDebugCheck(count + countSetBits() == m_size);
+ return count;
+ }
+
+ friend void swap(BitArray & a, BitArray & b)
+ {
+ swap(a.m_size, b.m_size);
+ swap(a.m_wordArray, b.m_wordArray);
+ }
+
+ void operator &= (const BitArray & other) {
+ if (other.m_size != m_size) {
+ resize(other.m_size);
+ }
+
+ const uint wordCount = m_wordArray.count();
+ for (uint i = 0; i < wordCount; i++) {
+ m_wordArray[i] &= other.m_wordArray[i];
+ }
+ }
+
+ void operator |= (const BitArray & other) {
+ if (other.m_size != m_size) {
+ resize(other.m_size);
+ }
+
+ const uint wordCount = m_wordArray.count();
+ for (uint i = 0; i < wordCount; i++) {
+ m_wordArray[i] |= other.m_wordArray[i];
+ }
+ }
+
+
+ private:
+
+ // Number of bits stored.
+ uint m_size;
+
+ // Array of bits.
+ Array<uint> m_wordArray;
+
+ };
+
+} // nv namespace
+
+#endif // NV_CORE_BITARRAY_H
+
diff --git a/thirdparty/thekla_atlas/nvcore/Debug.cpp b/thirdparty/thekla_atlas/nvcore/Debug.cpp
new file mode 100644
index 0000000000..75ac6beb75
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Debug.cpp
@@ -0,0 +1,1347 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#include "Debug.h"
+#include "Array.inl"
+#include "StrLib.h" // StringBuilder
+
+#include "StdStream.h" // fileOpen
+
+#include <stdlib.h>
+
+// Extern
+#if NV_OS_WIN32 //&& NV_CC_MSVC
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# include <windows.h>
+# include <direct.h>
+# if NV_CC_MSVC
+# include <crtdbg.h>
+# if _MSC_VER < 1300
+# define DECLSPEC_DEPRECATED
+// VC6: change this path to your Platform SDK headers
+# include <dbghelp.h> // must be XP version of file
+// include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h"
+# else
+// VC7: ships with updated headers
+# include <dbghelp.h>
+# endif
+# endif
+# pragma comment(lib,"dbghelp.lib")
+#endif
+
+#if NV_OS_XBOX
+# include <Xtl.h>
+# ifdef _DEBUG
+# include <xbdm.h>
+# endif //_DEBUG
+#endif //NV_OS_XBOX
+
+#if !NV_OS_WIN32 && defined(NV_HAVE_SIGNAL_H)
+# include <signal.h>
+#endif
+
+#if NV_OS_UNIX
+# include <unistd.h> // getpid
+#endif
+
+#if NV_OS_LINUX && defined(NV_HAVE_EXECINFO_H)
+# include <execinfo.h> // backtrace
+# if NV_CC_GNUC // defined(NV_HAVE_CXXABI_H)
+# include <cxxabi.h>
+# endif
+#endif
+
+#if NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD
+# include <sys/types.h>
+# include <sys/param.h>
+# include <sys/sysctl.h> // sysctl
+# if !defined(NV_OS_OPENBSD)
+# include <sys/ucontext.h>
+# endif
+# if defined(NV_HAVE_EXECINFO_H) // only after OSX 10.5
+# include <execinfo.h> // backtrace
+# if NV_CC_GNUC // defined(NV_HAVE_CXXABI_H)
+# include <cxxabi.h>
+# endif
+# endif
+#endif
+
+#if NV_OS_ORBIS
+#include <libdbg.h>
+#endif
+
+#if NV_OS_DURANGO
+#include "Windows.h"
+#include <winnt.h>
+#include <crtdbg.h>
+#include <dbghelp.h>
+#include <errhandlingapi.h>
+#define NV_USE_SEPARATE_THREAD 0
+#else
+#define NV_USE_SEPARATE_THREAD 1
+#endif
+
+
+
+using namespace nv;
+
+namespace
+{
+
+ static MessageHandler * s_message_handler = NULL;
+ static AssertHandler * s_assert_handler = NULL;
+
+ static bool s_sig_handler_enabled = false;
+ static bool s_interactive = true;
+
+#if (NV_OS_WIN32 && NV_CC_MSVC) || NV_OS_DURANGO
+
+ // Old exception filter.
+ static LPTOP_LEVEL_EXCEPTION_FILTER s_old_exception_filter = NULL;
+
+#elif !NV_OS_WIN32 && defined(NV_HAVE_SIGNAL_H)
+
+ // Old signal handlers.
+ struct sigaction s_old_sigsegv;
+ struct sigaction s_old_sigtrap;
+ struct sigaction s_old_sigfpe;
+ struct sigaction s_old_sigbus;
+
+#endif
+
+
+#if (NV_OS_WIN32 && NV_CC_MSVC) || NV_OS_DURANGO
+
+ // We should try to simplify the top level filter as much as possible.
+ // http://www.nynaeve.net/?p=128
+
+ // The critical section enforcing the requirement that only one exception be
+ // handled by a handler at a time.
+ static CRITICAL_SECTION s_handler_critical_section;
+
+#if NV_USE_SEPARATE_THREAD
+ // Semaphores used to move exception handling between the exception thread
+ // and the handler thread. handler_start_semaphore_ is signalled by the
+ // exception thread to wake up the handler thread when an exception occurs.
+ // handler_finish_semaphore_ is signalled by the handler thread to wake up
+ // the exception thread when handling is complete.
+ static HANDLE s_handler_start_semaphore = NULL;
+ static HANDLE s_handler_finish_semaphore = NULL;
+
+ // The exception handler thread.
+ static HANDLE s_handler_thread = NULL;
+
+ static DWORD s_requesting_thread_id = 0;
+ static EXCEPTION_POINTERS * s_exception_info = NULL;
+
+#endif // NV_USE_SEPARATE_THREAD
+
+
+ struct MinidumpCallbackContext {
+ ULONG64 memory_base;
+ ULONG memory_size;
+ bool finished;
+ };
+
+#if NV_OS_WIN32
+ // static
+ static BOOL CALLBACK miniDumpWriteDumpCallback(PVOID context, const PMINIDUMP_CALLBACK_INPUT callback_input, PMINIDUMP_CALLBACK_OUTPUT callback_output)
+ {
+ switch (callback_input->CallbackType)
+ {
+ case MemoryCallback: {
+ MinidumpCallbackContext* callback_context = reinterpret_cast<MinidumpCallbackContext*>(context);
+ if (callback_context->finished)
+ return FALSE;
+
+ // Include the specified memory region.
+ callback_output->MemoryBase = callback_context->memory_base;
+ callback_output->MemorySize = callback_context->memory_size;
+ callback_context->finished = true;
+ return TRUE;
+ }
+
+ // Include all modules.
+ case IncludeModuleCallback:
+ case ModuleCallback:
+ return TRUE;
+
+ // Include all threads.
+ case IncludeThreadCallback:
+ case ThreadCallback:
+ return TRUE;
+
+ // Stop receiving cancel callbacks.
+ case CancelCallback:
+ callback_output->CheckCancel = FALSE;
+ callback_output->Cancel = FALSE;
+ return TRUE;
+ }
+
+ // Ignore other callback types.
+ return FALSE;
+ }
+#endif
+
+ static bool writeMiniDump(EXCEPTION_POINTERS * pExceptionInfo)
+ {
+#if NV_OS_DURANGO
+ // Get a handle to the minidump method.
+ typedef BOOL(WINAPI* MiniDumpWriteDumpPfn) (
+ _In_ HANDLE hProcess,
+ _In_ DWORD ProcessId,
+ _In_ HANDLE hFile,
+ _In_ MINIDUMP_TYPE DumpType,
+ _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ _Reserved_ PVOID CallbackParam
+ );
+ MiniDumpWriteDumpPfn MiniDumpWriteDump = NULL;
+ HMODULE hToolHelpModule = ::LoadLibraryW(L"toolhelpx.dll");
+ if (hToolHelpModule != INVALID_HANDLE_VALUE) {
+ MiniDumpWriteDump = reinterpret_cast<MiniDumpWriteDumpPfn>(::GetProcAddress(hToolHelpModule, "MiniDumpWriteDump"));
+ if (!MiniDumpWriteDump) {
+ FreeLibrary(hToolHelpModule);
+ return false;
+ }
+ }
+ else
+ return false;
+
+ // Generate a decent filename.
+ nv::Path application_path(256);
+ HINSTANCE hinstance = GetModuleHandle(NULL);
+ GetModuleFileName(hinstance, application_path.str(), 256);
+ application_path.stripExtension();
+ const char * application_name = application_path.fileName();
+
+ SYSTEMTIME local_time;
+ GetLocalTime(&local_time);
+
+ char dump_filename[MAX_PATH] = {};
+ sprintf_s(dump_filename, "d:\\%s-%04d%02d%02d-%02d%02d%02d.dmp",
+ application_name,
+ local_time.wYear, local_time.wMonth, local_time.wDay,
+ local_time.wHour, local_time.wMinute, local_time.wSecond );
+#else
+ const char* dump_filename = "crash.dmp";
+#endif
+
+ // create the file
+ HANDLE hFile = CreateFileA(dump_filename, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ //nvDebug("*** Failed to create dump file.\n");
+#if NV_OS_DURANGO
+ FreeLibrary(hToolHelpModule);
+#endif
+ return false;
+ }
+
+ MINIDUMP_EXCEPTION_INFORMATION * pExInfo = NULL;
+#if NV_OS_WIN32
+ MINIDUMP_CALLBACK_INFORMATION * pCallback = NULL;
+#else
+ void * pCallback = NULL;
+#endif
+
+ MINIDUMP_EXCEPTION_INFORMATION ExInfo;
+ if (pExceptionInfo != NULL) {
+ ExInfo.ThreadId = ::GetCurrentThreadId();
+ ExInfo.ExceptionPointers = pExceptionInfo;
+ ExInfo.ClientPointers = NULL;
+ pExInfo = &ExInfo;
+
+#if NV_OS_WIN32
+ MINIDUMP_CALLBACK_INFORMATION callback;
+ MinidumpCallbackContext context;
+
+ // Find a memory region of 256 bytes centered on the
+ // faulting instruction pointer.
+ const ULONG64 instruction_pointer =
+ #if defined(_M_IX86)
+ pExceptionInfo->ContextRecord->Eip;
+ #elif defined(_M_AMD64)
+ pExceptionInfo->ContextRecord->Rip;
+ #else
+ #error Unsupported platform
+ #endif
+
+ MEMORY_BASIC_INFORMATION info;
+
+ if (VirtualQuery(reinterpret_cast<LPCVOID>(instruction_pointer), &info, sizeof(MEMORY_BASIC_INFORMATION)) != 0 && info.State == MEM_COMMIT)
+ {
+ // Attempt to get 128 bytes before and after the instruction
+ // pointer, but settle for whatever's available up to the
+ // boundaries of the memory region.
+ const ULONG64 kIPMemorySize = 256;
+ context.memory_base = max(reinterpret_cast<ULONG64>(info.BaseAddress), instruction_pointer - (kIPMemorySize / 2));
+ ULONG64 end_of_range = min(instruction_pointer + (kIPMemorySize / 2), reinterpret_cast<ULONG64>(info.BaseAddress) + info.RegionSize);
+ context.memory_size = static_cast<ULONG>(end_of_range - context.memory_base);
+ context.finished = false;
+
+ callback.CallbackRoutine = miniDumpWriteDumpCallback;
+ callback.CallbackParam = reinterpret_cast<void*>(&context);
+ pCallback = &callback;
+ }
+#endif
+ }
+
+ MINIDUMP_TYPE miniDumpType = (MINIDUMP_TYPE)(MiniDumpNormal|MiniDumpWithHandleData|MiniDumpWithThreadInfo);
+
+ // write the dump
+ BOOL ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, miniDumpType, pExInfo, NULL, pCallback) != 0;
+ CloseHandle(hFile);
+#if NV_OS_DURANGO
+ FreeLibrary(hToolHelpModule);
+#endif
+
+ if (ok == FALSE) {
+ //nvDebug("*** Failed to save dump file.\n");
+ return false;
+ }
+
+ //nvDebug("\nDump file saved.\n");
+
+ return true;
+ }
+
+#if NV_USE_SEPARATE_THREAD
+
+ static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter) {
+ nvDebugCheck(s_handler_start_semaphore != NULL);
+ nvDebugCheck(s_handler_finish_semaphore != NULL);
+
+ while (true) {
+ if (WaitForSingleObject(s_handler_start_semaphore, INFINITE) == WAIT_OBJECT_0) {
+ writeMiniDump(s_exception_info);
+
+ // Allow the requesting thread to proceed.
+ ReleaseSemaphore(s_handler_finish_semaphore, 1, NULL);
+ }
+ }
+
+ // This statement is not reached when the thread is unconditionally
+ // terminated by the ExceptionHandler destructor.
+ return 0;
+ }
+
+#endif // NV_USE_SEPARATE_THREAD
+
+ static bool hasStackTrace() {
+ return true;
+ }
+
+ /*static NV_NOINLINE int backtrace(void * trace[], int maxcount) {
+
+ // In Windows XP and Windows Server 2003, the sum of the FramesToSkip and FramesToCapture parameters must be less than 63.
+ int xp_maxcount = min(63-1, maxcount);
+
+ int count = RtlCaptureStackBackTrace(1, xp_maxcount, trace, NULL);
+ nvDebugCheck(count <= maxcount);
+
+ return count;
+ }*/
+
+#if NV_OS_WIN32
+ static NV_NOINLINE int backtraceWithSymbols(CONTEXT * ctx, void * trace[], int maxcount, int skip = 0) {
+
+ // Init the stack frame for this function
+ STACKFRAME64 stackFrame = { 0 };
+
+ #if NV_CPU_X86_64
+ DWORD dwMachineType = IMAGE_FILE_MACHINE_AMD64;
+ stackFrame.AddrPC.Offset = ctx->Rip;
+ stackFrame.AddrFrame.Offset = ctx->Rbp;
+ stackFrame.AddrStack.Offset = ctx->Rsp;
+ #elif NV_CPU_X86
+ DWORD dwMachineType = IMAGE_FILE_MACHINE_I386;
+ stackFrame.AddrPC.Offset = ctx->Eip;
+ stackFrame.AddrFrame.Offset = ctx->Ebp;
+ stackFrame.AddrStack.Offset = ctx->Esp;
+ #else
+ #error "Platform not supported!"
+ #endif
+ stackFrame.AddrPC.Mode = AddrModeFlat;
+ stackFrame.AddrFrame.Mode = AddrModeFlat;
+ stackFrame.AddrStack.Mode = AddrModeFlat;
+
+ // Walk up the stack
+ const HANDLE hThread = GetCurrentThread();
+ const HANDLE hProcess = GetCurrentProcess();
+ int i;
+ for (i = 0; i < maxcount; i++)
+ {
+ // walking once first makes us skip self
+ if (!StackWalk64(dwMachineType, hProcess, hThread, &stackFrame, ctx, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL)) {
+ break;
+ }
+
+ /*if (stackFrame.AddrPC.Offset == stackFrame.AddrReturn.Offset || stackFrame.AddrPC.Offset == 0) {
+ break;
+ }*/
+
+ if (i >= skip) {
+ trace[i - skip] = (PVOID)stackFrame.AddrPC.Offset;
+ }
+ }
+
+ return i - skip;
+ }
+
+#pragma warning(push)
+#pragma warning(disable:4748)
+ static NV_NOINLINE int backtrace(void * trace[], int maxcount) {
+ CONTEXT ctx = { 0 };
+#if NV_CPU_X86 && !NV_CPU_X86_64
+ ctx.ContextFlags = CONTEXT_CONTROL;
+ _asm {
+ call x
+ x: pop eax
+ mov ctx.Eip, eax
+ mov ctx.Ebp, ebp
+ mov ctx.Esp, esp
+ }
+#else
+ RtlCaptureContext(&ctx); // Not implemented correctly in x86.
+#endif
+
+ return backtraceWithSymbols(&ctx, trace, maxcount, 1);
+ }
+#pragma warning(pop)
+
+ static NV_NOINLINE void writeStackTrace(void * trace[], int size, int start, Array<const char *> & lines)
+ {
+ StringBuilder builder(512);
+
+ HANDLE hProcess = GetCurrentProcess();
+
+ // Resolve PC to function names
+ for (int i = start; i < size; i++)
+ {
+ // Check for end of stack walk
+ DWORD64 ip = (DWORD64)trace[i];
+ if (ip == NULL)
+ break;
+
+ // Get function name
+ #define MAX_STRING_LEN (512)
+ unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_STRING_LEN] = { 0 };
+ IMAGEHLP_SYMBOL64 * pSymbol = (IMAGEHLP_SYMBOL64*)byBuffer;
+ pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+ pSymbol->MaxNameLength = MAX_STRING_LEN;
+
+ DWORD64 dwDisplacement;
+
+ if (SymGetSymFromAddr64(hProcess, ip, &dwDisplacement, pSymbol))
+ {
+ pSymbol->Name[MAX_STRING_LEN-1] = 0;
+
+ /*
+ // Make the symbol readable for humans
+ UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
+ UNDNAME_COMPLETE |
+ UNDNAME_NO_THISTYPE |
+ UNDNAME_NO_SPECIAL_SYMS |
+ UNDNAME_NO_MEMBER_TYPE |
+ UNDNAME_NO_MS_KEYWORDS |
+ UNDNAME_NO_ACCESS_SPECIFIERS );
+ */
+
+ // pSymbol->Name
+ const char * pFunc = pSymbol->Name;
+
+ // Get file/line number
+ IMAGEHLP_LINE64 theLine = { 0 };
+ theLine.SizeOfStruct = sizeof(theLine);
+
+ DWORD dwDisplacement;
+ if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement, &theLine))
+ {
+ // Do not print unknown symbols anymore.
+ //break;
+ builder.format("unknown(%08X) : %s\n", (uint32)ip, pFunc);
+ }
+ else
+ {
+ /*
+ const char* pFile = strrchr(theLine.FileName, '\\');
+ if ( pFile == NULL ) pFile = theLine.FileName;
+ else pFile++;
+ */
+ const char * pFile = theLine.FileName;
+
+ int line = theLine.LineNumber;
+
+ builder.format("%s(%d) : %s\n", pFile, line, pFunc);
+ }
+
+ lines.append(builder.release());
+
+ if (pFunc != NULL && strcmp(pFunc, "WinMain") == 0) {
+ break;
+ }
+ }
+ }
+ }
+#endif
+
+ // Write mini dump and print stack trace.
+ static LONG WINAPI handleException(EXCEPTION_POINTERS * pExceptionInfo)
+ {
+ EnterCriticalSection(&s_handler_critical_section);
+#if NV_USE_SEPARATE_THREAD
+ s_requesting_thread_id = GetCurrentThreadId();
+ s_exception_info = pExceptionInfo;
+
+ // This causes the handler thread to call writeMiniDump.
+ ReleaseSemaphore(s_handler_start_semaphore, 1, NULL);
+
+ // Wait until WriteMinidumpWithException is done and collect its return value.
+ WaitForSingleObject(s_handler_finish_semaphore, INFINITE);
+ //bool status = s_handler_return_value;
+
+ // Clean up.
+ s_requesting_thread_id = 0;
+ s_exception_info = NULL;
+#else
+ // First of all, write mini dump.
+ writeMiniDump(pExceptionInfo);
+#endif
+ LeaveCriticalSection(&s_handler_critical_section);
+
+ nvDebug("\nDump file saved.\n");
+
+ // Try to attach to debugger.
+ if (s_interactive && debug::attachToDebugger()) {
+ nvDebugBreak();
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+#if NV_OS_WIN32
+ // If that fails, then try to pretty print a stack trace and terminate.
+ void * trace[64];
+
+ int size = backtraceWithSymbols(pExceptionInfo->ContextRecord, trace, 64);
+
+ // @@ Use win32's CreateFile?
+ FILE * fp = fileOpen("crash.txt", "wb");
+ if (fp != NULL) {
+ Array<const char *> lines;
+ writeStackTrace(trace, size, 0, lines);
+
+ for (uint i = 0; i < lines.count(); i++) {
+ fputs(lines[i], fp);
+ delete lines[i];
+ }
+
+ // @@ Add more info to crash.txt?
+
+ fclose(fp);
+ }
+#endif
+
+ // This should terminate the process and set the error exit code.
+ TerminateProcess(GetCurrentProcess(), EXIT_FAILURE + 2);
+
+ return EXCEPTION_EXECUTE_HANDLER; // Terminate app. In case terminate process did not succeed.
+ }
+
+ static void handlePureVirtualCall() {
+ nvDebugBreak();
+ TerminateProcess(GetCurrentProcess(), EXIT_FAILURE + 8);
+ }
+
+ static void handleInvalidParameter(const wchar_t * wexpresion, const wchar_t * wfunction, const wchar_t * wfile, unsigned int line, uintptr_t reserved) {
+
+ size_t convertedCharCount = 0;
+
+ StringBuilder expresion;
+ if (wexpresion != NULL) {
+ uint size = U32(wcslen(wexpresion) + 1);
+ expresion.reserve(size);
+ wcstombs_s(&convertedCharCount, expresion.str(), size, wexpresion, _TRUNCATE);
+ }
+
+ StringBuilder file;
+ if (wfile != NULL) {
+ uint size = U32(wcslen(wfile) + 1);
+ file.reserve(size);
+ wcstombs_s(&convertedCharCount, file.str(), size, wfile, _TRUNCATE);
+ }
+
+ StringBuilder function;
+ if (wfunction != NULL) {
+ uint size = U32(wcslen(wfunction) + 1);
+ function.reserve(size);
+ wcstombs_s(&convertedCharCount, function.str(), size, wfunction, _TRUNCATE);
+ }
+
+ int result = nvAbort(expresion.str(), file.str(), line, function.str());
+ if (result == NV_ABORT_DEBUG) {
+ nvDebugBreak();
+ }
+ }
+
+#elif !NV_OS_WIN32 && defined(NV_HAVE_SIGNAL_H) // NV_OS_LINUX || NV_OS_DARWIN
+
+#if defined(NV_HAVE_EXECINFO_H)
+
+ static bool hasStackTrace() {
+ return true;
+ }
+
+
+ static void writeStackTrace(void * trace[], int size, int start, Array<const char *> & lines) {
+ StringBuilder builder(512);
+ char ** string_array = backtrace_symbols(trace, size);
+
+ for(int i = start; i < size-1; i++ ) {
+ // IC: Just in case.
+ if (string_array[i] == NULL || string_array[i][0] == '\0') break;
+
+# if NV_CC_GNUC // defined(NV_HAVE_CXXABI_H)
+ // @@ Write a better parser for the possible formats.
+ char * begin = strchr(string_array[i], '(');
+ char * end = strrchr(string_array[i], '+');
+ char * module = string_array[i];
+
+ if (begin == 0 && end != 0) {
+ *(end - 1) = '\0';
+ begin = strrchr(string_array[i], ' ');
+ module = NULL; // Ignore module.
+ }
+
+ if (begin != 0 && begin < end) {
+ int stat;
+ *end = '\0';
+ *begin = '\0';
+ char * name = abi::__cxa_demangle(begin+1, 0, 0, &stat);
+ if (module == NULL) {
+ if (name == NULL || stat != 0) {
+ builder.format(" In: '%s'\n", begin+1);
+ }
+ else {
+ builder.format(" In: '%s'\n", name);
+ }
+ }
+ else {
+ if (name == NULL || stat != 0) {
+ builder.format(" In: [%s] '%s'\n", module, begin+1);
+ }
+ else {
+ builder.format(" In: [%s] '%s'\n", module, name);
+ }
+ }
+ free(name);
+ }
+ else {
+ builder.format(" In: '%s'\n", string_array[i]);
+ }
+# else
+ builder.format(" In: '%s'\n", string_array[i]);
+# endif
+ lines.append(builder.release());
+ }
+
+ free(string_array);
+ }
+
+ static void printStackTrace(void * trace[], int size, int start=0) {
+ nvDebug( "\nDumping stacktrace:\n" );
+
+ Array<const char *> lines;
+ writeStackTrace(trace, size, 1, lines);
+
+ for (uint i = 0; i < lines.count(); i++) {
+ nvDebug("%s", lines[i]);
+ delete lines[i];
+ }
+
+ nvDebug("\n");
+ }
+
+#endif // defined(NV_HAVE_EXECINFO_H)
+
+ static void * callerAddress(void * secret)
+ {
+#if NV_OS_DARWIN
+# if defined(_STRUCT_MCONTEXT)
+# if NV_CPU_PPC
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext->__ss.__srr0;
+# elif NV_CPU_X86_64
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext->__ss.__rip;
+# elif NV_CPU_X86
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext->__ss.__eip;
+# elif NV_CPU_ARM
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext->__ss.__pc;
+# else
+# error "Unknown CPU"
+# endif
+# else
+# if NV_CPU_PPC
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext->ss.srr0;
+# elif NV_CPU_X86
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext->ss.eip;
+# else
+# error "Unknown CPU"
+# endif
+# endif
+#elif NV_OS_FREEBSD
+# if NV_CPU_X86_64
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *)ucp->uc_mcontext.mc_rip;
+# elif NV_CPU_X86
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *)ucp->uc_mcontext.mc_eip;
+# else
+# error "Unknown CPU"
+# endif
+#elif NV_OS_OPENBSD
+# if NV_CPU_X86_64
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *)ucp->sc_rip;
+# elif NV_CPU_X86
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *)ucp->sc_eip;
+# else
+# error "Unknown CPU"
+# endif
+#else
+# if NV_CPU_X86_64
+ // #define REG_RIP REG_INDEX(rip) // seems to be 16
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *)ucp->uc_mcontext.gregs[REG_RIP];
+# elif NV_CPU_X86
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *)ucp->uc_mcontext.gregs[14/*REG_EIP*/];
+# elif NV_CPU_PPC
+ ucontext_t * ucp = (ucontext_t *)secret;
+ return (void *) ucp->uc_mcontext.regs->nip;
+# else
+# error "Unknown CPU"
+# endif
+#endif
+
+ // How to obtain the instruction pointers in different platforms, from mlton's source code.
+ // http://mlton.org/
+ // OpenBSD && NetBSD
+ // ucp->sc_eip
+ // FreeBSD:
+ // ucp->uc_mcontext.mc_eip
+ // HPUX:
+ // ucp->uc_link
+ // Solaris:
+ // ucp->uc_mcontext.gregs[REG_PC]
+ // Linux hppa:
+ // uc->uc_mcontext.sc_iaoq[0] & ~0x3UL
+ // Linux sparc:
+ // ((struct sigcontext*) secret)->sigc_regs.tpc
+ // Linux sparc64:
+ // ((struct sigcontext*) secret)->si_regs.pc
+
+ // potentially correct for other archs:
+ // Linux alpha: ucp->m_context.sc_pc
+ // Linux arm: ucp->m_context.ctx.arm_pc
+ // Linux ia64: ucp->m_context.sc_ip & ~0x3UL
+ // Linux mips: ucp->m_context.sc_pc
+ // Linux s390: ucp->m_context.sregs->regs.psw.addr
+ }
+
+ static void nvSigHandler(int sig, siginfo_t *info, void *secret)
+ {
+ void * pnt = callerAddress(secret);
+
+ // Do something useful with siginfo_t
+ if (sig == SIGSEGV) {
+ if (pnt != NULL) nvDebug("Got signal %d, faulty address is %p, from %p\n", sig, info->si_addr, pnt);
+ else nvDebug("Got signal %d, faulty address is %p\n", sig, info->si_addr);
+ }
+ else if(sig == SIGTRAP) {
+ nvDebug("Breakpoint hit.\n");
+ }
+ else {
+ nvDebug("Got signal %d\n", sig);
+ }
+
+#if defined(NV_HAVE_EXECINFO_H)
+ if (hasStackTrace()) // in case of weak linking
+ {
+ void * trace[64];
+ int size = backtrace(trace, 64);
+
+ if (pnt != NULL) {
+ // Overwrite sigaction with caller's address.
+ trace[1] = pnt;
+ }
+
+ printStackTrace(trace, size, 1);
+ }
+#endif // defined(NV_HAVE_EXECINFO_H)
+
+ exit(0);
+ }
+
+#endif // defined(NV_HAVE_SIGNAL_H)
+
+
+
+#if NV_OS_WIN32 //&& NV_CC_MSVC
+
+ /** Win32 assert handler. */
+ struct Win32AssertHandler : public AssertHandler
+ {
+ // Flush the message queue. This is necessary for the message box to show up.
+ static void flushMessageQueue()
+ {
+ MSG msg;
+ while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
+ //if( msg.message == WM_QUIT ) break;
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+ }
+
+ // Assert handler method.
+ virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
+ {
+ int ret = NV_ABORT_EXIT;
+
+ StringBuilder error_string;
+ error_string.format("*** Assertion failed: %s\n On file: %s\n On line: %d\n", exp, file, line );
+ if (func != NULL) {
+ error_string.appendFormat(" On function: %s\n", func);
+ }
+ if (msg != NULL) {
+ error_string.append(" Message: ");
+ va_list tmp;
+ va_copy(tmp, arg);
+ error_string.appendFormatList(msg, tmp);
+ va_end(tmp);
+ error_string.append("\n");
+ }
+ nvDebug( error_string.str() );
+
+ // Print stack trace:
+ debug::dumpInfo();
+
+ if (debug::isDebuggerPresent()) {
+ return NV_ABORT_DEBUG;
+ }
+
+ if (s_interactive) {
+ flushMessageQueue();
+ int action = MessageBoxA(NULL, error_string.str(), "Assertion failed", MB_ABORTRETRYIGNORE | MB_ICONERROR | MB_TOPMOST);
+ switch( action ) {
+ case IDRETRY:
+ ret = NV_ABORT_DEBUG;
+ break;
+ case IDIGNORE:
+ ret = NV_ABORT_IGNORE;
+ break;
+ case IDABORT:
+ default:
+ ret = NV_ABORT_EXIT;
+ break;
+ }
+ /*if( _CrtDbgReport( _CRT_ASSERT, file, line, module, exp ) == 1 ) {
+ return NV_ABORT_DEBUG;
+ }*/
+ }
+
+ if (ret == NV_ABORT_EXIT) {
+ // Exit cleanly.
+ exit(EXIT_FAILURE + 1);
+ }
+
+ return ret;
+ }
+ };
+#elif NV_OS_XBOX
+
+ /** Xbox360 assert handler. */
+ struct Xbox360AssertHandler : public AssertHandler
+ {
+ // Assert handler method.
+ virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
+ {
+ int ret = NV_ABORT_EXIT;
+
+ StringBuilder error_string;
+ if( func != NULL ) {
+ error_string.format( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
+ nvDebug( error_string.str() );
+ }
+ else {
+ error_string.format( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
+ nvDebug( error_string.str() );
+ }
+
+ if (debug::isDebuggerPresent()) {
+ return NV_ABORT_DEBUG;
+ }
+
+ if( ret == NV_ABORT_EXIT ) {
+ // Exit cleanly.
+ exit(EXIT_FAILURE + 1);
+ }
+
+ return ret;
+ }
+ };
+#elif NV_OS_ORBIS || NV_OS_DURANGO
+
+ /** Console assert handler. */
+ struct ConsoleAssertHandler : public AssertHandler
+ {
+ // Assert handler method.
+ virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
+ {
+ if( func != NULL ) {
+ nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
+ }
+ else {
+ nvDebug( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
+ }
+
+ //SBtodoORBIS print stack trace
+ /*if (hasStackTrace())
+ {
+ void * trace[64];
+ int size = backtrace(trace, 64);
+ printStackTrace(trace, size, 2);
+ }*/
+
+ if (debug::isDebuggerPresent())
+ return NV_ABORT_DEBUG;
+
+ return NV_ABORT_IGNORE;
+ }
+ };
+
+#else
+
+ /** Unix assert handler. */
+ struct UnixAssertHandler : public AssertHandler
+ {
+ // Assert handler method.
+ virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
+ {
+ int ret = NV_ABORT_EXIT;
+
+ if( func != NULL ) {
+ nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
+ }
+ else {
+ nvDebug( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
+ }
+
+#if _DEBUG
+ if (debug::isDebuggerPresent()) {
+ return NV_ABORT_DEBUG;
+ }
+#endif
+
+#if defined(NV_HAVE_EXECINFO_H)
+ if (hasStackTrace())
+ {
+ void * trace[64];
+ int size = backtrace(trace, 64);
+ printStackTrace(trace, size, 2);
+ }
+#endif
+
+ if( ret == NV_ABORT_EXIT ) {
+ // Exit cleanly.
+ exit(EXIT_FAILURE + 1);
+ }
+
+ return ret;
+ }
+ };
+
+#endif
+
+} // namespace
+
+
+/// Handle assertion through the assert handler.
+int nvAbort(const char * exp, const char * file, int line, const char * func/*=NULL*/, const char * msg/*= NULL*/, ...)
+{
+#if NV_OS_WIN32 //&& NV_CC_MSVC
+ static Win32AssertHandler s_default_assert_handler;
+#elif NV_OS_XBOX
+ static Xbox360AssertHandler s_default_assert_handler;
+#elif NV_OS_ORBIS || NV_OS_DURANGO
+ static ConsoleAssertHandler s_default_assert_handler;
+#else
+ static UnixAssertHandler s_default_assert_handler;
+#endif
+
+ va_list arg;
+ va_start(arg,msg);
+
+ AssertHandler * handler = s_assert_handler != NULL ? s_assert_handler : &s_default_assert_handler;
+ int result = handler->assertion(exp, file, line, func, msg, arg);
+
+ va_end(arg);
+
+ return result;
+}
+
+// Abnormal termination. Create mini dump and output call stack.
+void debug::terminate(int code)
+{
+#if NV_OS_WIN32 || NV_OS_DURANGO
+ EnterCriticalSection(&s_handler_critical_section);
+
+ writeMiniDump(NULL);
+
+#if NV_OS_WIN32
+ const int max_stack_size = 64;
+ void * trace[max_stack_size];
+ int size = backtrace(trace, max_stack_size);
+
+ // @@ Use win32's CreateFile?
+ FILE * fp = fileOpen("crash.txt", "wb");
+ if (fp != NULL) {
+ Array<const char *> lines;
+ writeStackTrace(trace, size, 0, lines);
+
+ for (uint i = 0; i < lines.count(); i++) {
+ fputs(lines[i], fp);
+ delete lines[i];
+ }
+
+ // @@ Add more info to crash.txt?
+
+ fclose(fp);
+ }
+#endif
+
+ LeaveCriticalSection(&s_handler_critical_section);
+#endif
+
+ exit(code);
+}
+
+
+/// Shows a message through the message handler.
+void NV_CDECL nvDebugPrint(const char *msg, ...)
+{
+ va_list arg;
+ va_start(arg,msg);
+ if (s_message_handler != NULL) {
+ s_message_handler->log( msg, arg );
+ }
+ else {
+ vprintf(msg, arg);
+ }
+ va_end(arg);
+}
+
+
+/// Dump debug info.
+void debug::dumpInfo()
+{
+#if (NV_OS_WIN32 && NV_CC_MSVC) || (defined(NV_HAVE_SIGNAL_H) && defined(NV_HAVE_EXECINFO_H))
+ if (hasStackTrace())
+ {
+ void * trace[64];
+ int size = backtrace(trace, 64);
+
+ nvDebug( "\nDumping stacktrace:\n" );
+
+ Array<const char *> lines;
+ writeStackTrace(trace, size, 1, lines);
+
+ for (uint i = 0; i < lines.count(); i++) {
+ nvDebug("%s", lines[i]);
+ delete lines[i];
+ }
+ }
+#endif
+}
+
+/// Dump callstack using the specified handler.
+void debug::dumpCallstack(MessageHandler *messageHandler, int callstackLevelsToSkip /*= 0*/)
+{
+#if (NV_OS_WIN32 && NV_CC_MSVC) || (defined(NV_HAVE_SIGNAL_H) && defined(NV_HAVE_EXECINFO_H))
+ if (hasStackTrace())
+ {
+ void * trace[64];
+ int size = backtrace(trace, 64);
+
+ Array<const char *> lines;
+ writeStackTrace(trace, size, callstackLevelsToSkip + 1, lines); // + 1 to skip the call to dumpCallstack
+
+ for (uint i = 0; i < lines.count(); i++) {
+ messageHandler->log(lines[i], NULL);
+ delete lines[i];
+ }
+ }
+#endif
+}
+
+
+/// Set the debug message handler.
+void debug::setMessageHandler(MessageHandler * message_handler)
+{
+ s_message_handler = message_handler;
+}
+
+/// Reset the debug message handler.
+void debug::resetMessageHandler()
+{
+ s_message_handler = NULL;
+}
+
+/// Set the assert handler.
+void debug::setAssertHandler(AssertHandler * assert_handler)
+{
+ s_assert_handler = assert_handler;
+}
+
+/// Reset the assert handler.
+void debug::resetAssertHandler()
+{
+ s_assert_handler = NULL;
+}
+
+#if NV_OS_WIN32 || NV_OS_DURANGO
+#if NV_USE_SEPARATE_THREAD
+
+static void initHandlerThread()
+{
+ static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
+
+ // Set synchronization primitives and the handler thread. Each
+ // ExceptionHandler object gets its own handler thread because that's the
+ // only way to reliably guarantee sufficient stack space in an exception,
+ // and it allows an easy way to get a snapshot of the requesting thread's
+ // context outside of an exception.
+ InitializeCriticalSection(&s_handler_critical_section);
+
+ s_handler_start_semaphore = CreateSemaphoreExW(NULL, 0, 1, NULL, 0,
+ SEMAPHORE_MODIFY_STATE | DELETE | SYNCHRONIZE);
+ nvDebugCheck(s_handler_start_semaphore != NULL);
+
+ s_handler_finish_semaphore = CreateSemaphoreExW(NULL, 0, 1, NULL, 0,
+ SEMAPHORE_MODIFY_STATE | DELETE | SYNCHRONIZE);
+ nvDebugCheck(s_handler_finish_semaphore != NULL);
+
+ // Don't attempt to create the thread if we could not create the semaphores.
+ if (s_handler_finish_semaphore != NULL && s_handler_start_semaphore != NULL) {
+ DWORD thread_id;
+ s_handler_thread = CreateThread(NULL, // lpThreadAttributes
+ kExceptionHandlerThreadInitialStackSize,
+ ExceptionHandlerThreadMain,
+ NULL, // lpParameter
+ 0, // dwCreationFlags
+ &thread_id);
+ nvDebugCheck(s_handler_thread != NULL);
+ }
+
+ /* @@ We should avoid loading modules in the exception handler!
+ dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
+ if (dbghelp_module_) {
+ minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));
+ }
+ */
+}
+
+static void shutHandlerThread() {
+ // @@ Free stuff. Terminate thread.
+}
+
+#endif // NV_USE_SEPARATE_THREAD
+#endif // NV_OS_WIN32
+
+
+// Enable signal handler.
+void debug::enableSigHandler(bool interactive)
+{
+ if (s_sig_handler_enabled) return;
+
+ s_sig_handler_enabled = true;
+ s_interactive = interactive;
+
+#if (NV_OS_WIN32 && NV_CC_MSVC) || NV_OS_DURANGO
+ if (interactive) {
+#if NV_OS_WIN32
+ // Do not display message boxes on error.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
+ SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
+#endif
+
+ // CRT reports errors to debug output only.
+ // http://msdn.microsoft.com/en-us/library/1y71x448(v=vs.80).aspx
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+ }
+
+
+#if NV_USE_SEPARATE_THREAD
+ initHandlerThread();
+#else
+ InitializeCriticalSection(&s_handler_critical_section);
+#endif
+
+ s_old_exception_filter = ::SetUnhandledExceptionFilter( handleException );
+
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ _set_invalid_parameter_handler(handleInvalidParameter);
+#endif // _MSC_VER >= 1400
+
+ _set_purecall_handler(handlePureVirtualCall);
+
+#if NV_OS_WIN32
+ // SYMOPT_DEFERRED_LOADS make us not take a ton of time unless we actual log traces
+ SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_FAIL_CRITICAL_ERRORS|SYMOPT_LOAD_LINES|SYMOPT_UNDNAME);
+
+ if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+ DWORD error = GetLastError();
+ nvDebug("SymInitialize returned error : %d\n", error);
+ }
+#endif
+
+#elif !NV_OS_WIN32 && defined(NV_HAVE_SIGNAL_H)
+
+ // Install our signal handler
+ struct sigaction sa;
+ sa.sa_sigaction = nvSigHandler;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+
+ sigaction(SIGSEGV, &sa, &s_old_sigsegv);
+ sigaction(SIGTRAP, &sa, &s_old_sigtrap);
+ sigaction(SIGFPE, &sa, &s_old_sigfpe);
+ sigaction(SIGBUS, &sa, &s_old_sigbus);
+
+#endif
+}
+
+/// Disable signal handler.
+void debug::disableSigHandler()
+{
+ nvCheck(s_sig_handler_enabled == true);
+ s_sig_handler_enabled = false;
+
+#if (NV_OS_WIN32 && NV_CC_MSVC) || NV_OS_DURANGO
+
+ ::SetUnhandledExceptionFilter( s_old_exception_filter );
+ s_old_exception_filter = NULL;
+
+#if NV_OS_WIN32
+ SymCleanup(GetCurrentProcess());
+#endif
+
+#elif !NV_OS_WIN32 && defined(NV_HAVE_SIGNAL_H)
+
+ sigaction(SIGSEGV, &s_old_sigsegv, NULL);
+ sigaction(SIGTRAP, &s_old_sigtrap, NULL);
+ sigaction(SIGFPE, &s_old_sigfpe, NULL);
+ sigaction(SIGBUS, &s_old_sigbus, NULL);
+
+#endif
+}
+
+
+bool debug::isDebuggerPresent()
+{
+#if NV_OS_WIN32
+ HINSTANCE kernel32 = GetModuleHandleA("kernel32.dll");
+ if (kernel32) {
+ FARPROC IsDebuggerPresent = GetProcAddress(kernel32, "IsDebuggerPresent");
+ if (IsDebuggerPresent != NULL && IsDebuggerPresent()) {
+ return true;
+ }
+ }
+ return false;
+#elif NV_OS_XBOX
+#ifdef _DEBUG
+ return DmIsDebuggerPresent() == TRUE;
+#else
+ return false;
+#endif
+#elif NV_OS_ORBIS
+ #if PS4_FINAL_REQUIREMENTS
+ return false;
+ #else
+ return sceDbgIsDebuggerAttached() == 1;
+ #endif
+#elif NV_OS_DURANGO
+ #if XB1_FINAL_REQUIREMENTS
+ return false;
+ #else
+ return IsDebuggerPresent() == TRUE;
+ #endif
+#elif NV_OS_DARWIN
+ int mib[4];
+ struct kinfo_proc info;
+ size_t size;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+ size = sizeof(info);
+ info.kp_proc.p_flag = 0;
+ sysctl(mib,4,&info,&size,NULL,0);
+ return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED);
+#else
+ // if ppid != sid, some process spawned our app, probably a debugger.
+ return getsid(getpid()) != getppid();
+#endif
+}
+
+bool debug::attachToDebugger()
+{
+#if NV_OS_WIN32
+ if (isDebuggerPresent() == FALSE) {
+ Path process(1024);
+ process.copy("\"");
+ GetSystemDirectoryA(process.str() + 1, 1024 - 1);
+
+ process.appendSeparator();
+
+ process.appendFormat("VSJitDebugger.exe\" -p %lu", ::GetCurrentProcessId());
+
+ STARTUPINFOA sSi;
+ memset(&sSi, 0, sizeof(sSi));
+
+ PROCESS_INFORMATION sPi;
+ memset(&sPi, 0, sizeof(sPi));
+
+ BOOL b = CreateProcessA(NULL, process.str(), NULL, NULL, FALSE, 0, NULL, NULL, &sSi, &sPi);
+ if (b != FALSE) {
+ ::WaitForSingleObject(sPi.hProcess, INFINITE);
+
+ DWORD dwExitCode;
+ ::GetExitCodeProcess(sPi.hProcess, &dwExitCode);
+ if (dwExitCode != 0) //if exit code is zero, a debugger was selected
+ b = FALSE;
+ }
+
+ if (sPi.hThread != NULL) ::CloseHandle(sPi.hThread);
+ if (sPi.hProcess != NULL) ::CloseHandle(sPi.hProcess);
+
+ if (b == FALSE)
+ return false;
+
+ for (int i = 0; i < 5*60; i++) {
+ if (isDebuggerPresent())
+ break;
+ ::Sleep(200);
+ }
+ }
+#endif // NV_OS_WIN32
+
+ return true;
+}
diff --git a/thirdparty/thekla_atlas/nvcore/Debug.h b/thirdparty/thekla_atlas/nvcore/Debug.h
new file mode 100644
index 0000000000..f37a05c453
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Debug.h
@@ -0,0 +1,246 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_DEBUG_H
+#define NV_CORE_DEBUG_H
+
+#include "nvcore.h"
+
+#include <stdarg.h> // va_list
+
+#if NV_OS_IOS //ACS: maybe we want this for OSX too?
+# ifdef __APPLE__
+# include <TargetConditionals.h>
+# include <signal.h>
+# endif
+#endif
+
+// Make sure we are using our assert.
+#undef assert
+
+#define NV_ABORT_DEBUG 1
+#define NV_ABORT_IGNORE 2
+#define NV_ABORT_EXIT 3
+
+#define nvNoAssert(exp) \
+ NV_MULTI_LINE_MACRO_BEGIN \
+ (void)sizeof(exp); \
+ NV_MULTI_LINE_MACRO_END
+
+#if NV_NO_ASSERT
+
+# define nvAssert(exp) nvNoAssert(exp)
+# define nvCheck(exp) nvNoAssert(exp)
+# define nvDebugAssert(exp) nvNoAssert(exp)
+# define nvDebugCheck(exp) nvNoAssert(exp)
+# define nvDebugBreak() nvNoAssert(0)
+
+#else // NV_NO_ASSERT
+
+# if NV_CC_MSVC
+ // @@ Does this work in msvc-6 and earlier?
+# define nvDebugBreak() __debugbreak()
+//# define nvDebugBreak() __asm { int 3 }
+# elif NV_OS_ORBIS
+# define nvDebugBreak() __debugbreak()
+# elif NV_OS_IOS && TARGET_OS_IPHONE
+# define nvDebugBreak() raise(SIGINT)
+# elif NV_CC_CLANG
+# define nvDebugBreak() __builtin_debugtrap()
+# elif NV_CC_GNUC
+//# define nvDebugBreak() __builtin_debugtrap() // Does GCC have debugtrap?
+# define nvDebugBreak() __builtin_trap()
+/*
+# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN
+// @@ Use __builtin_trap() on GCC
+# define nvDebugBreak() __asm__ volatile ("trap")
+# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN
+# define nvDebugBreak() __asm__ volatile ("int3")
+# elif NV_CC_GNUC && NV_CPU_X86
+# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) )
+# elif NV_OS_ORBIS
+# define nvDebugBreak() __asm volatile ("int $0x41")
+# else
+# include <signal.h>
+# define nvDebugBreak() raise(SIGTRAP);
+// define nvDebugBreak() *((int *)(0)) = 0
+*/
+# endif
+
+# if NV_CC_MSVC
+# define nvExpect(expr) (expr)
+#else
+# define nvExpect(expr) __builtin_expect((expr) != 0, true)
+#endif
+
+#if NV_CC_CLANG
+# if __has_feature(attribute_analyzer_noreturn)
+# define NV_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
+# else
+# define NV_ANALYZER_NORETURN
+# endif
+#else
+# define NV_ANALYZER_NORETURN
+#endif
+
+#define nvDebugBreakOnce() \
+ NV_MULTI_LINE_MACRO_BEGIN \
+ static bool firstTime = true; \
+ if (firstTime) { firstTime = false; nvDebugBreak(); } \
+ NV_MULTI_LINE_MACRO_END
+
+#define nvAssertMacro(exp) \
+ NV_MULTI_LINE_MACRO_BEGIN \
+ if (!nvExpect(exp)) { \
+ if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \
+ nvDebugBreak(); \
+ } \
+ } \
+ NV_MULTI_LINE_MACRO_END
+
+// GCC, LLVM need "##" before the __VA_ARGS__, MSVC doesn't care
+#define nvAssertMacroWithIgnoreAll(exp,...) \
+ NV_MULTI_LINE_MACRO_BEGIN \
+ static bool ignoreAll = false; \
+ if (!ignoreAll && !nvExpect(exp)) { \
+ int _result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__, ##__VA_ARGS__); \
+ if (_result == NV_ABORT_DEBUG) { \
+ nvDebugBreak(); \
+ } else if (_result == NV_ABORT_IGNORE) { \
+ ignoreAll = true; \
+ } \
+ } \
+ NV_MULTI_LINE_MACRO_END
+
+// Interesting assert macro from Insomniac:
+// http://www.gdcvault.com/play/1015319/Developing-Imperfect-Software-How-to
+// Used as follows:
+// if (nvCheck(i < count)) {
+// normal path
+// } else {
+// fixup code.
+// }
+// This style of macro could be combined with __builtin_expect to let the compiler know failure is unlikely.
+#define nvCheckMacro(exp) \
+ (\
+ (exp) ? true : ( \
+ (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) ? (nvDebugBreak(), true) : ( false ) \
+ ) \
+ )
+
+
+#define nvAssert(exp) nvAssertMacro(exp)
+#define nvCheck(exp) nvAssertMacro(exp)
+
+#if defined(_DEBUG)
+# define nvDebugAssert(exp) nvAssertMacro(exp)
+# define nvDebugCheck(exp) nvAssertMacro(exp)
+#else // _DEBUG
+# define nvDebugAssert(exp) nvNoAssert(exp)
+# define nvDebugCheck(exp) nvNoAssert(exp)
+#endif // _DEBUG
+
+#endif // NV_NO_ASSERT
+
+// Use nvAssume for very simple expresions only: nvAssume(0), nvAssume(value == true), etc.
+/*#if !defined(_DEBUG)
+# if NV_CC_MSVC
+# define nvAssume(exp) __assume(exp)
+# else
+# define nvAssume(exp) nvCheck(exp)
+# endif
+#else
+# define nvAssume(exp) nvCheck(exp)
+#endif*/
+
+#if defined(_DEBUG)
+# if NV_CC_MSVC
+# define nvUnreachable() nvAssert(0 && "unreachable"); __assume(0)
+# else
+# define nvUnreachable() nvAssert(0 && "unreachable"); __builtin_unreachable()
+# endif
+#else
+# if NV_CC_MSVC
+# define nvUnreachable() __assume(0)
+# else
+# define nvUnreachable() __builtin_unreachable()
+# endif
+#endif
+
+#define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__)
+#define nvWarning(x) nvDebugPrint("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x))
+
+#ifndef NV_DEBUG_PRINT
+#define NV_DEBUG_PRINT 1 //defined(_DEBUG)
+#endif
+
+#if NV_DEBUG_PRINT
+#define nvDebug(...) nvDebugPrint(__VA_ARGS__)
+#else
+#if NV_CC_MSVC
+#define nvDebug(...) __noop(__VA_ARGS__)
+#else
+#define nvDebug(...) ((void)0) // Non-msvc platforms do not evaluate arguments?
+#endif
+#endif
+
+
+NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = NULL, const char * msg = NULL, ...) __attribute__((format (printf, 5, 6))) NV_ANALYZER_NORETURN;
+NVCORE_API void NV_CDECL nvDebugPrint( const char *msg, ... ) __attribute__((format (printf, 1, 2)));
+
+namespace nv
+{
+ inline bool isValidPtr(const void * ptr) {
+ #if NV_OS_DARWIN
+ return true; // IC: Not sure what ranges are OK on OSX.
+ #endif
+
+ #if NV_CPU_X86_64
+ if (ptr == NULL) return true;
+ if (reinterpret_cast<uint64>(ptr) < 0x10000ULL) return false;
+ if (reinterpret_cast<uint64>(ptr) >= 0x000007FFFFFEFFFFULL) return false;
+ #else
+ if (reinterpret_cast<uint32>(ptr) == 0xcccccccc) return false;
+ if (reinterpret_cast<uint32>(ptr) == 0xcdcdcdcd) return false;
+ if (reinterpret_cast<uint32>(ptr) == 0xdddddddd) return false;
+ if (reinterpret_cast<uint32>(ptr) == 0xffffffff) return false;
+ #endif
+ return true;
+ }
+
+ // Message handler interface.
+ struct MessageHandler {
+ virtual void log(const char * str, va_list arg) = 0;
+ virtual ~MessageHandler() {}
+ };
+
+ // Assert handler interface.
+ struct AssertHandler {
+ virtual int assertion(const char *exp, const char *file, int line, const char *func, const char *msg, va_list arg) = 0;
+ virtual ~AssertHandler() {}
+ };
+
+
+ namespace debug
+ {
+ NVCORE_API void dumpInfo();
+ NVCORE_API void dumpCallstack( MessageHandler *messageHandler, int callstackLevelsToSkip = 0 );
+
+ NVCORE_API void setMessageHandler( MessageHandler * messageHandler );
+ NVCORE_API void resetMessageHandler();
+
+ NVCORE_API void setAssertHandler( AssertHandler * assertHanlder );
+ NVCORE_API void resetAssertHandler();
+
+ NVCORE_API void enableSigHandler(bool interactive);
+ NVCORE_API void disableSigHandler();
+
+ NVCORE_API bool isDebuggerPresent();
+ NVCORE_API bool attachToDebugger();
+
+ NVCORE_API void terminate(int code);
+ }
+
+} // nv namespace
+
+#endif // NV_CORE_DEBUG_H
diff --git a/thirdparty/thekla_atlas/nvcore/DefsGnucDarwin.h b/thirdparty/thekla_atlas/nvcore/DefsGnucDarwin.h
new file mode 100644
index 0000000000..afb21c3d25
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/DefsGnucDarwin.h
@@ -0,0 +1,57 @@
+#ifndef NV_CORE_H
+#error "Do not include this file directly."
+#endif
+
+#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
+#include <stddef.h> // operator new, size_t, NULL
+
+// Function linkage
+#define DLL_IMPORT
+#if __GNUC__ >= 4
+# define DLL_EXPORT __attribute__((visibility("default")))
+# define DLL_EXPORT_CLASS DLL_EXPORT
+#else
+# define DLL_EXPORT
+# define DLL_EXPORT_CLASS
+#endif
+
+// Function calling modes
+#if NV_CPU_X86
+# define NV_CDECL __attribute__((cdecl))
+# define NV_STDCALL __attribute__((stdcall))
+#else
+# define NV_CDECL
+# define NV_STDCALL
+#endif
+
+#define NV_FASTCALL __attribute__((fastcall))
+#define NV_FORCEINLINE __attribute__((always_inline)) inline
+#define NV_DEPRECATED __attribute__((deprecated))
+#if NV_OS_IOS
+#define NV_THREAD_LOCAL // @@ IC: Looks like iOS does not have support for TLS declarations.
+#else
+#define NV_THREAD_LOCAL __thread
+#endif
+
+#if __GNUC__ > 2
+#define NV_PURE __attribute__((pure))
+#define NV_CONST __attribute__((const))
+#else
+#define NV_PURE
+#define NV_CONST
+#endif
+
+#define NV_NOINLINE __attribute__((noinline))
+
+// Define __FUNC__ properly.
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+# define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
+# else
+# define __FUNC__ "<unknown>"
+# endif
+#else
+# define __FUNC__ __PRETTY_FUNCTION__
+#endif
+
+#define restrict __restrict__
diff --git a/thirdparty/thekla_atlas/nvcore/DefsGnucLinux.h b/thirdparty/thekla_atlas/nvcore/DefsGnucLinux.h
new file mode 100644
index 0000000000..2126d866f5
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/DefsGnucLinux.h
@@ -0,0 +1,59 @@
+#ifndef NV_CORE_H
+#error "Do not include this file directly."
+#endif
+
+#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
+#include <stddef.h> // operator new, size_t, NULL
+
+// Function linkage
+#define DLL_IMPORT
+#if __GNUC__ >= 4
+# define DLL_EXPORT __attribute__((visibility("default")))
+# define DLL_EXPORT_CLASS DLL_EXPORT
+#else
+# define DLL_EXPORT
+# define DLL_EXPORT_CLASS
+#endif
+
+// Function calling modes
+#if NV_CPU_X86
+# define NV_CDECL __attribute__((cdecl))
+# define NV_STDCALL __attribute__((stdcall))
+#else
+# define NV_CDECL
+# define NV_STDCALL
+#endif
+
+#define NV_FASTCALL __attribute__((fastcall))
+//#if __GNUC__ > 3
+// It seems that GCC does not assume always_inline implies inline. I think this depends on the GCC version :(
+#define NV_FORCEINLINE inline __attribute__((always_inline))
+//#else
+// Some compilers complain that inline and always_inline are redundant.
+//#define NV_FORCEINLINE __attribute__((always_inline))
+//#endif
+#define NV_DEPRECATED __attribute__((deprecated))
+#define NV_THREAD_LOCAL __thread
+
+#if __GNUC__ > 2
+#define NV_PURE __attribute__((pure))
+#define NV_CONST __attribute__((const))
+#else
+#define NV_PURE
+#define NV_CONST
+#endif
+
+#define NV_NOINLINE __attribute__((noinline))
+
+// Define __FUNC__ properly.
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+# define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
+# else
+# define __FUNC__ "<unknown>"
+# endif
+#else
+# define __FUNC__ __PRETTY_FUNCTION__
+#endif
+
+#define restrict __restrict__
diff --git a/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h b/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h
new file mode 100644
index 0000000000..f35ed88575
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/DefsGnucWin32.h
@@ -0,0 +1,65 @@
+#ifndef NV_CORE_H
+#error "Do not include this file directly."
+#endif
+
+//#include <cstddef> // size_t, NULL
+
+// Function linkage
+#define DLL_IMPORT __declspec(dllimport)
+#define DLL_EXPORT __declspec(dllexport)
+#define DLL_EXPORT_CLASS DLL_EXPORT
+
+// Function calling modes
+#if NV_CPU_X86
+# define NV_CDECL __attribute__((cdecl))
+# define NV_STDCALL __attribute__((stdcall))
+#else
+# define NV_CDECL
+# define NV_STDCALL
+#endif
+
+#define NV_FASTCALL __attribute__((fastcall))
+#define NV_FORCEINLINE __attribute__((always_inline))
+#define NV_DEPRECATED __attribute__((deprecated))
+
+#if __GNUC__ > 2
+#define NV_PURE __attribute__((pure))
+#define NV_CONST __attribute__((const))
+#else
+#define NV_PURE
+#define NV_CONST
+#endif
+
+#define NV_NOINLINE __attribute__((noinline))
+
+// Define __FUNC__ properly.
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+# define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
+# else
+# define __FUNC__ "<unknown>"
+# endif
+#else
+# define __FUNC__ __PRETTY_FUNCTION__
+#endif
+
+#define restrict __restrict__
+
+/*
+// Type definitions
+typedef unsigned char uint8;
+typedef signed char int8;
+
+typedef unsigned short uint16;
+typedef signed short int16;
+
+typedef unsigned int uint32;
+typedef signed int int32;
+
+typedef unsigned long long uint64;
+typedef signed long long int64;
+
+// Aliases
+typedef uint32 uint;
+*/
+
diff --git a/thirdparty/thekla_atlas/nvcore/DefsVcWin32.h b/thirdparty/thekla_atlas/nvcore/DefsVcWin32.h
new file mode 100644
index 0000000000..a915f3791a
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/DefsVcWin32.h
@@ -0,0 +1,94 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#ifndef NV_CORE_H
+#error "Do not include this file directly."
+#endif
+
+// Function linkage
+#define DLL_IMPORT __declspec(dllimport)
+#define DLL_EXPORT __declspec(dllexport)
+#define DLL_EXPORT_CLASS DLL_EXPORT
+
+// Function calling modes
+#define NV_CDECL __cdecl
+#define NV_STDCALL __stdcall
+#define NV_FASTCALL __fastcall
+#define NV_DEPRECATED
+
+#define NV_PURE
+#define NV_CONST
+
+// Set standard function names.
+#if _MSC_VER < 1900
+# define snprintf _snprintf
+#endif
+#if _MSC_VER < 1500
+# define vsnprintf _vsnprintf
+#endif
+#if _MSC_VER < 1700
+# define strtoll _strtoi64
+# define strtoull _strtoui64
+#endif
+//#define chdir _chdir
+#define getcwd _getcwd
+
+#if _MSC_VER <= 1600
+#define va_copy(a, b) (a) = (b)
+#endif
+
+#if !defined restrict
+#define restrict
+#endif
+
+// Ignore gcc attributes.
+#define __attribute__(X)
+
+#if !defined __FUNC__
+#define __FUNC__ __FUNCTION__
+#endif
+
+#define NV_NOINLINE __declspec(noinline)
+#define NV_FORCEINLINE __forceinline
+
+#define NV_THREAD_LOCAL __declspec(thread)
+
+/*
+// Type definitions
+typedef unsigned char uint8;
+typedef signed char int8;
+
+typedef unsigned short uint16;
+typedef signed short int16;
+
+typedef unsigned int uint32;
+typedef signed int int32;
+
+typedef unsigned __int64 uint64;
+typedef signed __int64 int64;
+
+// Aliases
+typedef uint32 uint;
+*/
+
+// Unwanted VC++ warnings to disable.
+/*
+#pragma warning(disable : 4244) // conversion to float, possible loss of data
+#pragma warning(disable : 4245) // conversion from 'enum ' to 'unsigned long', signed/unsigned mismatch
+#pragma warning(disable : 4100) // unreferenced formal parameter
+#pragma warning(disable : 4514) // unreferenced inline function has been removed
+#pragma warning(disable : 4710) // inline function not expanded
+#pragma warning(disable : 4127) // Conditional expression is constant
+#pragma warning(disable : 4305) // truncation from 'const double' to 'float'
+#pragma warning(disable : 4505) // unreferenced local function has been removed
+
+#pragma warning(disable : 4702) // unreachable code in inline expanded function
+#pragma warning(disable : 4711) // function selected for automatic inlining
+#pragma warning(disable : 4725) // Pentium fdiv bug
+
+#pragma warning(disable : 4786) // Identifier was truncated and cannot be debugged.
+
+#pragma warning(disable : 4675) // resolved overload was found by argument-dependent lookup
+*/
+
+#pragma warning(1 : 4705) // Report unused local variables.
+#pragma warning(1 : 4555) // Expression has no effect.
diff --git a/thirdparty/thekla_atlas/nvcore/FileSystem.cpp b/thirdparty/thekla_atlas/nvcore/FileSystem.cpp
new file mode 100644
index 0000000000..5ed0ca074f
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/FileSystem.cpp
@@ -0,0 +1,75 @@
+// This code is in the public domain -- castano@gmail.com
+
+#include "FileSystem.h"
+
+#if NV_OS_WIN32
+#define _CRT_NONSTDC_NO_WARNINGS // _chdir is defined deprecated, but that's a bug, chdir is deprecated, _chdir is *not*.
+//#include <shlwapi.h> // PathFileExists
+#include <windows.h> // GetFileAttributes
+#include <direct.h> // _mkdir
+#elif NV_OS_XBOX
+#include <Xtl.h>
+#elif NV_OS_DURANGO
+#include <Windows.h>
+#else
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <stdio.h> // remove, unlink
+
+using namespace nv;
+
+
+bool FileSystem::exists(const char * path)
+{
+#if NV_OS_UNIX
+ return access(path, F_OK|R_OK) == 0;
+ //struct stat buf;
+ //return stat(path, &buf) == 0;
+#elif NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
+ // PathFileExists requires linking to shlwapi.lib
+ //return PathFileExists(path) != 0;
+ return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
+#else
+ if (FILE * fp = fopen(path, "r"))
+ {
+ fclose(fp);
+ return true;
+ }
+ return false;
+#endif
+}
+
+bool FileSystem::createDirectory(const char * path)
+{
+#if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
+ return CreateDirectoryA(path, NULL) != 0;
+#elif NV_OS_ORBIS
+ // not implemented
+ return false;
+#else
+ return mkdir(path, 0777) != -1;
+#endif
+}
+
+bool FileSystem::changeDirectory(const char * path)
+{
+#if NV_OS_WIN32
+ return _chdir(path) != -1;
+#elif NV_OS_XBOX || NV_OS_DURANGO
+ // Xbox doesn't support Current Working Directory!
+ return false;
+#elif NV_OS_ORBIS
+ // Orbis doesn't support Current Working Directory!
+ return false;
+#else
+ return chdir(path) != -1;
+#endif
+}
+
+bool FileSystem::removeFile(const char * path)
+{
+ // @@ Use unlink or remove?
+ return remove(path) == 0;
+}
diff --git a/thirdparty/thekla_atlas/nvcore/FileSystem.h b/thirdparty/thekla_atlas/nvcore/FileSystem.h
new file mode 100644
index 0000000000..afd0f449d3
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/FileSystem.h
@@ -0,0 +1,24 @@
+// This code is in the public domain -- castano@gmail.com
+
+#pragma once
+#ifndef NV_CORE_FILESYSTEM_H
+#define NV_CORE_FILESYSTEM_H
+
+#include "nvcore.h"
+
+namespace nv
+{
+
+ namespace FileSystem
+ {
+ NVCORE_API bool exists(const char * path);
+ NVCORE_API bool createDirectory(const char * path);
+ NVCORE_API bool changeDirectory(const char * path);
+ NVCORE_API bool removeFile(const char * path);
+
+ } // FileSystem namespace
+
+} // nv namespace
+
+
+#endif // NV_CORE_FILESYSTEM_H
diff --git a/thirdparty/thekla_atlas/nvcore/ForEach.h b/thirdparty/thekla_atlas/nvcore/ForEach.h
new file mode 100644
index 0000000000..bc66f424ef
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/ForEach.h
@@ -0,0 +1,71 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_FOREACH_H
+#define NV_CORE_FOREACH_H
+
+/*
+These foreach macros are very non-standard and somewhat confusing, but I like them.
+*/
+
+#include "nvcore.h"
+
+
+#if NV_CC_CPP11
+
+#define NV_FOREACH(i, container) \
+ for (auto i = (container).start(); !(container).isDone(i); (container).advance(i))
+
+#elif NV_CC_GNUC // If typeof is available:
+
+/*
+Ideally we would like to write this:
+
+#define NV_FOREACH(i, container) \
+ for(decltype(container)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i))
+
+But gcc versions prior to 4.7 required an intermediate type. See:
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=6709
+*/
+
+#define NV_FOREACH(i, container) \
+ typedef typeof(container) NV_STRING_JOIN2(cont,__LINE__); \
+ for(NV_STRING_JOIN2(cont,__LINE__)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i))
+
+#else // If typeof not available:
+
+#define NV_NEED_PSEUDOINDEX_WRAPPER 1
+
+#include <new> // placement new
+
+struct PseudoIndexWrapper {
+ template <typename T>
+ PseudoIndexWrapper(const T & container) {
+ nvStaticCheck(sizeof(typename T::PseudoIndex) <= sizeof(memory));
+ new (memory) typename T::PseudoIndex(container.start());
+ }
+ // PseudoIndex cannot have a dtor!
+
+ template <typename T> typename T::PseudoIndex & operator()(const T * /*container*/) {
+ return *reinterpret_cast<typename T::PseudoIndex *>(memory);
+ }
+ template <typename T> const typename T::PseudoIndex & operator()(const T * /*container*/) const {
+ return *reinterpret_cast<const typename T::PseudoIndex *>(memory);
+ }
+
+ uint8 memory[4]; // Increase the size if we have bigger enumerators.
+};
+
+#define NV_FOREACH(i, container) \
+ for(PseudoIndexWrapper i(container); !(container).isDone(i(&(container))); (container).advance(i(&(container))))
+
+#endif
+
+// Declare foreach keyword.
+#if !defined NV_NO_USE_KEYWORDS
+# define foreach NV_FOREACH
+# define foreach_index NV_FOREACH
+#endif
+
+
+#endif // NV_CORE_FOREACH_H
diff --git a/thirdparty/thekla_atlas/nvcore/Hash.h b/thirdparty/thekla_atlas/nvcore/Hash.h
new file mode 100644
index 0000000000..a8b0b2c63b
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Hash.h
@@ -0,0 +1,83 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_HASH_H
+#define NV_CORE_HASH_H
+
+#include "nvcore.h"
+
+namespace nv
+{
+ inline uint sdbmHash(const void * data_in, uint size, uint h = 5381)
+ {
+ const uint8 * data = (const uint8 *) data_in;
+ uint i = 0;
+ while (i < size) {
+ h = (h << 16) + (h << 6) - h + (uint) data[i++];
+ }
+ return h;
+ }
+
+ // Note that this hash does not handle NaN properly.
+ inline uint sdbmFloatHash(const float * f, uint count, uint h = 5381)
+ {
+ for (uint i = 0; i < count; i++) {
+ //nvDebugCheck(nv::isFinite(*f));
+ union { float f; uint32 i; } x = { f[i] };
+ if (x.i == 0x80000000) x.i = 0;
+ h = sdbmHash(&x, 4, h);
+ }
+ return h;
+ }
+
+
+ template <typename T>
+ inline uint hash(const T & t, uint h = 5381)
+ {
+ return sdbmHash(&t, sizeof(T), h);
+ }
+
+ template <>
+ inline uint hash(const float & f, uint h)
+ {
+ return sdbmFloatHash(&f, 1, h);
+ }
+
+
+ // Functors for hash table:
+ template <typename Key> struct Hash
+ {
+ uint operator()(const Key & k) const {
+ return hash(k);
+ }
+ };
+
+ template <typename Key> struct Equal
+ {
+ bool operator()(const Key & k0, const Key & k1) const {
+ return k0 == k1;
+ }
+ };
+
+
+ // @@ Move to Utils.h?
+ template <typename T1, typename T2>
+ struct Pair {
+ T1 first;
+ T2 second;
+ };
+
+ template <typename T1, typename T2>
+ bool operator==(const Pair<T1,T2> & p0, const Pair<T1,T2> & p1) {
+ return p0.first == p1.first && p0.second == p1.second;
+ }
+
+ template <typename T1, typename T2>
+ uint hash(const Pair<T1,T2> & p, uint h = 5381) {
+ return hash(p.second, hash(p.first));
+ }
+
+
+} // nv namespace
+
+#endif // NV_CORE_HASH_H
diff --git a/thirdparty/thekla_atlas/nvcore/HashMap.h b/thirdparty/thekla_atlas/nvcore/HashMap.h
new file mode 100644
index 0000000000..7856d6a8c9
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/HashMap.h
@@ -0,0 +1,174 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_HASHMAP_H
+#define NV_CORE_HASHMAP_H
+
+/*
+HashMap based on Thatcher Ulrich <tu@tulrich.com> container, donated to the Public Domain.
+
+I'd like to do something to reduce the amount of code generated with this template. The type of
+U is largely irrelevant to the generated code, except for calls to constructors and destructors,
+but the combination of all T and U pairs, generate a large amounts of code.
+
+HashMap is not used in NVTT, so it could be removed from the repository.
+*/
+
+
+#include "Memory.h"
+#include "Debug.h"
+#include "ForEach.h"
+#include "Hash.h"
+
+namespace nv
+{
+ class Stream;
+
+ /** Thatcher Ulrich's hash table.
+ *
+ * Hash table, linear probing, internal chaining. One
+ * interesting/nice thing about this implementation is that the table
+ * itself is a flat chunk of memory containing no pointers, only
+ * relative indices. If the key and value types of the hash contain
+ * no pointers, then the hash can be serialized using raw IO. Could
+ * come in handy.
+ *
+ * Never shrinks, unless you explicitly clear() it. Expands on
+ * demand, though. For best results, if you know roughly how big your
+ * table will be, default it to that size when you create it.
+ */
+ template<typename T, typename U, typename H = Hash<T>, typename E = Equal<T> >
+ class NVCORE_CLASS HashMap
+ {
+ NV_FORBID_COPY(HashMap);
+ public:
+
+ /// Default ctor.
+ HashMap() : entry_count(0), size_mask(-1), table(NULL) { }
+
+ /// Ctor with size hint.
+ explicit HashMap(int size_hint) : entry_count(0), size_mask(-1), table(NULL) { setCapacity(size_hint); }
+
+ /// Dtor.
+ ~HashMap() { clear(); }
+
+
+ void set(const T& key, const U& value);
+ void add(const T& key, const U& value);
+ bool remove(const T& key);
+ void clear();
+ bool isEmpty() const;
+ bool get(const T& key, U* value = NULL, T* other_key = NULL) const;
+ bool contains(const T & key) const;
+ int size() const;
+ int count() const;
+ int capacity() const;
+ void checkExpand();
+ void resize(int n);
+
+ void setCapacity(int new_size);
+
+ // Behaves much like std::pair.
+ struct Entry
+ {
+ int next_in_chain; // internal chaining for collisions
+ uint hash_value; // avoids recomputing. Worthwhile?
+ T key;
+ U value;
+
+ Entry() : next_in_chain(-2) {}
+ Entry(const Entry& e) : next_in_chain(e.next_in_chain), hash_value(e.hash_value), key(e.key), value(e.value) {}
+ Entry(const T& k, const U& v, int next, int hash) : next_in_chain(next), hash_value(hash), key(k), value(v) {}
+
+ bool isEmpty() const { return next_in_chain == -2; }
+ bool isEndOfChain() const { return next_in_chain == -1; }
+ bool isTombstone() const { return hash_value == TOMBSTONE_HASH; }
+
+ void clear() {
+ key.~T(); // placement delete
+ value.~U(); // placement delete
+ next_in_chain = -2;
+ hash_value = ~TOMBSTONE_HASH;
+ }
+
+ void makeTombstone() {
+ key.~T();
+ value.~U();
+ hash_value = TOMBSTONE_HASH;
+ }
+ };
+
+
+ // HashMap enumerator.
+ typedef int PseudoIndex;
+ PseudoIndex start() const { PseudoIndex i = 0; findNext(i); return i; }
+ bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); return i == size_mask+1; };
+ void advance(PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); i++; findNext(i); }
+
+#if NV_NEED_PSEUDOINDEX_WRAPPER
+ Entry & operator[]( const PseudoIndexWrapper & i ) {
+ Entry & e = entry(i(this));
+ nvDebugCheck(e.isTombstone() == false);
+ return e;
+ }
+ const Entry & operator[]( const PseudoIndexWrapper & i ) const {
+ const Entry & e = entry(i(this));
+ nvDebugCheck(e.isTombstone() == false);
+ return e;
+ }
+#else
+ Entry & operator[](const PseudoIndex & i) {
+ Entry & e = entry(i);
+ nvDebugCheck(e.isTombstone() == false);
+ return e;
+ }
+ const Entry & operator[](const PseudoIndex & i) const {
+ const Entry & e = entry(i);
+ nvDebugCheck(e.isTombstone() == false);
+ return e;
+ }
+#endif
+
+
+ // By default we serialize the key-value pairs compactl y.
+ template<typename _T, typename _U, typename _H, typename _E>
+ friend Stream & operator<< (Stream & s, HashMap<_T, _U, _H, _E> & map);
+
+ // This requires more storage, but saves us from rehashing the elements.
+ template<typename _T, typename _U, typename _H, typename _E>
+ friend Stream & rawSerialize(Stream & s, HashMap<_T, _U, _H, _E> & map);
+
+ /// Swap the members of this vector and the given vector.
+ template<typename _T, typename _U, typename _H, typename _E>
+ friend void swap(HashMap<_T, _U, _H, _E> & a, HashMap<_T, _U, _H, _E> & b);
+
+ private:
+ static const uint TOMBSTONE_HASH = (uint) -1;
+
+ uint compute_hash(const T& key) const;
+
+ // Find the index of the matching entry. If no match, then return -1.
+ int findIndex(const T& key) const;
+
+ // Return the index of the newly cleared element.
+ int removeTombstone(int index);
+
+ // Helpers.
+ Entry & entry(int index);
+ const Entry & entry(int index) const;
+
+ void setRawCapacity(int new_size);
+
+ // Move the enumerator to the next valid element.
+ void findNext(PseudoIndex & i) const;
+
+
+ int entry_count;
+ int size_mask;
+ Entry * table;
+
+ };
+
+} // nv namespace
+
+#endif // NV_CORE_HASHMAP_H
diff --git a/thirdparty/thekla_atlas/nvcore/HashMap.inl b/thirdparty/thekla_atlas/nvcore/HashMap.inl
new file mode 100644
index 0000000000..f0b6bfea62
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/HashMap.inl
@@ -0,0 +1,550 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_HASHMAP_INL
+#define NV_CORE_HASHMAP_INL
+
+#include "HashMap.h"
+
+#include "Stream.h"
+#include "Utils.h" // swap
+
+#include <new> // for placement new
+
+
+namespace nv
+{
+
+ // Set a new or existing value under the key, to the value.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::set(const T& key, const U& value)
+ {
+ int index = findIndex(key);
+ if (index >= 0)
+ {
+ entry(index).value = value;
+ return;
+ }
+
+ // Entry under key doesn't exist.
+ add(key, value);
+ }
+
+
+ // Add a new value to the hash table, under the specified key.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::add(const T& key, const U& value)
+ {
+ nvCheck(findIndex(key) == -1);
+
+ checkExpand();
+ nvCheck(table != NULL);
+ entry_count++;
+
+ const uint hash_value = compute_hash(key);
+ const int index = hash_value & size_mask;
+
+ Entry * natural_entry = &(entry(index));
+
+ if (natural_entry->isEmpty())
+ {
+ // Put the new entry in.
+ new (natural_entry) Entry(key, value, -1, hash_value);
+ }
+ else if (natural_entry->isTombstone()) {
+ // Put the new entry in, without disturbing the rest of the chain.
+ int next_in_chain = natural_entry->next_in_chain;
+ new (natural_entry) Entry(key, value, next_in_chain, hash_value);
+ }
+ else
+ {
+ // Find a blank spot.
+ int blank_index = index;
+ for (int search_count = 0; ; search_count++)
+ {
+ blank_index = (blank_index + 1) & size_mask;
+ if (entry(blank_index).isEmpty()) break; // found it
+ if (entry(blank_index).isTombstone()) {
+ blank_index = removeTombstone(blank_index);
+ break;
+ }
+ nvCheck(search_count < this->size_mask);
+ }
+ Entry * blank_entry = &entry(blank_index);
+
+ if (int(natural_entry->hash_value & size_mask) == index)
+ {
+ // Collision. Link into this chain.
+
+ // Move existing list head.
+ new (blank_entry) Entry(*natural_entry); // placement new, copy ctor
+
+ // Put the new info in the natural entry.
+ natural_entry->key = key;
+ natural_entry->value = value;
+ natural_entry->next_in_chain = blank_index;
+ natural_entry->hash_value = hash_value;
+ }
+ else
+ {
+ // Existing entry does not naturally
+ // belong in this slot. Existing
+ // entry must be moved.
+
+ // Find natural location of collided element (i.e. root of chain)
+ int collided_index = natural_entry->hash_value & size_mask;
+ for (int search_count = 0; ; search_count++)
+ {
+ Entry * e = &entry(collided_index);
+ if (e->next_in_chain == index)
+ {
+ // Here's where we need to splice.
+ new (blank_entry) Entry(*natural_entry);
+ e->next_in_chain = blank_index;
+ break;
+ }
+ collided_index = e->next_in_chain;
+ nvCheck(collided_index >= 0 && collided_index <= size_mask);
+ nvCheck(search_count <= size_mask);
+ }
+
+ // Put the new data in the natural entry.
+ natural_entry->key = key;
+ natural_entry->value = value;
+ natural_entry->hash_value = hash_value;
+ natural_entry->next_in_chain = -1;
+ }
+ }
+ }
+
+
+ // Remove the first value under the specified key.
+ template<typename T, typename U, typename H, typename E>
+ bool HashMap<T, U, H, E>::remove(const T& key)
+ {
+ if (table == NULL)
+ {
+ return false;
+ }
+
+ int index = findIndex(key);
+ if (index < 0)
+ {
+ return false;
+ }
+
+ Entry * pos = &entry(index);
+
+ int natural_index = (int) (pos->hash_value & size_mask);
+
+ if (index != natural_index) {
+ // We're not the head of our chain, so we can
+ // be spliced out of it.
+
+ // Iterate up the chain, and splice out when
+ // we get to m_index.
+ Entry* e = &entry(natural_index);
+ while (e->next_in_chain != index) {
+ nvDebugCheck(e->isEndOfChain() == false);
+ e = &entry(e->next_in_chain);
+ }
+
+ if (e->isTombstone() && pos->isEndOfChain()) {
+ // Tombstone has nothing else to point
+ // to, so mark it empty.
+ e->next_in_chain = -2;
+ } else {
+ e->next_in_chain = pos->next_in_chain;
+ }
+
+ pos->clear();
+ }
+ else if (pos->isEndOfChain() == false) {
+ // We're the head of our chain, and there are
+ // additional elements.
+ //
+ // We need to put a tombstone here.
+ //
+ // We can't clear the element, because the
+ // rest of the elements in the chain must be
+ // linked to this position.
+ //
+ // We can't move any of the succeeding
+ // elements in the chain (i.e. to fill this
+ // entry), because we don't want to invalidate
+ // any other existing iterators.
+ pos->makeTombstone();
+ } else {
+ // We're the head of the chain, but we're the
+ // only member of the chain.
+ pos->clear();
+ }
+
+ entry_count--;
+
+ return true;
+ }
+
+
+ // Remove all entries from the hash table.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::clear()
+ {
+ if (table != NULL)
+ {
+ // Delete the entries.
+ for (int i = 0, n = size_mask; i <= n; i++)
+ {
+ Entry * e = &entry(i);
+ if (e->isEmpty() == false && e->isTombstone() == false)
+ {
+ e->clear();
+ }
+ }
+ free(table);
+ table = NULL;
+ entry_count = 0;
+ size_mask = -1;
+ }
+ }
+
+
+ // Returns true if the hash is empty.
+ template<typename T, typename U, typename H, typename E>
+ bool HashMap<T, U, H, E>::isEmpty() const
+ {
+ return table == NULL || entry_count == 0;
+ }
+
+
+ // Retrieve the value under the given key.
+ // - If there's no value under the key, then return false and leave *value alone.
+ // - If there is a value, return true, and set *value to the entry's value.
+ // - If value == NULL, return true or false according to the presence of the key, but don't touch *value.
+ template<typename T, typename U, typename H, typename E>
+ bool HashMap<T, U, H, E>::get(const T& key, U* value/*= NULL*/, T* other_key/*= NULL*/) const
+ {
+ int index = findIndex(key);
+ if (index >= 0)
+ {
+ if (value != NULL) {
+ *value = entry(index).value; // take care with side-effects!
+ }
+ if (other_key != NULL) {
+ *other_key = entry(index).key;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // Determine if the given key is contained in the hash.
+ template<typename T, typename U, typename H, typename E>
+ bool HashMap<T, U, H, E>::contains(const T & key) const
+ {
+ return get(key);
+ }
+
+ // Number of entries in the hash.
+ template<typename T, typename U, typename H, typename E>
+ int HashMap<T, U, H, E>::size() const
+ {
+ return entry_count;
+ }
+
+ // Number of entries in the hash.
+ template<typename T, typename U, typename H, typename E>
+ int HashMap<T, U, H, E>::count() const
+ {
+ return size();
+ }
+
+ template<typename T, typename U, typename H, typename E>
+ int HashMap<T, U, H, E>::capacity() const
+ {
+ return size_mask+1;
+ }
+
+
+ // Resize the hash table to fit one more entry. Often this doesn't involve any action.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::checkExpand()
+ {
+ if (table == NULL) {
+ // Initial creation of table. Make a minimum-sized table.
+ setRawCapacity(16);
+ }
+ else if (entry_count * 3 > (size_mask + 1) * 2) {
+ // Table is more than 2/3rds full. Expand.
+ setRawCapacity(entry_count * 2);
+ }
+ }
+
+
+ // Hint the bucket count to >= n.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::resize(int n)
+ {
+ // Not really sure what this means in relation to
+ // STLport's hash_map... they say they "increase the
+ // bucket count to at least n" -- but does that mean
+ // their real capacity after resize(n) is more like
+ // n*2 (since they do linked-list chaining within
+ // buckets?).
+ setCapacity(n);
+ }
+
+
+ // Size the hash so that it can comfortably contain the given number of elements. If the hash already contains more
+ // elements than new_size, then this may be a no-op.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::setCapacity(int new_size)
+ {
+ int new_raw_size = (new_size * 3) / 2;
+ if (new_raw_size < size()) { return; }
+
+ setRawCapacity(new_raw_size);
+ }
+
+
+ // By default we serialize the key-value pairs compactly.
+ template<typename _T, typename _U, typename _H, typename _E>
+ Stream & operator<< (Stream & s, HashMap<_T, _U, _H, _E> & map)
+ {
+ typedef typename HashMap<_T, _U, _H, _E>::Entry HashMapEntry;
+
+ int entry_count = map.entry_count;
+ s << entry_count;
+
+ if (s.isLoading()) {
+ map.clear();
+ if(entry_count == 0) {
+ return s;
+ }
+ map.entry_count = entry_count;
+ map.size_mask = nextPowerOfTwo(U32(entry_count)) - 1;
+ map.table = malloc<HashMapEntry>(map.size_mask + 1);
+
+ for (int i = 0; i <= map.size_mask; i++) {
+ map.table[i].next_in_chain = -2; // mark empty
+ }
+
+ _T key;
+ _U value;
+ for (int i = 0; i < entry_count; i++) {
+ s << key << value;
+ map.add(key, value);
+ }
+ }
+ else {
+ int i = 0;
+ map.findNext(i);
+ while (i != map.size_mask+1) {
+ HashMapEntry & e = map.entry(i);
+
+ s << e.key << e.value;
+
+ i++;
+ map.findNext(i);
+ }
+ //for(HashMap<_T, _U, _H, _E>::PseudoIndex i((map).start()); !(map).isDone(i); (map).advance(i)) {
+ //foreach(i, map) {
+ // s << map[i].key << map[i].value;
+ //}
+ }
+
+ return s;
+ }
+
+ // This requires more storage, but saves us from rehashing the elements.
+ template<typename _T, typename _U, typename _H, typename _E>
+ Stream & rawSerialize(Stream & s, HashMap<_T, _U, _H, _E> & map)
+ {
+ typedef typename HashMap<_T, _U, _H, _E>::Entry HashMapEntry;
+
+ if (s.isLoading()) {
+ map.clear();
+ }
+
+ s << map.size_mask;
+
+ if (map.size_mask != -1) {
+ s << map.entry_count;
+
+ if (s.isLoading()) {
+ map.table = new HashMapEntry[map.size_mask+1];
+ }
+
+ for (int i = 0; i <= map.size_mask; i++) {
+ HashMapEntry & e = map.table[i];
+ s << e.next_in_chain << e.hash_value;
+ s << e.key;
+ s << e.value;
+ }
+ }
+
+ return s;
+ }
+
+ // Swap the members of this vector and the given vector.
+ template<typename _T, typename _U, typename _H, typename _E>
+ void swap(HashMap<_T, _U, _H, _E> & a, HashMap<_T, _U, _H, _E> & b)
+ {
+ swap(a.entry_count, b.entry_count);
+ swap(a.size_mask, b.size_mask);
+ swap(a.table, b.table);
+ }
+
+
+ template<typename T, typename U, typename H, typename E>
+ uint HashMap<T, U, H, E>::compute_hash(const T& key) const
+ {
+ H hash;
+ uint hash_value = hash(key);
+ if (hash_value == TOMBSTONE_HASH) {
+ hash_value ^= 0x8000;
+ }
+ return hash_value;
+ }
+
+ // Find the index of the matching entry. If no match, then return -1.
+ template<typename T, typename U, typename H, typename E>
+ int HashMap<T, U, H, E>::findIndex(const T& key) const
+ {
+ if (table == NULL) return -1;
+
+ E equal;
+
+ uint hash_value = compute_hash(key);
+ int index = hash_value & size_mask;
+
+ const Entry * e = &entry(index);
+ if (e->isEmpty()) return -1;
+ if (e->isTombstone() == false && int(e->hash_value & size_mask) != index) {
+ // occupied by a collider
+ return -1;
+ }
+
+ for (;;)
+ {
+ nvCheck(e->isTombstone() || (e->hash_value & size_mask) == (hash_value & size_mask));
+
+ if (e->hash_value == hash_value && equal(e->key, key))
+ {
+ // Found it.
+ return index;
+ }
+ nvDebugCheck(e->isTombstone() || !equal(e->key, key)); // keys are equal, but hash differs!
+
+ // Keep looking through the chain.
+ index = e->next_in_chain;
+ if (index == -1) break; // end of chain
+
+ nvCheck(index >= 0 && index <= size_mask);
+ e = &entry(index);
+
+ nvCheck(e->isEmpty() == false || e->isTombstone());
+ }
+ return -1;
+ }
+
+ // Return the index of the newly cleared element.
+ template<typename T, typename U, typename H, typename E>
+ int HashMap<T, U, H, E>::removeTombstone(int index) {
+ Entry* e = &entry(index);
+ nvCheck(e->isTombstone());
+ nvCheck(!e->isEndOfChain());
+
+ // Move the next element of the chain into the
+ // tombstone slot, and return the vacated element.
+ int new_blank_index = e->next_in_chain;
+ Entry* new_blank = &entry(new_blank_index);
+ new (e) Entry(*new_blank);
+ new_blank->clear();
+ return new_blank_index;
+ }
+
+ // Helpers.
+ template<typename T, typename U, typename H, typename E>
+ typename HashMap<T, U, H, E>::Entry & HashMap<T, U, H, E>::entry(int index)
+ {
+ nvDebugCheck(table != NULL);
+ nvDebugCheck(index >= 0 && index <= size_mask);
+ return table[index];
+ }
+ template<typename T, typename U, typename H, typename E>
+ const typename HashMap<T, U, H, E>::Entry & HashMap<T, U, H, E>::entry(int index) const
+ {
+ nvDebugCheck(table != NULL);
+ nvDebugCheck(index >= 0 && index <= size_mask);
+ return table[index];
+ }
+
+
+ // Resize the hash table to the given size (Rehash the contents of the current table). The arg is the number of
+ // hash table entries, not the number of elements we should actually contain (which will be less than this).
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::setRawCapacity(int new_size)
+ {
+ if (new_size <= 0) {
+ // Special case.
+ clear();
+ return;
+ }
+
+ // Force new_size to be a power of two.
+ new_size = nextPowerOfTwo(U32(new_size));
+
+ HashMap<T, U, H, E> new_hash;
+ new_hash.table = malloc<Entry>(new_size);
+ nvDebugCheck(new_hash.table != NULL);
+
+ new_hash.entry_count = 0;
+ new_hash.size_mask = new_size - 1;
+ for (int i = 0; i < new_size; i++)
+ {
+ new_hash.entry(i).next_in_chain = -2; // mark empty
+ }
+
+ // Copy stuff to new_hash
+ if (table != NULL)
+ {
+ for (int i = 0, n = size_mask; i <= n; i++)
+ {
+ Entry * e = &entry(i);
+ if (e->isEmpty() == false && e->isTombstone() == false)
+ {
+ // Insert old entry into new hash.
+ new_hash.add(e->key, e->value);
+ e->clear(); // placement delete of old element
+ }
+ }
+
+ // Delete our old data buffer.
+ free(table);
+ }
+
+ // Steal new_hash's data.
+ entry_count = new_hash.entry_count;
+ size_mask = new_hash.size_mask;
+ table = new_hash.table;
+ new_hash.entry_count = 0;
+ new_hash.size_mask = -1;
+ new_hash.table = NULL;
+ }
+
+ // Move the enumerator to the next valid element.
+ template<typename T, typename U, typename H, typename E>
+ void HashMap<T, U, H, E>::findNext(PseudoIndex & i) const {
+ while (i <= size_mask) {
+ const Entry & e = entry(i);
+ if (e.isEmpty() == false && e.isTombstone() == false) {
+ break;
+ }
+ i++;
+ }
+ }
+
+} // nv namespace
+
+#endif // NV_CORE_HASHMAP_INL
diff --git a/thirdparty/thekla_atlas/nvcore/Memory.cpp b/thirdparty/thekla_atlas/nvcore/Memory.cpp
new file mode 100644
index 0000000000..302a2d84cb
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Memory.cpp
@@ -0,0 +1,153 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#include "Memory.h"
+#include "Debug.h"
+#include "Utils.h"
+
+#include <stdlib.h>
+
+#ifdef NV_OS_LINUX
+#include <malloc.h>
+#endif
+
+#define USE_EFENCE 0
+
+#if USE_EFENCE
+extern "C" void *EF_malloc(size_t size);
+extern "C" void *EF_realloc(void * oldBuffer, size_t newSize);
+extern "C" void EF_free(void * address);
+#endif
+
+using namespace nv;
+
+#if NV_OVERRIDE_ALLOC
+
+void * malloc(size_t size)
+{
+#if USE_EFENCE
+ return EF_malloc(size);
+#else
+ return ::malloc(size);
+#endif
+}
+
+void * debug_malloc(size_t size, const char * file, int line)
+{
+ NV_UNUSED(file);
+ NV_UNUSED(line);
+#if USE_EFENCE
+ return EF_malloc(size);
+#else
+ return ::malloc(size);
+#endif
+}
+
+void free(void * ptr)
+{
+#if USE_EFENCE
+ return EF_free(const_cast<void *>(ptr));
+#else
+ ::free(const_cast<void *>(ptr));
+#endif
+}
+
+void * realloc(void * ptr, size_t size)
+{
+ nvDebugCheck(ptr != NULL || size != 0); // undefined realloc behavior.
+#if USE_EFENCE
+ return EF_realloc(ptr, size);
+#else
+ return ::realloc(ptr, size);
+#endif
+}
+
+
+/* No need to override this unless we want line info.
+void * operator new (size_t size) throw()
+{
+ return malloc(size);
+}
+
+void operator delete (void *p) throw()
+{
+ free(p);
+}
+
+void * operator new [] (size_t size) throw()
+{
+ return malloc(size);
+}
+
+void operator delete [] (void * p) throw()
+{
+ free(p);
+}
+*/
+
+#if 0 // Code from Apple:
+void* operator new(std::size_t sz) throw (std::bad_alloc)
+{
+ void *result = std::malloc (sz == 0 ? 1 : sz);
+ if (result == NULL)
+ throw std::bad_alloc();
+ gNewCounter++;
+ return result;
+}
+void operator delete(void* p) throw()
+{
+ if (p == NULL)
+ return;
+ std::free (p);
+ gDeleteCounter++;
+}
+
+/* These are the 'nothrow' versions of the above operators.
+ The system version will try to call a std::new_handler if they
+ fail, but your overriding versions are not required to do this. */
+void* operator new(std::size_t sz, const std::nothrow_t&) throw()
+{
+ try {
+ void * result = ::operator new (sz); // calls our overridden operator new
+ return result;
+ } catch (std::bad_alloc &) {
+ return NULL;
+ }
+}
+void operator delete(void* p, const std::nothrow_t&) throw()
+{
+ ::operator delete (p);
+}
+
+#endif // 0
+
+#endif // NV_OVERRIDE_ALLOC
+
+void * nv::aligned_malloc(size_t size, size_t alignment)
+{
+ // alignment must be a power of two, multiple of sizeof(void*)
+ nvDebugCheck(isPowerOfTwo(alignment));
+ nvDebugCheck((alignment & (sizeof(void*) - 1)) == 0);
+
+#if NV_OS_WIN32 || NV_OS_DURANGO
+ return _aligned_malloc(size, alignment);
+#elif NV_OS_DARWIN && !NV_OS_IOS
+ void * ptr = NULL;
+ posix_memalign(&ptr, alignment, size);
+ return ptr;
+#elif NV_OS_LINUX
+ return memalign(alignment, size);
+#else // NV_OS_ORBIS || NV_OS_IOS
+ // @@ IC: iOS appears to be 16 byte aligned, should we check alignment and assert if we request a higher alignment factor?
+ return ::malloc(size);
+#endif
+}
+
+void nv::aligned_free(void * ptr)
+{
+#if NV_OS_WIN32 || NV_OS_DURANGO
+ _aligned_free(ptr);
+#else
+ ::free(ptr);
+#endif
+}
+
diff --git a/thirdparty/thekla_atlas/nvcore/Memory.h b/thirdparty/thekla_atlas/nvcore/Memory.h
new file mode 100644
index 0000000000..1f71b60947
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Memory.h
@@ -0,0 +1,72 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_MEMORY_H
+#define NV_CORE_MEMORY_H
+
+#include "nvcore.h"
+
+#include <stdlib.h> // malloc(), realloc() and free()
+#include <string.h> // memset
+//#include <stddef.h> // size_t
+
+//#include <new> // new and delete
+
+#define TRACK_MEMORY_LEAKS 0
+#if TRACK_MEMORY_LEAKS
+#include <vld.h>
+#endif
+
+
+#if NV_CC_GNUC
+# define NV_ALIGN_16 __attribute__ ((__aligned__ (16)))
+#else
+# define NV_ALIGN_16 __declspec(align(16))
+#endif
+
+
+#define NV_OVERRIDE_ALLOC 0
+
+#if NV_OVERRIDE_ALLOC
+
+// Custom memory allocator
+extern "C" {
+ NVCORE_API void * malloc(size_t size);
+ NVCORE_API void * debug_malloc(size_t size, const char * file, int line);
+ NVCORE_API void free(void * ptr);
+ NVCORE_API void * realloc(void * ptr, size_t size);
+}
+
+/*
+#ifdef _DEBUG
+#define new new(__FILE__, __LINE__)
+#define malloc(i) debug_malloc(i, __FILE__, __LINE__)
+#endif
+*/
+
+#endif
+
+namespace nv {
+ NVCORE_API void * aligned_malloc(size_t size, size_t alignment);
+ NVCORE_API void aligned_free(void * );
+
+ // C++ helpers.
+ template <typename T> NV_FORCEINLINE T * malloc(size_t count) {
+ return (T *)::malloc(sizeof(T) * count);
+ }
+
+ template <typename T> NV_FORCEINLINE T * realloc(T * ptr, size_t count) {
+ return (T *)::realloc(ptr, sizeof(T) * count);
+ }
+
+ template <typename T> NV_FORCEINLINE void free(const T * ptr) {
+ ::free((void *)ptr);
+ }
+
+ template <typename T> NV_FORCEINLINE void zero(T & data) {
+ memset(&data, 0, sizeof(T));
+ }
+
+} // nv namespace
+
+#endif // NV_CORE_MEMORY_H
diff --git a/thirdparty/thekla_atlas/nvcore/Ptr.h b/thirdparty/thekla_atlas/nvcore/Ptr.h
new file mode 100644
index 0000000000..b43039274b
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Ptr.h
@@ -0,0 +1,322 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#ifndef NV_CORE_PTR_H
+#define NV_CORE_PTR_H
+
+#include "nvcore.h"
+#include "Debug.h"
+
+#include "RefCounted.h"
+
+namespace nv
+{
+ class WeakProxy;
+
+ /** Simple auto pointer template class.
+ *
+ * This is very similar to the standard auto_ptr class, but with some
+ * additional limitations to make its use less error prone:
+ * - Copy constructor and assignment operator are disabled.
+ * - reset method is removed.
+ *
+ * The semantics of the standard auto_ptr are not clear and change depending
+ * on the std implementation. For a discussion of the problems of auto_ptr read:
+ * http://www.awprofessional.com/content/images/020163371X/autoptrupdate\auto_ptr_update.html
+ */
+ template <class T>
+ class AutoPtr
+ {
+ NV_FORBID_COPY(AutoPtr);
+ NV_FORBID_HEAPALLOC();
+ public:
+
+ /// Ctor.
+ AutoPtr(T * p = NULL) : m_ptr(p) { }
+
+ template <class Q>
+ AutoPtr(Q * p) : m_ptr(static_cast<T *>(p)) { }
+
+ /// Dtor. Deletes owned pointer.
+ ~AutoPtr() {
+ delete m_ptr;
+ m_ptr = NULL;
+ }
+
+ /// Delete owned pointer and assign new one.
+ void operator=( T * p ) {
+ if (p != m_ptr)
+ {
+ delete m_ptr;
+ m_ptr = p;
+ }
+ }
+
+ template <class Q>
+ void operator=( Q * p ) {
+ if (p != m_ptr)
+ {
+ delete m_ptr;
+ m_ptr = static_cast<T *>(p);
+ }
+ }
+
+ /// Member access.
+ T * operator -> () const {
+ nvDebugCheck(m_ptr != NULL);
+ return m_ptr;
+ }
+
+ /// Get reference.
+ T & operator*() const {
+ nvDebugCheck(m_ptr != NULL);
+ return *m_ptr;
+ }
+
+ /// Get pointer.
+ T * ptr() const { return m_ptr; }
+
+ /// Relinquish ownership of the underlying pointer and returns that pointer.
+ T * release() {
+ T * tmp = m_ptr;
+ m_ptr = NULL;
+ return tmp;
+ }
+
+ /// Const pointer equal comparation.
+ friend bool operator == (const AutoPtr<T> & ap, const T * const p) {
+ return (ap.ptr() == p);
+ }
+
+ /// Const pointer nequal comparation.
+ friend bool operator != (const AutoPtr<T> & ap, const T * const p) {
+ return (ap.ptr() != p);
+ }
+
+ /// Const pointer equal comparation.
+ friend bool operator == (const T * const p, const AutoPtr<T> & ap) {
+ return (ap.ptr() == p);
+ }
+
+ /// Const pointer nequal comparation.
+ friend bool operator != (const T * const p, const AutoPtr<T> & ap) {
+ return (ap.ptr() != p);
+ }
+
+ private:
+ T * m_ptr;
+ };
+
+
+ /// Smart pointer template class.
+ template <class BaseClass>
+ class SmartPtr {
+ public:
+
+ // BaseClass must implement addRef() and release().
+ typedef SmartPtr<BaseClass> ThisType;
+
+ /// Default ctor.
+ SmartPtr() : m_ptr(NULL)
+ {
+ }
+
+ /// Other type assignment.
+ template <class OtherBase>
+ SmartPtr( const SmartPtr<OtherBase> & tc )
+ {
+ m_ptr = static_cast<BaseClass *>( tc.ptr() );
+ if (m_ptr) {
+ m_ptr->addRef();
+ }
+ }
+
+ /// Copy ctor.
+ SmartPtr( const ThisType & bc )
+ {
+ m_ptr = bc.ptr();
+ if (m_ptr) {
+ m_ptr->addRef();
+ }
+ }
+
+ /// Copy cast ctor. SmartPtr(NULL) is valid.
+ explicit SmartPtr( BaseClass * bc )
+ {
+ m_ptr = bc;
+ if (m_ptr) {
+ m_ptr->addRef();
+ }
+ }
+
+ /// Dtor.
+ ~SmartPtr()
+ {
+ set(NULL);
+ }
+
+
+ /// -> operator.
+ BaseClass * operator -> () const
+ {
+ nvCheck( m_ptr != NULL );
+ return m_ptr;
+ }
+
+ /// * operator.
+ BaseClass & operator*() const
+ {
+ nvCheck( m_ptr != NULL );
+ return *m_ptr;
+ }
+
+ /// Get pointer.
+ BaseClass * ptr() const
+ {
+ return m_ptr;
+ }
+
+ /// Other type assignment.
+ template <class OtherBase>
+ void operator = ( const SmartPtr<OtherBase> & tc )
+ {
+ set( static_cast<BaseClass *>(tc.ptr()) );
+ }
+
+ /// This type assignment.
+ void operator = ( const ThisType & bc )
+ {
+ set( bc.ptr() );
+ }
+
+ /// Pointer assignment.
+ void operator = ( BaseClass * bc )
+ {
+ set( bc );
+ }
+
+
+ /// Other type equal comparation.
+ template <class OtherBase>
+ bool operator == ( const SmartPtr<OtherBase> & other ) const
+ {
+ return m_ptr == other.ptr();
+ }
+
+ /// This type equal comparation.
+ bool operator == ( const ThisType & bc ) const
+ {
+ return m_ptr == bc.ptr();
+ }
+
+ /// Const pointer equal comparation.
+ bool operator == ( const BaseClass * const bc ) const
+ {
+ return m_ptr == bc;
+ }
+
+ /// Other type not equal comparation.
+ template <class OtherBase>
+ bool operator != ( const SmartPtr<OtherBase> & other ) const
+ {
+ return m_ptr != other.ptr();
+ }
+
+ /// Other type not equal comparation.
+ bool operator != ( const ThisType & bc ) const
+ {
+ return m_ptr != bc.ptr();
+ }
+
+ /// Const pointer not equal comparation.
+ bool operator != (const BaseClass * const bc) const
+ {
+ return m_ptr != bc;
+ }
+
+ /// This type lower than comparation.
+ bool operator < (const ThisType & p) const
+ {
+ return m_ptr < p.ptr();
+ }
+
+ bool isValid() const {
+ return isValidPtr(m_ptr);
+ }
+
+ private:
+
+ // Set this pointer.
+ void set( BaseClass * p )
+ {
+ if (p) p->addRef();
+ if (m_ptr) m_ptr->release();
+ m_ptr = p;
+ }
+
+ private:
+
+ BaseClass * m_ptr;
+
+ };
+
+
+ /// Smart pointer template class.
+ template <class T>
+ class WeakPtr {
+ public:
+
+ WeakPtr() {}
+
+ WeakPtr(T * p) { operator=(p); }
+ WeakPtr(const SmartPtr<T> & p) { operator=(p.ptr()); }
+
+ // Default constructor and assignment from weak_ptr<T> are OK.
+
+ void operator=(T * p)
+ {
+ if (p) {
+ m_proxy = p->getWeakProxy();
+ nvDebugCheck(m_proxy != NULL);
+ nvDebugCheck(m_proxy->ptr() == p);
+ }
+ else {
+ m_proxy = NULL;
+ }
+ }
+
+ void operator=(const SmartPtr<T> & ptr) { operator=(ptr.ptr()); }
+
+ bool operator==(const SmartPtr<T> & p) const { return ptr() == p.ptr(); }
+ bool operator!=(const SmartPtr<T> & p) const { return ptr() != p.ptr(); }
+
+ bool operator==(const WeakPtr<T> & p) const { return ptr() == p.ptr(); }
+ bool operator!=(const WeakPtr<T> & p) const { return ptr() != p.ptr(); }
+
+ bool operator==(T * p) const { return ptr() == p; }
+ bool operator!=(T * p) const { return ptr() != p; }
+
+ T * operator->() const
+ {
+ T * p = ptr();
+ nvDebugCheck(p != NULL);
+ return p;
+ }
+
+ T * ptr() const
+ {
+ if (m_proxy != NULL) {
+ return static_cast<T *>(m_proxy->ptr());
+ }
+ return NULL;
+ }
+
+ private:
+
+ mutable SmartPtr<WeakProxy> m_proxy;
+
+ };
+
+
+} // nv namespace
+
+#endif // NV_CORE_PTR_H
diff --git a/thirdparty/thekla_atlas/nvcore/RadixSort.cpp b/thirdparty/thekla_atlas/nvcore/RadixSort.cpp
new file mode 100644
index 0000000000..3f44620c99
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/RadixSort.cpp
@@ -0,0 +1,285 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#include "RadixSort.h"
+
+#include "Utils.h"
+
+#include <string.h> // memset
+
+using namespace nv;
+
+static inline void FloatFlip(uint32 & f) {
+ //uint32 mask = -int32(f >> 31) | 0x80000000; // Michael Herf.
+ int32 mask = (int32(f) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko.
+ f ^= mask;
+}
+
+static inline void IFloatFlip(uint32 & f) {
+ uint32 mask = ((f >> 31) - 1) | 0x80000000; // Michael Herf.
+ //uint32 mask = (int32(f ^ 0x80000000) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko. @@ Correct, but fails in release on gcc-4.2.1
+ f ^= mask;
+}
+
+
+template<typename T>
+void createHistograms(const T * buffer, uint count, uint * histogram)
+{
+ const uint bucketCount = sizeof(T); // (8 * sizeof(T)) / log2(radix)
+
+ // Init bucket pointers.
+ uint * h[bucketCount];
+ for (uint i = 0; i < bucketCount; i++) {
+#if NV_BIG_ENDIAN
+ h[sizeof(T)-1-i] = histogram + 256 * i;
+#else
+ h[i] = histogram + 256 * i;
+#endif
+ }
+
+ // Clear histograms.
+ memset(histogram, 0, 256 * bucketCount * sizeof(uint));
+
+ // @@ Add support for signed integers.
+
+ // Build histograms.
+ const uint8 * p = (const uint8 *)buffer; // @@ Does this break aliasing rules?
+ const uint8 * pe = p + count * sizeof(T);
+
+ while (p != pe) {
+ h[0][*p++]++, h[1][*p++]++, h[2][*p++]++, h[3][*p++]++;
+ if (bucketCount == 8) h[4][*p++]++, h[5][*p++]++, h[6][*p++]++, h[7][*p++]++;
+ }
+}
+
+/*
+template <>
+void createHistograms<float>(const float * buffer, uint count, uint * histogram)
+{
+ // Init bucket pointers.
+ uint32 * h[4];
+ for (uint i = 0; i < 4; i++) {
+#if NV_BIG_ENDIAN
+ h[3-i] = histogram + 256 * i;
+#else
+ h[i] = histogram + 256 * i;
+#endif
+ }
+
+ // Clear histograms.
+ memset(histogram, 0, 256 * 4 * sizeof(uint32));
+
+ // Build histograms.
+ for (uint i = 0; i < count; i++) {
+ uint32 fi = FloatFlip(buffer[i]);
+
+ h[0][fi & 0xFF]++;
+ h[1][(fi >> 8) & 0xFF]++;
+ h[2][(fi >> 16) & 0xFF]++;
+ h[3][fi >> 24]++;
+ }
+}
+*/
+
+RadixSort::RadixSort() : m_size(0), m_ranks(NULL), m_ranks2(NULL), m_validRanks(false)
+{
+}
+
+RadixSort::RadixSort(uint reserve_count) : m_size(0), m_ranks(NULL), m_ranks2(NULL), m_validRanks(false)
+{
+ checkResize(reserve_count);
+}
+
+RadixSort::~RadixSort()
+{
+ // Release everything
+ free(m_ranks2);
+ free(m_ranks);
+}
+
+
+void RadixSort::resize(uint count)
+{
+ m_ranks2 = realloc<uint>(m_ranks2, count);
+ m_ranks = realloc<uint>(m_ranks, count);
+}
+
+inline void RadixSort::checkResize(uint count)
+{
+ if (count != m_size)
+ {
+ if (count > m_size) resize(count);
+ m_size = count;
+ m_validRanks = false;
+ }
+}
+
+template <typename T> inline void RadixSort::insertionSort(const T * input, uint count)
+{
+ if (!m_validRanks) {
+ /*for (uint i = 0; i < count; i++) {
+ m_ranks[i] = i;
+ }*/
+
+ m_ranks[0] = 0;
+ for (uint i = 1; i != count; ++i)
+ {
+ int rank = m_ranks[i] = i;
+
+ uint j = i;
+ while (j != 0 && input[rank] < input[m_ranks[j-1]])
+ {
+ m_ranks[j] = m_ranks[j-1];
+ --j;
+ }
+ if (i != j)
+ {
+ m_ranks[j] = rank;
+ }
+ }
+
+ m_validRanks = true;
+ }
+ else {
+ for (uint i = 1; i != count; ++i)
+ {
+ int rank = m_ranks[i];
+
+ uint j = i;
+ while (j != 0 && input[rank] < input[m_ranks[j-1]])
+ {
+ m_ranks[j] = m_ranks[j-1];
+ --j;
+ }
+ if (i != j)
+ {
+ m_ranks[j] = rank;
+ }
+ }
+ }
+}
+
+template <typename T> inline void RadixSort::radixSort(const T * input, uint count)
+{
+ const uint P = sizeof(T); // pass count
+
+ // Allocate histograms & offsets on the stack
+ uint histogram[256 * P];
+ uint * link[256];
+
+ createHistograms(input, count, histogram);
+
+ // Radix sort, j is the pass number (0=LSB, P=MSB)
+ for (uint j = 0; j < P; j++)
+ {
+ // Pointer to this bucket.
+ const uint * h = &histogram[j * 256];
+
+ const uint8 * inputBytes = (const uint8*)input; // @@ Is this aliasing legal?
+
+#if NV_BIG_ENDIAN
+ inputBytes += P - 1 - j;
+#else
+ inputBytes += j;
+#endif
+
+ if (h[inputBytes[0]] == count) {
+ // Skip this pass, all values are the same.
+ continue;
+ }
+
+ // Create offsets
+ link[0] = m_ranks2;
+ for (uint i = 1; i < 256; i++) link[i] = link[i-1] + h[i-1];
+
+ // Perform Radix Sort
+ if (!m_validRanks)
+ {
+ for (uint i = 0; i < count; i++)
+ {
+ *link[inputBytes[i*P]]++ = i;
+ }
+ m_validRanks = true;
+ }
+ else
+ {
+ for (uint i = 0; i < count; i++)
+ {
+ const uint idx = m_ranks[i];
+ *link[inputBytes[idx*P]]++ = idx;
+ }
+ }
+
+ // Swap pointers for next pass. Valid indices - the most recent ones - are in m_ranks after the swap.
+ swap(m_ranks, m_ranks2);
+ }
+
+ // All values were equal, generate linear ranks.
+ if (!m_validRanks)
+ {
+ for (uint i = 0; i < count; i++)
+ {
+ m_ranks[i] = i;
+ }
+ m_validRanks = true;
+ }
+}
+
+
+RadixSort & RadixSort::sort(const uint32 * input, uint count)
+{
+ if (input == NULL || count == 0) return *this;
+
+ // Resize lists if needed
+ checkResize(count);
+
+ if (count < 32) {
+ insertionSort(input, count);
+ }
+ else {
+ radixSort<uint32>(input, count);
+ }
+ return *this;
+}
+
+
+RadixSort & RadixSort::sort(const uint64 * input, uint count)
+{
+ if (input == NULL || count == 0) return *this;
+
+ // Resize lists if needed
+ checkResize(count);
+
+ if (count < 64) {
+ insertionSort(input, count);
+ }
+ else {
+ radixSort(input, count);
+ }
+ return *this;
+}
+
+RadixSort& RadixSort::sort(const float * input, uint count)
+{
+ if (input == NULL || count == 0) return *this;
+
+ // Resize lists if needed
+ checkResize(count);
+
+ if (count < 32) {
+ insertionSort(input, count);
+ }
+ else {
+ // @@ Avoid touching the input multiple times.
+ for (uint i = 0; i < count; i++) {
+ FloatFlip((uint32 &)input[i]);
+ }
+
+ radixSort<uint32>((const uint32 *)input, count);
+
+ for (uint i = 0; i < count; i++) {
+ IFloatFlip((uint32 &)input[i]);
+ }
+ }
+
+ return *this;
+}
diff --git a/thirdparty/thekla_atlas/nvcore/RadixSort.h b/thirdparty/thekla_atlas/nvcore/RadixSort.h
new file mode 100644
index 0000000000..82325ebb24
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/RadixSort.h
@@ -0,0 +1,75 @@
+#pragma once
+#ifndef NV_CORE_RADIXSORT_H
+#define NV_CORE_RADIXSORT_H
+
+// Based on Pierre Terdiman's and Michael Herf's source code.
+// http://www.codercorner.com/RadixSortRevisited.htm
+// http://www.stereopsis.com/radix.html
+
+#include "nvcore.h"
+#include "Array.h"
+
+namespace nv
+{
+
+ class NVCORE_CLASS RadixSort
+ {
+ NV_FORBID_COPY(RadixSort);
+ public:
+ // Constructor/Destructor
+ RadixSort();
+ RadixSort(uint reserve_count);
+ ~RadixSort();
+
+ // Invalidate ranks.
+ RadixSort & reset() { m_validRanks = false; return *this; }
+
+ // Sorting methods.
+ RadixSort & sort(const uint32 * input, uint count);
+ RadixSort & sort(const uint64 * input, uint count);
+ RadixSort & sort(const float * input, uint count);
+
+ // Helpers.
+ RadixSort & sort(const Array<uint32> & input);
+ RadixSort & sort(const Array<uint64> & input);
+ RadixSort & sort(const Array<float> & input);
+
+ // Access to results. m_ranks is a list of indices in sorted order, i.e. in the order you may further process your data
+ inline const uint * ranks() const { nvDebugCheck(m_validRanks); return m_ranks; }
+ inline uint * ranks() { nvDebugCheck(m_validRanks); return m_ranks; }
+ inline uint rank(uint i) const { nvDebugCheck(m_validRanks); return m_ranks[i]; }
+
+ // query whether the sort has been performed
+ inline bool valid() const { return m_validRanks; }
+
+ private:
+ uint m_size;
+ uint * m_ranks;
+ uint * m_ranks2;
+ bool m_validRanks;
+
+ // Internal methods
+ template <typename T> void insertionSort(const T * input, uint count);
+ template <typename T> void radixSort(const T * input, uint count);
+
+ void checkResize(uint nb);
+ void resize(uint nb);
+ };
+
+ inline RadixSort & RadixSort::sort(const Array<uint32> & input) {
+ return sort(input.buffer(), input.count());
+ }
+
+ inline RadixSort & RadixSort::sort(const Array<uint64> & input) {
+ return sort(input.buffer(), input.count());
+ }
+
+ inline RadixSort & RadixSort::sort(const Array<float> & input) {
+ return sort(input.buffer(), input.count());
+ }
+
+} // nv namespace
+
+
+
+#endif // NV_CORE_RADIXSORT_H
diff --git a/thirdparty/thekla_atlas/nvcore/RefCounted.h b/thirdparty/thekla_atlas/nvcore/RefCounted.h
new file mode 100644
index 0000000000..b8d68edee3
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/RefCounted.h
@@ -0,0 +1,149 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#ifndef NV_CORE_REFCOUNTED_H
+#define NV_CORE_REFCOUNTED_H
+
+#include "nvcore.h"
+#include "Debug.h"
+
+#define NV_DECLARE_PTR(Class) \
+ template <class T> class SmartPtr; \
+ typedef SmartPtr<class Class> Class ## Ptr; \
+ typedef SmartPtr<const class Class> Class ## ConstPtr
+
+
+namespace nv
+{
+ /// Weak proxy.
+ class WeakProxy
+ {
+ NV_FORBID_COPY(WeakProxy);
+ public:
+ /// Ctor.
+ WeakProxy(void * ptr) : m_count(0), m_ptr(ptr) { }
+
+ /// Dtor.
+ ~WeakProxy()
+ {
+ nvCheck( m_count == 0 );
+ }
+
+ /// Increase reference count.
+ uint addRef() const
+ {
+ m_count++;
+ return m_count;
+ }
+
+ /// Decrease reference count and remove when 0.
+ uint release() const
+ {
+ nvCheck( m_count > 0 );
+
+ m_count--;
+ if( m_count == 0 ) {
+ delete this;
+ return 0;
+ }
+ return m_count;
+ }
+
+ /// WeakPtr's call this to determine if their pointer is valid or not.
+ bool isAlive() const {
+ return m_ptr != NULL;
+ }
+
+ /// Only the actual object should call this.
+ void notifyObjectDied() {
+ m_ptr = NULL;
+ }
+
+ /// Return proxy pointer.
+ void * ptr() const {
+ return m_ptr;
+ }
+
+ private:
+ mutable int m_count;
+ void * m_ptr;
+ };
+
+
+ /// Reference counted base class to be used with SmartPtr and WeakPtr.
+ class RefCounted
+ {
+ NV_FORBID_COPY(RefCounted);
+ public:
+
+ /// Ctor.
+ RefCounted() : m_count(0), m_weak_proxy(NULL)
+ {
+ }
+
+ /// Virtual dtor.
+ virtual ~RefCounted()
+ {
+ nvCheck( m_count == 0 );
+ releaseWeakProxy();
+ }
+
+
+ /// Increase reference count.
+ uint addRef() const
+ {
+ m_count++;
+ return m_count;
+ }
+
+
+ /// Decrease reference count and remove when 0.
+ uint release() const
+ {
+ nvCheck( m_count > 0 );
+
+ m_count--;
+ if( m_count == 0 ) {
+ delete this;
+ return 0;
+ }
+ return m_count;
+ }
+
+ /// Get weak proxy.
+ WeakProxy * getWeakProxy() const
+ {
+ if (m_weak_proxy == NULL) {
+ m_weak_proxy = new WeakProxy((void *)this);
+ m_weak_proxy->addRef();
+ }
+ return m_weak_proxy;
+ }
+
+ /// Release the weak proxy.
+ void releaseWeakProxy() const
+ {
+ if (m_weak_proxy != NULL) {
+ m_weak_proxy->notifyObjectDied();
+ m_weak_proxy->release();
+ m_weak_proxy = NULL;
+ }
+ }
+
+ /// Get reference count.
+ int refCount() const
+ {
+ return m_count;
+ }
+
+
+ private:
+
+ mutable int m_count;
+ mutable WeakProxy * m_weak_proxy;
+
+ };
+
+} // nv namespace
+
+
+#endif // NV_CORE_REFCOUNTED_H
diff --git a/thirdparty/thekla_atlas/nvcore/StdStream.h b/thirdparty/thekla_atlas/nvcore/StdStream.h
new file mode 100644
index 0000000000..f65d6dab59
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/StdStream.h
@@ -0,0 +1,474 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+//#pragma once
+//#ifndef NV_CORE_STDSTREAM_H
+//#define NV_CORE_STDSTREAM_H
+
+#include "nvcore.h"
+#include "Stream.h"
+#include "Array.h"
+
+#include <stdio.h> // fopen
+#include <string.h> // memcpy
+
+namespace nv
+{
+
+ // Portable version of fopen.
+ inline FILE * fileOpen(const char * fileName, const char * mode)
+ {
+ nvCheck(fileName != NULL);
+#if NV_CC_MSVC && _MSC_VER >= 1400
+ FILE * fp;
+ if (fopen_s(&fp, fileName, mode) == 0) {
+ return fp;
+ }
+ return NULL;
+#else
+ return fopen(fileName, mode);
+#endif
+ }
+
+
+ /// Base stdio stream.
+ class NVCORE_CLASS StdStream : public Stream
+ {
+ NV_FORBID_COPY(StdStream);
+ public:
+
+ /// Ctor.
+ StdStream( FILE * fp, bool autoclose ) : m_fp(fp), m_autoclose(autoclose) { }
+
+ /// Dtor.
+ virtual ~StdStream()
+ {
+ if( m_fp != NULL && m_autoclose ) {
+#if NV_OS_WIN32
+ _fclose_nolock( m_fp );
+#else
+ fclose( m_fp );
+#endif
+ }
+ }
+
+
+ /** @name Stream implementation. */
+ //@{
+ virtual void seek( uint pos )
+ {
+ nvDebugCheck(m_fp != NULL);
+ nvDebugCheck(pos <= size());
+#if NV_OS_WIN32
+ _fseek_nolock(m_fp, pos, SEEK_SET);
+#else
+ fseek(m_fp, pos, SEEK_SET);
+#endif
+ }
+
+ virtual uint tell() const
+ {
+ nvDebugCheck(m_fp != NULL);
+#if NV_OS_WIN32
+ return _ftell_nolock(m_fp);
+#else
+ return (uint)ftell(m_fp);
+#endif
+ }
+
+ virtual uint size() const
+ {
+ nvDebugCheck(m_fp != NULL);
+#if NV_OS_WIN32
+ uint pos = _ftell_nolock(m_fp);
+ _fseek_nolock(m_fp, 0, SEEK_END);
+ uint end = _ftell_nolock(m_fp);
+ _fseek_nolock(m_fp, pos, SEEK_SET);
+#else
+ uint pos = (uint)ftell(m_fp);
+ fseek(m_fp, 0, SEEK_END);
+ uint end = (uint)ftell(m_fp);
+ fseek(m_fp, pos, SEEK_SET);
+#endif
+ return end;
+ }
+
+ virtual bool isError() const
+ {
+ return m_fp == NULL || ferror( m_fp ) != 0;
+ }
+
+ virtual void clearError()
+ {
+ nvDebugCheck(m_fp != NULL);
+ clearerr(m_fp);
+ }
+
+ // @@ The original implementation uses feof, which only returns true when we attempt to read *past* the end of the stream.
+ // That is, if we read the last byte of a file, then isAtEnd would still return false, even though the stream pointer is at the file end. This is not the intent and was inconsistent with the implementation of the MemoryStream, a better
+ // implementation uses use ftell and fseek to determine our location within the file.
+ virtual bool isAtEnd() const
+ {
+ if (m_fp == NULL) return true;
+ //nvDebugCheck(m_fp != NULL);
+ //return feof( m_fp ) != 0;
+#if NV_OS_WIN32
+ uint pos = _ftell_nolock(m_fp);
+ _fseek_nolock(m_fp, 0, SEEK_END);
+ uint end = _ftell_nolock(m_fp);
+ _fseek_nolock(m_fp, pos, SEEK_SET);
+#else
+ uint pos = (uint)ftell(m_fp);
+ fseek(m_fp, 0, SEEK_END);
+ uint end = (uint)ftell(m_fp);
+ fseek(m_fp, pos, SEEK_SET);
+#endif
+ return pos == end;
+ }
+
+ /// Always true.
+ virtual bool isSeekable() const { return true; }
+ //@}
+
+ protected:
+
+ FILE * m_fp;
+ bool m_autoclose;
+
+ };
+
+
+ /// Standard output stream.
+ class NVCORE_CLASS StdOutputStream : public StdStream
+ {
+ NV_FORBID_COPY(StdOutputStream);
+ public:
+
+ /// Construct stream by file name.
+ StdOutputStream( const char * name ) : StdStream(fileOpen(name, "wb"), /*autoclose=*/true) { }
+
+ /// Construct stream by file handle.
+ StdOutputStream( FILE * fp, bool autoclose ) : StdStream(fp, autoclose)
+ {
+ }
+
+ /** @name Stream implementation. */
+ //@{
+ /// Write data.
+ virtual uint serialize( void * data, uint len )
+ {
+ nvDebugCheck(data != NULL);
+ nvDebugCheck(m_fp != NULL);
+#if NV_OS_WIN32
+ return (uint)_fwrite_nolock(data, 1, len, m_fp);
+#elif NV_OS_LINUX
+ return (uint)fwrite_unlocked(data, 1, len, m_fp);
+#elif NV_OS_DARWIN
+ // @@ No error checking, always returns len.
+ for (uint i = 0; i < len; i++) {
+ putc_unlocked(((char *)data)[i], m_fp);
+ }
+ return len;
+#else
+ return (uint)fwrite(data, 1, len, m_fp);
+#endif
+ }
+
+ virtual bool isLoading() const
+ {
+ return false;
+ }
+
+ virtual bool isSaving() const
+ {
+ return true;
+ }
+ //@}
+
+ };
+
+
+ /// Standard input stream.
+ class NVCORE_CLASS StdInputStream : public StdStream
+ {
+ NV_FORBID_COPY(StdInputStream);
+ public:
+
+ /// Construct stream by file name.
+ StdInputStream( const char * name ) : StdStream(fileOpen(name, "rb"), /*autoclose=*/true) { }
+
+ /// Construct stream by file handle.
+ StdInputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose)
+ {
+ }
+
+ /** @name Stream implementation. */
+ //@{
+ /// Read data.
+ virtual uint serialize( void * data, uint len )
+ {
+ nvDebugCheck(data != NULL);
+ nvDebugCheck(m_fp != NULL);
+#if NV_OS_WIN32
+ return (uint)_fread_nolock(data, 1, len, m_fp);
+#elif NV_OS_LINUX
+ return (uint)fread_unlocked(data, 1, len, m_fp);
+#elif NV_OS_DARWIN
+ // This is rather lame. Not sure if it's faster than the locked version.
+ for (uint i = 0; i < len; i++) {
+ ((char *)data)[i] = getc_unlocked(m_fp);
+ if (feof_unlocked(m_fp) != 0) {
+ return i;
+ }
+ }
+ return len;
+#else
+ return (uint)fread(data, 1, len, m_fp);
+#endif
+
+ }
+
+ virtual bool isLoading() const
+ {
+ return true;
+ }
+
+ virtual bool isSaving() const
+ {
+ return false;
+ }
+ //@}
+ };
+
+
+
+ /// Memory input stream.
+ class NVCORE_CLASS MemoryInputStream : public Stream
+ {
+ NV_FORBID_COPY(MemoryInputStream);
+ public:
+
+ /// Ctor.
+ MemoryInputStream( const uint8 * mem, uint size ) : m_mem(mem), m_ptr(mem), m_size(size) { }
+
+ /** @name Stream implementation. */
+ //@{
+ /// Read data.
+ virtual uint serialize( void * data, uint len )
+ {
+ nvDebugCheck(data != NULL);
+ nvDebugCheck(!isError());
+
+ uint left = m_size - tell();
+ if (len > left) len = left;
+
+ memcpy( data, m_ptr, len );
+ m_ptr += len;
+
+ return len;
+ }
+
+ virtual void seek( uint pos )
+ {
+ nvDebugCheck(!isError());
+ m_ptr = m_mem + pos;
+ nvDebugCheck(!isError());
+ }
+
+ virtual uint tell() const
+ {
+ nvDebugCheck(m_ptr >= m_mem);
+ return uint(m_ptr - m_mem);
+ }
+
+ virtual uint size() const
+ {
+ return m_size;
+ }
+
+ virtual bool isError() const
+ {
+ return m_mem == NULL || m_ptr > m_mem + m_size || m_ptr < m_mem;
+ }
+
+ virtual void clearError()
+ {
+ // Nothing to do.
+ }
+
+ virtual bool isAtEnd() const
+ {
+ return m_ptr == m_mem + m_size;
+ }
+
+ /// Always true.
+ virtual bool isSeekable() const
+ {
+ return true;
+ }
+
+ virtual bool isLoading() const
+ {
+ return true;
+ }
+
+ virtual bool isSaving() const
+ {
+ return false;
+ }
+ //@}
+
+ const uint8 * ptr() const { return m_ptr; }
+
+
+ private:
+
+ const uint8 * m_mem;
+ const uint8 * m_ptr;
+ uint m_size;
+
+ };
+
+
+ /// Buffer output stream.
+ class NVCORE_CLASS BufferOutputStream : public Stream
+ {
+ NV_FORBID_COPY(BufferOutputStream);
+ public:
+
+ BufferOutputStream(Array<uint8> & buffer) : m_buffer(buffer) { }
+
+ virtual uint serialize( void * data, uint len )
+ {
+ nvDebugCheck(data != NULL);
+ m_buffer.append((uint8 *)data, len);
+ return len;
+ }
+
+ virtual void seek( uint /*pos*/ ) { /*Not implemented*/ }
+ virtual uint tell() const { return m_buffer.size(); }
+ virtual uint size() const { return m_buffer.size(); }
+
+ virtual bool isError() const { return false; }
+ virtual void clearError() {}
+
+ virtual bool isAtEnd() const { return true; }
+ virtual bool isSeekable() const { return false; }
+ virtual bool isLoading() const { return false; }
+ virtual bool isSaving() const { return true; }
+
+ private:
+ Array<uint8> & m_buffer;
+ };
+
+
+ /// Protected input stream.
+ class NVCORE_CLASS ProtectedStream : public Stream
+ {
+ NV_FORBID_COPY(ProtectedStream);
+ public:
+
+ /// Ctor.
+ ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false)
+ {
+ }
+
+ /// Ctor.
+ ProtectedStream( Stream * s, bool autodelete = true ) :
+ m_s(s), m_autodelete(autodelete)
+ {
+ nvDebugCheck(m_s != NULL);
+ }
+
+ /// Dtor.
+ virtual ~ProtectedStream()
+ {
+ if( m_autodelete ) {
+ delete m_s;
+ }
+ }
+
+ /** @name Stream implementation. */
+ //@{
+ /// Read data.
+ virtual uint serialize( void * data, uint len )
+ {
+ nvDebugCheck(data != NULL);
+ len = m_s->serialize( data, len );
+
+ if( m_s->isError() ) {
+#if NV_OS_ORBIS
+ //SBtodoORBIS disabled (no exceptions)
+#else
+ throw;
+#endif
+ }
+
+ return len;
+ }
+
+ virtual void seek( uint pos )
+ {
+ m_s->seek( pos );
+
+ if( m_s->isError() ) {
+#if NV_OS_ORBIS
+ //SBtodoORBIS disabled (no exceptions)
+#else
+ throw;
+#endif
+ }
+ }
+
+ virtual uint tell() const
+ {
+ return m_s->tell();
+ }
+
+ virtual uint size() const
+ {
+ return m_s->size();
+ }
+
+ virtual bool isError() const
+ {
+ return m_s->isError();
+ }
+
+ virtual void clearError()
+ {
+ m_s->clearError();
+ }
+
+ virtual bool isAtEnd() const
+ {
+ return m_s->isAtEnd();
+ }
+
+ virtual bool isSeekable() const
+ {
+ return m_s->isSeekable();
+ }
+
+ virtual bool isLoading() const
+ {
+ return m_s->isLoading();
+ }
+
+ virtual bool isSaving() const
+ {
+ return m_s->isSaving();
+ }
+ //@}
+
+
+ private:
+
+ Stream * const m_s;
+ bool const m_autodelete;
+
+ };
+
+} // nv namespace
+
+
+//#endif // NV_CORE_STDSTREAM_H
diff --git a/thirdparty/thekla_atlas/nvcore/StrLib.cpp b/thirdparty/thekla_atlas/nvcore/StrLib.cpp
new file mode 100644
index 0000000000..7ec6c70136
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/StrLib.cpp
@@ -0,0 +1,796 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#include "StrLib.h"
+
+#include "Memory.h"
+#include "Utils.h" // swap
+
+#include <math.h> // log
+#include <stdio.h> // vsnprintf
+#include <string.h> // strlen, strcmp, etc.
+
+#if NV_CC_MSVC
+#include <stdarg.h> // vsnprintf
+#endif
+
+using namespace nv;
+
+namespace
+{
+ static char * strAlloc(uint size)
+ {
+ return malloc<char>(size);
+ }
+
+ static char * strReAlloc(char * str, uint size)
+ {
+ return realloc<char>(str, size);
+ }
+
+ static void strFree(const char * str)
+ {
+ return free<char>(str);
+ }
+
+ /*static char * strDup( const char * str )
+ {
+ nvDebugCheck( str != NULL );
+ uint len = uint(strlen( str ) + 1);
+ char * dup = strAlloc( len );
+ memcpy( dup, str, len );
+ return dup;
+ }*/
+
+ // helper function for integer to string conversion.
+ static char * i2a( uint i, char *a, uint r )
+ {
+ if( i / r > 0 ) {
+ a = i2a( i / r, a, r );
+ }
+ *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % r];
+ return a + 1;
+ }
+
+ // Locale independent functions.
+ static inline char toUpper( char c ) {
+ return (c<'a' || c>'z') ? (c) : (c+'A'-'a');
+ }
+ static inline char toLower( char c ) {
+ return (c<'A' || c>'Z') ? (c) : (c+'a'-'A');
+ }
+ static inline bool isAlpha( char c ) {
+ return (c>='a' && c<='z') || (c>='A' && c<='Z');
+ }
+ static inline bool isDigit( char c ) {
+ return c>='0' && c<='9';
+ }
+ static inline bool isAlnum( char c ) {
+ return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
+ }
+
+}
+
+uint nv::strLen(const char * str)
+{
+ nvDebugCheck(str != NULL);
+ return U32(strlen(str));
+}
+
+int nv::strDiff(const char * s1, const char * s2)
+{
+ nvDebugCheck(s1 != NULL);
+ nvDebugCheck(s2 != NULL);
+ return strcmp(s1, s2);
+}
+
+int nv::strCaseDiff(const char * s1, const char * s2)
+{
+ nvDebugCheck(s1 != NULL);
+ nvDebugCheck(s1 != NULL);
+#if NV_CC_MSVC
+ return _stricmp(s1, s2);
+#else
+ return strcasecmp(s1, s2);
+#endif
+}
+
+bool nv::strEqual(const char * s1, const char * s2)
+{
+ if (s1 == s2) return true;
+ if (s1 == NULL || s2 == NULL) return false;
+ return strcmp(s1, s2) == 0;
+}
+
+bool nv::strCaseEqual(const char * s1, const char * s2)
+{
+ if (s1 == s2) return true;
+ if (s1 == NULL || s2 == NULL) return false;
+ return strCaseDiff(s1, s2) == 0;
+}
+
+bool nv::strBeginsWith(const char * str, const char * prefix)
+{
+ //return strstr(str, prefix) == dst;
+ return strncmp(str, prefix, strlen(prefix)) == 0;
+}
+
+bool nv::strEndsWith(const char * str, const char * suffix)
+{
+ uint ml = strLen(str);
+ uint sl = strLen(suffix);
+ if (ml < sl) return false;
+ return strncmp(str + ml - sl, suffix, sl) == 0;
+}
+
+// @@ Add asserts to detect overlap between dst and src?
+void nv::strCpy(char * dst, uint size, const char * src)
+{
+ nvDebugCheck(dst != NULL);
+ nvDebugCheck(src != NULL);
+#if NV_CC_MSVC && _MSC_VER >= 1400
+ strcpy_s(dst, size, src);
+#else
+ NV_UNUSED(size);
+ strcpy(dst, src);
+#endif
+}
+
+void nv::strCpy(char * dst, uint size, const char * src, uint len)
+{
+ nvDebugCheck(dst != NULL);
+ nvDebugCheck(src != NULL);
+#if NV_CC_MSVC && _MSC_VER >= 1400
+ strncpy_s(dst, size, src, len);
+#else
+ int n = min(len+1, size);
+ strncpy(dst, src, n);
+ dst[n-1] = '\0';
+#endif
+}
+
+void nv::strCat(char * dst, uint size, const char * src)
+{
+ nvDebugCheck(dst != NULL);
+ nvDebugCheck(src != NULL);
+#if NV_CC_MSVC && _MSC_VER >= 1400
+ strcat_s(dst, size, src);
+#else
+ NV_UNUSED(size);
+ strcat(dst, src);
+#endif
+}
+
+NVCORE_API const char * nv::strSkipWhiteSpace(const char * str)
+{
+ nvDebugCheck(str != NULL);
+ while (*str == ' ') str++;
+ return str;
+}
+
+NVCORE_API char * nv::strSkipWhiteSpace(char * str)
+{
+ nvDebugCheck(str != NULL);
+ while (*str == ' ') str++;
+ return str;
+}
+
+
+/** Pattern matching routine. I don't remember where did I get this. */
+bool nv::strMatch(const char * str, const char * pat)
+{
+ nvDebugCheck(str != NULL);
+ nvDebugCheck(pat != NULL);
+
+ char c2;
+
+ while (true) {
+ if (*pat==0) {
+ if (*str==0) return true;
+ else return false;
+ }
+ if ((*str==0) && (*pat!='*')) return false;
+ if (*pat=='*') {
+ pat++;
+ if (*pat==0) return true;
+ while (true) {
+ if (strMatch(str, pat)) return true;
+ if (*str==0) return false;
+ str++;
+ }
+ }
+ if (*pat=='?') goto match;
+ if (*pat=='[') {
+ pat++;
+ while (true) {
+ if ((*pat==']') || (*pat==0)) return false;
+ if (*pat==*str) break;
+ if (pat[1] == '-') {
+ c2 = pat[2];
+ if (c2==0) return false;
+ if ((*pat<=*str) && (c2>=*str)) break;
+ if ((*pat>=*str) && (c2<=*str)) break;
+ pat+=2;
+ }
+ pat++;
+ }
+ while (*pat!=']') {
+ if (*pat==0) {
+ pat--;
+ break;
+ }
+ pat++;
+ }
+ goto match;
+ }
+
+ if (*pat == NV_PATH_SEPARATOR) {
+ pat++;
+ if (*pat==0) return false;
+ }
+ if (*pat!=*str) return false;
+
+match:
+ pat++;
+ str++;
+ }
+}
+
+bool nv::isNumber(const char * str) {
+ while(*str != '\0') {
+ if (!isDigit(*str)) return false;
+ str++;
+ }
+ return true;
+}
+
+
+/** Empty string. */
+StringBuilder::StringBuilder() : m_size(0), m_str(NULL)
+{
+}
+
+/** Preallocate space. */
+StringBuilder::StringBuilder( uint size_hint ) : m_size(size_hint)
+{
+ nvDebugCheck(m_size > 0);
+ m_str = strAlloc(m_size);
+ *m_str = '\0';
+}
+
+/** Copy ctor. */
+StringBuilder::StringBuilder( const StringBuilder & s ) : m_size(0), m_str(NULL)
+{
+ copy(s);
+}
+
+/** Copy string. */
+StringBuilder::StringBuilder(const char * s) : m_size(0), m_str(NULL)
+{
+ if (s != NULL) {
+ copy(s);
+ }
+}
+
+/** Copy string. */
+StringBuilder::StringBuilder(const char * s, uint len) : m_size(0), m_str(NULL)
+{
+ copy(s, len);
+}
+
+/** Delete the string. */
+StringBuilder::~StringBuilder()
+{
+ strFree(m_str);
+}
+
+
+/** Format a string safely. */
+StringBuilder & StringBuilder::format( const char * fmt, ... )
+{
+ nvDebugCheck(fmt != NULL);
+ va_list arg;
+ va_start( arg, fmt );
+
+ formatList( fmt, arg );
+
+ va_end( arg );
+
+ return *this;
+}
+
+
+/** Format a string safely. */
+StringBuilder & StringBuilder::formatList( const char * fmt, va_list arg )
+{
+ nvDebugCheck(fmt != NULL);
+
+ if (m_size == 0) {
+ m_size = 64;
+ m_str = strAlloc( m_size );
+ }
+
+ va_list tmp;
+ va_copy(tmp, arg);
+#if NV_CC_MSVC && _MSC_VER >= 1400
+ int n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp);
+#else
+ int n = vsnprintf(m_str, m_size, fmt, tmp);
+#endif
+ va_end(tmp);
+
+ while( n < 0 || n >= int(m_size) ) {
+ if( n > -1 ) {
+ m_size = n + 1;
+ }
+ else {
+ m_size *= 2;
+ }
+
+ m_str = strReAlloc(m_str, m_size);
+
+ va_copy(tmp, arg);
+#if NV_CC_MSVC && _MSC_VER >= 1400
+ n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp);
+#else
+ n = vsnprintf(m_str, m_size, fmt, tmp);
+#endif
+ va_end(tmp);
+ }
+
+ nvDebugCheck(n < int(m_size));
+
+ // Make sure it's null terminated.
+ nvDebugCheck(m_str[n] == '\0');
+ //str[n] = '\0';
+
+ return *this;
+}
+
+
+// Append a character.
+StringBuilder & StringBuilder::append( char c )
+{
+ return append(&c, 1);
+}
+
+// Append a string.
+StringBuilder & StringBuilder::append( const char * s )
+{
+ return append(s, U32(strlen( s )));
+}
+
+// Append a string.
+StringBuilder & StringBuilder::append(const char * s, uint len)
+{
+ nvDebugCheck(s != NULL);
+
+ uint offset = length();
+ const uint size = offset + len + 1;
+ reserve(size);
+ strCpy(m_str + offset, len + 1, s, len);
+
+ return *this;
+}
+
+StringBuilder & StringBuilder::append(const StringBuilder & str)
+{
+ return append(str.m_str, str.length());
+}
+
+
+/** Append a formatted string. */
+StringBuilder & StringBuilder::appendFormat( const char * fmt, ... )
+{
+ nvDebugCheck( fmt != NULL );
+
+ va_list arg;
+ va_start( arg, fmt );
+
+ appendFormatList( fmt, arg );
+
+ va_end( arg );
+
+ return *this;
+}
+
+
+/** Append a formatted string. */
+StringBuilder & StringBuilder::appendFormatList( const char * fmt, va_list arg )
+{
+ nvDebugCheck( fmt != NULL );
+
+ va_list tmp;
+ va_copy(tmp, arg);
+
+ if (m_size == 0) {
+ formatList(fmt, arg);
+ }
+ else {
+ StringBuilder tmp_str;
+ tmp_str.formatList( fmt, tmp );
+ append( tmp_str.str() );
+ }
+
+ va_end(tmp);
+
+ return *this;
+}
+
+// Append n spaces.
+StringBuilder & StringBuilder::appendSpace(uint n)
+{
+ if (m_str == NULL) {
+ m_size = n + 1;
+ m_str = strAlloc(m_size);
+ memset(m_str, ' ', m_size);
+ m_str[n] = '\0';
+ }
+ else {
+ const uint len = strLen(m_str);
+ if (m_size < len + n + 1) {
+ m_size = len + n + 1;
+ m_str = strReAlloc(m_str, m_size);
+ }
+ memset(m_str + len, ' ', n);
+ m_str[len+n] = '\0';
+ }
+
+ return *this;
+}
+
+
+/** Convert number to string in the given base. */
+StringBuilder & StringBuilder::number( int i, int base )
+{
+ nvCheck( base >= 2 );
+ nvCheck( base <= 36 );
+
+ // @@ This needs to be done correctly.
+ // length = floor(log(i, base));
+ uint len = uint(log(float(i)) / log(float(base)) + 2); // one more if negative
+ reserve(len);
+
+ if( i < 0 ) {
+ *m_str = '-';
+ *i2a(uint(-i), m_str+1, base) = 0;
+ }
+ else {
+ *i2a(i, m_str, base) = 0;
+ }
+
+ return *this;
+}
+
+
+/** Convert number to string in the given base. */
+StringBuilder & StringBuilder::number( uint i, int base )
+{
+ nvCheck( base >= 2 );
+ nvCheck( base <= 36 );
+
+ // @@ This needs to be done correctly.
+ // length = floor(log(i, base));
+ uint len = uint(log(float(i)) / log(float(base)) - 0.5f + 1);
+ reserve(len);
+
+ *i2a(i, m_str, base) = 0;
+
+ return *this;
+}
+
+
+/** Resize the string preserving the contents. */
+StringBuilder & StringBuilder::reserve( uint size_hint )
+{
+ nvCheck(size_hint != 0);
+ if (size_hint > m_size) {
+ m_str = strReAlloc(m_str, size_hint);
+ m_size = size_hint;
+ }
+ return *this;
+}
+
+
+/** Copy a string safely. */
+StringBuilder & StringBuilder::copy(const char * s)
+{
+ nvCheck( s != NULL );
+ const uint str_size = uint(strlen( s )) + 1;
+ reserve(str_size);
+ memcpy(m_str, s, str_size);
+ return *this;
+}
+
+/** Copy a string safely. */
+StringBuilder & StringBuilder::copy(const char * s, uint len)
+{
+ nvCheck( s != NULL );
+ const uint str_size = len + 1;
+ reserve(str_size);
+ strCpy(m_str, str_size, s, len);
+ return *this;
+}
+
+
+/** Copy an StringBuilder. */
+StringBuilder & StringBuilder::copy( const StringBuilder & s )
+{
+ if (s.m_str == NULL) {
+ nvCheck( s.m_size == 0 );
+ reset();
+ }
+ else {
+ reserve( s.m_size );
+ strCpy( m_str, s.m_size, s.m_str );
+ }
+ return *this;
+}
+
+bool StringBuilder::endsWith(const char * str) const
+{
+ uint l = uint(strlen(str));
+ uint ml = uint(strlen(m_str));
+ if (ml < l) return false;
+ return strncmp(m_str + ml - l, str, l) == 0;
+}
+
+bool StringBuilder::beginsWith(const char * str) const
+{
+ size_t l = strlen(str);
+ return strncmp(m_str, str, l) == 0;
+}
+
+// Find given char starting from the end.
+char * StringBuilder::reverseFind(char c)
+{
+ int length = (int)strlen(m_str) - 1;
+ while (length >= 0 && m_str[length] != c) {
+ length--;
+ }
+ if (length >= 0) {
+ return m_str + length;
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+/** Reset the string. */
+void StringBuilder::reset()
+{
+ m_size = 0;
+ strFree( m_str );
+ m_str = NULL;
+}
+
+/** Release the allocated string. */
+char * StringBuilder::release()
+{
+ char * str = m_str;
+ m_size = 0;
+ m_str = NULL;
+ return str;
+}
+
+// Take ownership of string.
+void StringBuilder::acquire(char * str)
+{
+ if (str) {
+ m_size = strLen(str) + 1;
+ m_str = str;
+ }
+ else {
+ m_size = 0;
+ m_str = NULL;
+ }
+}
+
+// Swap strings.
+void nv::swap(StringBuilder & a, StringBuilder & b) {
+ swap(a.m_size, b.m_size);
+ swap(a.m_str, b.m_str);
+}
+
+
+/// Get the file name from a path.
+const char * Path::fileName() const
+{
+ return fileName(m_str);
+}
+
+
+/// Get the extension from a file path.
+const char * Path::extension() const
+{
+ return extension(m_str);
+}
+
+
+/*static */void Path::translatePath(char * path, char pathSeparator/*= NV_PATH_SEPARATOR*/) {
+ if (path != NULL) {
+ for (int i = 0;; i++) {
+ if (path[i] == '\0') break;
+ if (path[i] == '\\' || path[i] == '/') path[i] = pathSeparator;
+ }
+ }
+}
+
+/// Toggles path separators (ie. \\ into /).
+void Path::translatePath(char pathSeparator/*=NV_PATH_SEPARATOR*/)
+{
+ if (!isNull()) {
+ translatePath(m_str, pathSeparator);
+ }
+}
+
+void Path::appendSeparator(char pathSeparator/*=NV_PATH_SEPARATOR*/)
+{
+ nvCheck(!isNull());
+
+ const uint l = length();
+
+ if (m_str[l] != '\\' && m_str[l] != '/') {
+ char separatorString[] = { pathSeparator, '\0' };
+ append(separatorString);
+ }
+}
+
+
+/**
+* Strip the file name from a path.
+* @warning path cannot end with '/' o '\\', can't it?
+*/
+void Path::stripFileName()
+{
+ nvCheck( m_str != NULL );
+
+ int length = (int)strlen(m_str) - 1;
+ while (length > 0 && m_str[length] != '/' && m_str[length] != '\\'){
+ length--;
+ }
+ if( length ) {
+ m_str[length+1] = 0;
+ }
+ else {
+ m_str[0] = 0;
+ }
+}
+
+
+/// Strip the extension from a path name.
+void Path::stripExtension()
+{
+ nvCheck( m_str != NULL );
+
+ int length = (int)strlen(m_str) - 1;
+ while (length > 0 && m_str[length] != '.') {
+ length--;
+ if( m_str[length] == NV_PATH_SEPARATOR ) {
+ return; // no extension
+ }
+ }
+ if (length > 0) {
+ m_str[length] = 0;
+ }
+}
+
+
+/// Get the path separator.
+// static
+char Path::separator()
+{
+ return NV_PATH_SEPARATOR;
+}
+
+// static
+const char * Path::fileName(const char * str)
+{
+ nvCheck( str != NULL );
+
+ int length = (int)strlen(str) - 1;
+ while (length >= 0 && str[length] != '\\' && str[length] != '/') {
+ length--;
+ }
+
+ return &str[length+1];
+}
+
+// static
+const char * Path::extension(const char * str)
+{
+ nvCheck( str != NULL );
+
+ int length, l;
+ l = length = (int)strlen( str );
+ while (length > 0 && str[length] != '.') {
+ length--;
+ if (str[length] == '\\' || str[length] == '/') {
+ return &str[l]; // no extension
+ }
+ }
+ if (length == 0) {
+ return &str[l];
+ }
+ return &str[length];
+}
+
+
+
+/// Clone this string
+String String::clone() const
+{
+ String str(data);
+ return str;
+}
+
+void String::setString(const char * str)
+{
+ if (str == NULL) {
+ data = NULL;
+ }
+ else {
+ allocString( str );
+ addRef();
+ }
+}
+
+void String::setString(const char * str, uint length)
+{
+ nvDebugCheck(str != NULL);
+
+ allocString(str, length);
+ addRef();
+}
+
+void String::setString(const StringBuilder & str)
+{
+ if (str.str() == NULL) {
+ data = NULL;
+ }
+ else {
+ allocString(str.str());
+ addRef();
+ }
+}
+
+// Add reference count.
+void String::addRef()
+{
+ if (data != NULL)
+ {
+ setRefCount(getRefCount() + 1);
+ }
+}
+
+// Decrease reference count.
+void String::release()
+{
+ if (data != NULL)
+ {
+ const uint16 count = getRefCount();
+ setRefCount(count - 1);
+ if (count - 1 == 0) {
+ free(data - 2);
+ data = NULL;
+ }
+ }
+}
+
+void String::allocString(const char * str, uint len)
+{
+ const char * ptr = malloc<char>(2 + len + 1);
+
+ setData( ptr );
+ setRefCount( 0 );
+
+ // Copy string.
+ strCpy(const_cast<char *>(data), len+1, str, len);
+
+ // Add terminating character.
+ const_cast<char *>(data)[len] = '\0';
+}
+
+void nv::swap(String & a, String & b) {
+ swap(a.data, b.data);
+}
diff --git a/thirdparty/thekla_atlas/nvcore/StrLib.h b/thirdparty/thekla_atlas/nvcore/StrLib.h
new file mode 100644
index 0000000000..ae4b5d12a0
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/StrLib.h
@@ -0,0 +1,433 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_STRING_H
+#define NV_CORE_STRING_H
+
+#include "Debug.h"
+#include "Hash.h" // hash
+
+//#include <string.h> // strlen, etc.
+
+#if NV_OS_WIN32
+#define NV_PATH_SEPARATOR '\\'
+#else
+#define NV_PATH_SEPARATOR '/'
+#endif
+
+namespace nv
+{
+
+ NVCORE_API uint strHash(const char * str, uint h) NV_PURE;
+
+ /// String hash based on Bernstein's hash.
+ inline uint strHash(const char * data, uint h = 5381)
+ {
+ uint i = 0;
+ while(data[i] != 0) {
+ h = (33 * h) ^ uint(data[i]);
+ i++;
+ }
+ return h;
+ }
+
+ template <> struct Hash<const char *> {
+ uint operator()(const char * str) const { return strHash(str); }
+ };
+
+ NVCORE_API uint strLen(const char * str) NV_PURE; // Asserts on NULL strings.
+
+ NVCORE_API int strDiff(const char * s1, const char * s2) NV_PURE; // Asserts on NULL strings.
+ NVCORE_API int strCaseDiff(const char * s1, const char * s2) NV_PURE; // Asserts on NULL strings.
+ NVCORE_API bool strEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
+ NVCORE_API bool strCaseEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
+
+ template <> struct Equal<const char *> {
+ bool operator()(const char * a, const char * b) const { return strEqual(a, b); }
+ };
+
+ NVCORE_API bool strBeginsWith(const char * dst, const char * prefix) NV_PURE;
+ NVCORE_API bool strEndsWith(const char * dst, const char * suffix) NV_PURE;
+
+
+ NVCORE_API void strCpy(char * dst, uint size, const char * src);
+ NVCORE_API void strCpy(char * dst, uint size, const char * src, uint len);
+ NVCORE_API void strCat(char * dst, uint size, const char * src);
+
+ NVCORE_API const char * strSkipWhiteSpace(const char * str);
+ NVCORE_API char * strSkipWhiteSpace(char * str);
+
+ NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE;
+
+ NVCORE_API bool isNumber(const char * str) NV_PURE;
+
+ /* @@ Implement these two functions and modify StringBuilder to use them?
+ NVCORE_API void strFormat(const char * dst, const char * fmt, ...);
+ NVCORE_API void strFormatList(const char * dst, const char * fmt, va_list arg);
+
+ template <size_t count> void strFormatSafe(char (&buffer)[count], const char *fmt, ...) __attribute__((format (printf, 2, 3)));
+ template <size_t count> void strFormatSafe(char (&buffer)[count], const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ strFormatList(buffer, count, fmt, args);
+ va_end(args);
+ }
+ template <size_t count> void strFormatListSafe(char (&buffer)[count], const char *fmt, va_list arg) {
+ va_list tmp;
+ va_copy(tmp, args);
+ strFormatList(buffer, count, fmt, tmp);
+ va_end(tmp);
+ }*/
+
+ template <int count> void strCpySafe(char (&buffer)[count], const char *src) {
+ strCpy(buffer, count, src);
+ }
+
+ template <int count> void strCatSafe(char (&buffer)[count], const char * src) {
+ strCat(buffer, count, src);
+ }
+
+
+
+ /// String builder.
+ class NVCORE_CLASS StringBuilder
+ {
+ public:
+
+ StringBuilder();
+ explicit StringBuilder( uint size_hint );
+ StringBuilder(const char * str);
+ StringBuilder(const char * str, uint len);
+ StringBuilder(const StringBuilder & other);
+
+ ~StringBuilder();
+
+ StringBuilder & format( const char * format, ... ) __attribute__((format (printf, 2, 3)));
+ StringBuilder & formatList( const char * format, va_list arg );
+
+ StringBuilder & append(char c);
+ StringBuilder & append(const char * str);
+ StringBuilder & append(const char * str, uint len);
+ StringBuilder & append(const StringBuilder & str);
+ StringBuilder & appendFormat(const char * format, ...) __attribute__((format (printf, 2, 3)));
+ StringBuilder & appendFormatList(const char * format, va_list arg);
+
+ StringBuilder & appendSpace(uint n);
+
+ StringBuilder & number( int i, int base = 10 );
+ StringBuilder & number( uint i, int base = 10 );
+
+ StringBuilder & reserve(uint size_hint);
+ StringBuilder & copy(const char * str);
+ StringBuilder & copy(const char * str, uint len);
+ StringBuilder & copy(const StringBuilder & str);
+
+ StringBuilder & toLower();
+ StringBuilder & toUpper();
+
+ bool endsWith(const char * str) const;
+ bool beginsWith(const char * str) const;
+
+ char * reverseFind(char c);
+
+ void reset();
+ bool isNull() const { return m_size == 0; }
+
+ // const char * accessors
+ //operator const char * () const { return m_str; }
+ //operator char * () { return m_str; }
+ const char * str() const { return m_str; }
+ char * str() { return m_str; }
+
+ char * release(); // Release ownership of string.
+ void acquire(char *); // Take ownership of string.
+
+ /// Implement value semantics.
+ StringBuilder & operator=( const StringBuilder & s ) {
+ return copy(s);
+ }
+
+ /// Implement value semantics.
+ StringBuilder & operator=( const char * s ) {
+ return copy(s);
+ }
+
+ /// Equal operator.
+ bool operator==( const StringBuilder & s ) const {
+ return strMatch(s.m_str, m_str);
+ }
+
+ /// Return the exact length.
+ uint length() const { return isNull() ? 0 : strLen(m_str); }
+
+ /// Return the size of the string container.
+ uint capacity() const { return m_size; }
+
+ /// Return the hash of the string.
+ uint hash() const { return isNull() ? 0 : strHash(m_str); }
+
+ // Swap strings.
+ friend void swap(StringBuilder & a, StringBuilder & b);
+
+ protected:
+
+ /// Size of the string container.
+ uint m_size;
+
+ /// String.
+ char * m_str;
+
+ };
+
+
+ /// Path string. @@ This should be called PathBuilder.
+ class NVCORE_CLASS Path : public StringBuilder
+ {
+ public:
+ Path() : StringBuilder() {}
+ explicit Path(int size_hint) : StringBuilder(size_hint) {}
+ Path(const char * str) : StringBuilder(str) {}
+ Path(const Path & path) : StringBuilder(path) {}
+
+ const char * fileName() const;
+ const char * extension() const;
+
+ void translatePath(char pathSeparator = NV_PATH_SEPARATOR);
+
+ void appendSeparator(char pathSeparator = NV_PATH_SEPARATOR);
+
+ void stripFileName();
+ void stripExtension();
+
+ // statics
+ NVCORE_API static char separator();
+ NVCORE_API static const char * fileName(const char *);
+ NVCORE_API static const char * extension(const char *);
+
+ NVCORE_API static void translatePath(char * path, char pathSeparator = NV_PATH_SEPARATOR);
+ };
+
+
+ /// String class.
+ class NVCORE_CLASS String
+ {
+ public:
+
+ /// Constructs a null string. @sa isNull()
+ String()
+ {
+ data = NULL;
+ }
+
+ /// Constructs a shared copy of str.
+ String(const String & str)
+ {
+ data = str.data;
+ if (data != NULL) addRef();
+ }
+
+ /// Constructs a shared string from a standard string.
+ String(const char * str)
+ {
+ setString(str);
+ }
+
+ /// Constructs a shared string from a standard string.
+ String(const char * str, int length)
+ {
+ setString(str, length);
+ }
+
+ /// Constructs a shared string from a StringBuilder.
+ String(const StringBuilder & str)
+ {
+ setString(str);
+ }
+
+ /// Dtor.
+ ~String()
+ {
+ release();
+ }
+
+ String clone() const;
+
+ /// Release the current string and allocate a new one.
+ const String & operator=( const char * str )
+ {
+ release();
+ setString( str );
+ return *this;
+ }
+
+ /// Release the current string and allocate a new one.
+ const String & operator=( const StringBuilder & str )
+ {
+ release();
+ setString( str );
+ return *this;
+ }
+
+ /// Implement value semantics.
+ String & operator=( const String & str )
+ {
+ if (str.data != data)
+ {
+ release();
+ data = str.data;
+ addRef();
+ }
+ return *this;
+ }
+
+ /// Equal operator.
+ bool operator==( const String & str ) const
+ {
+ return strMatch(str.data, data);
+ }
+
+ /// Equal operator.
+ bool operator==( const char * str ) const
+ {
+ return strMatch(str, data);
+ }
+
+ /// Not equal operator.
+ bool operator!=( const String & str ) const
+ {
+ return !strMatch(str.data, data);
+ }
+
+ /// Not equal operator.
+ bool operator!=( const char * str ) const
+ {
+ return !strMatch(str, data);
+ }
+
+ /// Returns true if this string is the null string.
+ bool isNull() const { return data == NULL; }
+
+ /// Return the exact length.
+ uint length() const { nvDebugCheck(data != NULL); return strLen(data); }
+
+ /// Return the hash of the string.
+ uint hash() const { nvDebugCheck(data != NULL); return strHash(data); }
+
+ /// const char * cast operator.
+ operator const char * () const { return data; }
+
+ /// Get string pointer.
+ const char * str() const { return data; }
+
+
+ private:
+
+ // Add reference count.
+ void addRef();
+
+ // Decrease reference count.
+ void release();
+
+ uint16 getRefCount() const
+ {
+ nvDebugCheck(data != NULL);
+ return *reinterpret_cast<const uint16 *>(data - 2);
+ }
+
+ void setRefCount(uint16 count) {
+ nvDebugCheck(data != NULL);
+ nvCheck(count < 0xFFFF);
+ *reinterpret_cast<uint16 *>(const_cast<char *>(data - 2)) = uint16(count);
+ }
+
+ void setData(const char * str) {
+ data = str + 2;
+ }
+
+ void allocString(const char * str)
+ {
+ allocString(str, strLen(str));
+ }
+
+ void allocString(const char * str, uint length);
+
+ void setString(const char * str);
+ void setString(const char * str, uint length);
+ void setString(const StringBuilder & str);
+
+ // Swap strings.
+ friend void swap(String & a, String & b);
+
+ private:
+
+ const char * data;
+
+ };
+
+ template <> struct Hash<String> {
+ uint operator()(const String & str) const { return str.hash(); }
+ };
+
+
+ // Like AutoPtr, but for const char strings.
+ class AutoString
+ {
+ NV_FORBID_COPY(AutoString);
+ NV_FORBID_HEAPALLOC();
+ public:
+
+ // Ctor.
+ AutoString(const char * p = NULL) : m_ptr(p) { }
+
+#if NV_CC_CPP11
+ // Move ctor.
+ AutoString(AutoString && ap) : m_ptr(ap.m_ptr) { ap.m_ptr = NULL; }
+#endif
+
+ // Dtor. Deletes owned pointer.
+ ~AutoString() {
+ delete [] m_ptr;
+ m_ptr = NULL;
+ }
+
+ // Delete owned pointer and assign new one.
+ void operator=(const char * p) {
+ if (p != m_ptr)
+ {
+ delete [] m_ptr;
+ m_ptr = p;
+ }
+ }
+
+ // Get pointer.
+ const char * ptr() const { return m_ptr; }
+ operator const char *() const { return m_ptr; }
+
+ // Relinquish ownership of the underlying pointer and returns that pointer.
+ const char * release() {
+ const char * tmp = m_ptr;
+ m_ptr = NULL;
+ return tmp;
+ }
+
+ // comparison operators.
+ friend bool operator == (const AutoString & ap, const char * const p) {
+ return (ap.ptr() == p);
+ }
+ friend bool operator != (const AutoString & ap, const char * const p) {
+ return (ap.ptr() != p);
+ }
+ friend bool operator == (const char * const p, const AutoString & ap) {
+ return (ap.ptr() == p);
+ }
+ friend bool operator != (const char * const p, const AutoString & ap) {
+ return (ap.ptr() != p);
+ }
+
+ private:
+ const char * m_ptr;
+ };
+
+} // nv namespace
+
+#endif // NV_CORE_STRING_H
diff --git a/thirdparty/thekla_atlas/nvcore/Stream.h b/thirdparty/thekla_atlas/nvcore/Stream.h
new file mode 100644
index 0000000000..c35c0d0c78
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Stream.h
@@ -0,0 +1,164 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_STREAM_H
+#define NV_CORE_STREAM_H
+
+#include "nvcore.h"
+#include "Debug.h"
+
+namespace nv
+{
+
+ /// Base stream class.
+ class NVCORE_CLASS Stream {
+ public:
+
+ enum ByteOrder {
+ LittleEndian = false,
+ BigEndian = true,
+ };
+
+ /// Get the byte order of the system.
+ static ByteOrder getSystemByteOrder() {
+#if NV_LITTLE_ENDIAN
+ return LittleEndian;
+#else
+ return BigEndian;
+#endif
+ }
+
+
+ /// Ctor.
+ Stream() : m_byteOrder(LittleEndian) { }
+
+ /// Virtual destructor.
+ virtual ~Stream() {}
+
+ /// Set byte order.
+ void setByteOrder(ByteOrder bo) { m_byteOrder = bo; }
+
+ /// Get byte order.
+ ByteOrder byteOrder() const { return m_byteOrder; }
+
+
+ /// Serialize the given data.
+ virtual uint serialize( void * data, uint len ) = 0;
+
+ /// Move to the given position in the archive.
+ virtual void seek( uint pos ) = 0;
+
+ /// Return the current position in the archive.
+ virtual uint tell() const = 0;
+
+ /// Return the current size of the archive.
+ virtual uint size() const = 0;
+
+ /// Determine if there has been any error.
+ virtual bool isError() const = 0;
+
+ /// Clear errors.
+ virtual void clearError() = 0;
+
+ /// Return true if the stream is at the end.
+ virtual bool isAtEnd() const = 0;
+
+ /// Return true if the stream is seekable.
+ virtual bool isSeekable() const = 0;
+
+ /// Return true if this is an input stream.
+ virtual bool isLoading() const = 0;
+
+ /// Return true if this is an output stream.
+ virtual bool isSaving() const = 0;
+
+
+ void advance(uint offset) { seek(tell() + offset); }
+
+
+ // friends
+ friend Stream & operator<<( Stream & s, bool & c ) {
+#if NV_OS_DARWIN && !NV_CC_CPP11
+ nvStaticCheck(sizeof(bool) == 4);
+ uint8 b = c ? 1 : 0;
+ s.serialize( &b, 1 );
+ c = (b != 0);
+#else
+ nvStaticCheck(sizeof(bool) == 1);
+ s.serialize( &c, 1 );
+#endif
+ return s;
+ }
+ friend Stream & operator<<( Stream & s, char & c ) {
+ nvStaticCheck(sizeof(char) == 1);
+ s.serialize( &c, 1 );
+ return s;
+ }
+ friend Stream & operator<<( Stream & s, uint8 & c ) {
+ nvStaticCheck(sizeof(uint8) == 1);
+ s.serialize( &c, 1 );
+ return s;
+ }
+ friend Stream & operator<<( Stream & s, int8 & c ) {
+ nvStaticCheck(sizeof(int8) == 1);
+ s.serialize( &c, 1 );
+ return s;
+ }
+ friend Stream & operator<<( Stream & s, uint16 & c ) {
+ nvStaticCheck(sizeof(uint16) == 2);
+ return s.byteOrderSerialize( &c, 2 );
+ }
+ friend Stream & operator<<( Stream & s, int16 & c ) {
+ nvStaticCheck(sizeof(int16) == 2);
+ return s.byteOrderSerialize( &c, 2 );
+ }
+ friend Stream & operator<<( Stream & s, uint32 & c ) {
+ nvStaticCheck(sizeof(uint32) == 4);
+ return s.byteOrderSerialize( &c, 4 );
+ }
+ friend Stream & operator<<( Stream & s, int32 & c ) {
+ nvStaticCheck(sizeof(int32) == 4);
+ return s.byteOrderSerialize( &c, 4 );
+ }
+ friend Stream & operator<<( Stream & s, uint64 & c ) {
+ nvStaticCheck(sizeof(uint64) == 8);
+ return s.byteOrderSerialize( &c, 8 );
+ }
+ friend Stream & operator<<( Stream & s, int64 & c ) {
+ nvStaticCheck(sizeof(int64) == 8);
+ return s.byteOrderSerialize( &c, 8 );
+ }
+ friend Stream & operator<<( Stream & s, float & c ) {
+ nvStaticCheck(sizeof(float) == 4);
+ return s.byteOrderSerialize( &c, 4 );
+ }
+ friend Stream & operator<<( Stream & s, double & c ) {
+ nvStaticCheck(sizeof(double) == 8);
+ return s.byteOrderSerialize( &c, 8 );
+ }
+
+ protected:
+
+ /// Serialize in the stream byte order.
+ Stream & byteOrderSerialize( void * v, uint len ) {
+ if( m_byteOrder == getSystemByteOrder() ) {
+ serialize( v, len );
+ }
+ else {
+ for( uint i = len; i > 0; i-- ) {
+ serialize( (uint8 *)v + i - 1, 1 );
+ }
+ }
+ return *this;
+ }
+
+
+ private:
+
+ ByteOrder m_byteOrder;
+
+ };
+
+} // nv namespace
+
+#endif // NV_CORE_STREAM_H
diff --git a/thirdparty/thekla_atlas/nvcore/Utils.h b/thirdparty/thekla_atlas/nvcore/Utils.h
new file mode 100644
index 0000000000..f20e42cda8
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/Utils.h
@@ -0,0 +1,315 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_UTILS_H
+#define NV_CORE_UTILS_H
+
+#include "Debug.h" // nvDebugCheck
+
+#include <new> // for placement new
+
+
+// Just in case. Grrr.
+#undef min
+#undef max
+
+#define NV_INT8_MIN (-128)
+#define NV_INT8_MAX 127
+#define NV_UINT8_MAX 255
+#define NV_INT16_MIN (-32767-1)
+#define NV_INT16_MAX 32767
+#define NV_UINT16_MAX 0xffff
+#define NV_INT32_MIN (-2147483647-1)
+#define NV_INT32_MAX 2147483647
+#define NV_UINT32_MAX 0xffffffff
+#define NV_INT64_MAX POSH_I64(9223372036854775807)
+#define NV_INT64_MIN (-POSH_I64(9223372036854775807)-1)
+#define NV_UINT64_MAX POSH_U64(0xffffffffffffffff)
+
+#define NV_HALF_MAX 65504.0F
+#define NV_FLOAT_MAX 3.402823466e+38F
+
+#define NV_INTEGER_TO_FLOAT_MAX 16777217 // Largest integer such that it and all smaller integers can be stored in a 32bit float.
+
+
+namespace nv
+{
+ // Less error prone than casting. From CB:
+ // http://cbloomrants.blogspot.com/2011/06/06-17-11-c-casting-is-devil.html
+
+ // These intentionally look like casts.
+
+ // uint64 casts:
+ template <typename T> inline uint64 U64(T x) { return x; }
+ //template <> inline uint64 U64<uint64>(uint64 x) { return x; }
+ template <> inline uint64 U64<int64>(int64 x) { nvDebugCheck(x >= 0); return (uint64)x; }
+ //template <> inline uint64 U32<uint32>(uint32 x) { return x; }
+ template <> inline uint64 U64<int32>(int32 x) { nvDebugCheck(x >= 0); return (uint64)x; }
+ //template <> inline uint64 U64<uint16>(uint16 x) { return x; }
+ template <> inline uint64 U64<int16>(int16 x) { nvDebugCheck(x >= 0); return (uint64)x; }
+ //template <> inline uint64 U64<uint8>(uint8 x) { return x; }
+ template <> inline uint64 U64<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint64)x; }
+
+ // int64 casts:
+ template <typename T> inline int64 I64(T x) { return x; }
+ template <> inline int64 I64<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT64_MAX); return (int64)x; }
+ //template <> inline uint64 U64<int64>(int64 x) { return x; }
+ //template <> inline uint64 U32<uint32>(uint32 x) { return x; }
+ //template <> inline uint64 U64<int32>(int32 x) { return x; }
+ //template <> inline uint64 U64<uint16>(uint16 x) { return x; }
+ //template <> inline uint64 U64<int16>(int16 x) { return x; }
+ //template <> inline uint64 U64<uint8>(uint8 x) { return x; }
+ //template <> inline uint64 U64<int8>(int8 x) { return x; }
+
+ // uint32 casts:
+ template <typename T> inline uint32 U32(T x) { return x; }
+ template <> inline uint32 U32<uint64>(uint64 x) { nvDebugCheck(x <= NV_UINT32_MAX); return (uint32)x; }
+ template <> inline uint32 U32<int64>(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT32_MAX); return (uint32)x; }
+ //template <> inline uint32 U32<uint32>(uint32 x) { return x; }
+ template <> inline uint32 U32<int32>(int32 x) { nvDebugCheck(x >= 0); return (uint32)x; }
+ //template <> inline uint32 U32<uint16>(uint16 x) { return x; }
+ template <> inline uint32 U32<int16>(int16 x) { nvDebugCheck(x >= 0); return (uint32)x; }
+ //template <> inline uint32 U32<uint8>(uint8 x) { return x; }
+ template <> inline uint32 U32<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint32)x; }
+
+ // int32 casts:
+ template <typename T> inline int32 I32(T x) { return x; }
+ template <> inline int32 I32<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT32_MAX); return (int32)x; }
+ template <> inline int32 I32<int64>(int64 x) { nvDebugCheck(x >= NV_INT32_MIN && x <= NV_UINT32_MAX); return (int32)x; }
+ template <> inline int32 I32<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT32_MAX); return (int32)x; }
+ //template <> inline int32 I32<int32>(int32 x) { return x; }
+ //template <> inline int32 I32<uint16>(uint16 x) { return x; }
+ //template <> inline int32 I32<int16>(int16 x) { return x; }
+ //template <> inline int32 I32<uint8>(uint8 x) { return x; }
+ //template <> inline int32 I32<int8>(int8 x) { return x; }
+
+ // uint16 casts:
+ template <typename T> inline uint16 U16(T x) { return x; }
+ template <> inline uint16 U16<uint64>(uint64 x) { nvDebugCheck(x <= NV_UINT16_MAX); return (uint16)x; }
+ template <> inline uint16 U16<int64>(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT16_MAX); return (uint16)x; }
+ template <> inline uint16 U16<uint32>(uint32 x) { nvDebugCheck(x <= NV_UINT16_MAX); return (uint16)x; }
+ template <> inline uint16 U16<int32>(int32 x) { nvDebugCheck(x >= 0 && x <= NV_UINT16_MAX); return (uint16)x; }
+ //template <> inline uint16 U16<uint16>(uint16 x) { return x; }
+ template <> inline uint16 U16<int16>(int16 x) { nvDebugCheck(x >= 0); return (uint16)x; }
+ //template <> inline uint16 U16<uint8>(uint8 x) { return x; }
+ template <> inline uint16 U16<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint16)x; }
+
+ // int16 casts:
+ template <typename T> inline int16 I16(T x) { return x; }
+ template <> inline int16 I16<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; }
+ template <> inline int16 I16<int64>(int64 x) { nvDebugCheck(x >= NV_INT16_MIN && x <= NV_UINT16_MAX); return (int16)x; }
+ template <> inline int16 I16<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; }
+ template <> inline int16 I16<int32>(int32 x) { nvDebugCheck(x >= NV_INT16_MIN && x <= NV_UINT16_MAX); return (int16)x; }
+ template <> inline int16 I16<uint16>(uint16 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; }
+ //template <> inline int16 I16<int16>(int16 x) { return x; }
+ //template <> inline int16 I16<uint8>(uint8 x) { return x; }
+ //template <> inline int16 I16<int8>(int8 x) { return x; }
+
+ // uint8 casts:
+ template <typename T> inline uint8 U8(T x) { return x; }
+ template <> inline uint8 U8<uint64>(uint64 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; }
+ template <> inline uint8 U8<int64>(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; }
+ template <> inline uint8 U8<uint32>(uint32 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; }
+ template <> inline uint8 U8<int32>(int32 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; }
+ template <> inline uint8 U8<uint16>(uint16 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; }
+ template <> inline uint8 U8<int16>(int16 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; }
+ //template <> inline uint8 U8<uint8>(uint8 x) { return x; }
+ template <> inline uint8 U8<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint8)x; }
+ //template <> inline uint8 U8<float>(int8 x) { nvDebugCheck(x >= 0.0f && x <= 255.0f); return (uint8)x; }
+
+ // int8 casts:
+ template <typename T> inline int8 I8(T x) { return x; }
+ template <> inline int8 I8<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
+ template <> inline int8 I8<int64>(int64 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
+ template <> inline int8 I8<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
+ template <> inline int8 I8<int32>(int32 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
+ template <> inline int8 I8<uint16>(uint16 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
+ template <> inline int8 I8<int16>(int16 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
+ template <> inline int8 I8<uint8>(uint8 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
+ //template <> inline int8 I8<int8>(int8 x) { return x; }
+
+ // float casts:
+ template <typename T> inline float F32(T x) { return x; }
+ template <> inline float F32<uint64>(uint64 x) { nvDebugCheck(x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
+ template <> inline float F32<int64>(int64 x) { nvDebugCheck(x >= -NV_INTEGER_TO_FLOAT_MAX && x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
+ template <> inline float F32<uint32>(uint32 x) { nvDebugCheck(x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
+ template <> inline float F32<int32>(int32 x) { nvDebugCheck(x >= -NV_INTEGER_TO_FLOAT_MAX && x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
+ // The compiler should not complain about these conversions:
+ //template <> inline float F32<uint16>(uint16 x) { nvDebugCheck(return (float)x; }
+ //template <> inline float F32<int16>(int16 x) { nvDebugCheck(return (float)x; }
+ //template <> inline float F32<uint8>(uint8 x) { nvDebugCheck(return (float)x; }
+ //template <> inline float F32<int8>(int8 x) { nvDebugCheck(return (float)x; }
+
+
+ /// Swap two values.
+ template <typename T>
+ inline void swap(T & a, T & b)
+ {
+ T temp(a);
+ a = b;
+ b = temp;
+ }
+
+ /// Return the maximum of the two arguments. For floating point values, it returns the second value if the first is NaN.
+ template <typename T>
+ //inline const T & max(const T & a, const T & b)
+ inline T max(const T & a, const T & b)
+ {
+ return (b < a) ? a : b;
+ }
+
+ /// Return the maximum of the four arguments.
+ template <typename T>
+ //inline const T & max4(const T & a, const T & b, const T & c)
+ inline T max4(const T & a, const T & b, const T & c, const T & d)
+ {
+ return max(max(a, b), max(c, d));
+ }
+
+ /// Return the maximum of the three arguments.
+ template <typename T>
+ //inline const T & max3(const T & a, const T & b, const T & c)
+ inline T max3(const T & a, const T & b, const T & c)
+ {
+ return max(a, max(b, c));
+ }
+
+ /// Return the minimum of two values.
+ template <typename T>
+ //inline const T & min(const T & a, const T & b)
+ inline T min(const T & a, const T & b)
+ {
+ return (a < b) ? a : b;
+ }
+
+ /// Return the maximum of the three arguments.
+ template <typename T>
+ //inline const T & min3(const T & a, const T & b, const T & c)
+ inline T min3(const T & a, const T & b, const T & c)
+ {
+ return min(a, min(b, c));
+ }
+
+ /// Clamp between two values.
+ template <typename T>
+ //inline const T & clamp(const T & x, const T & a, const T & b)
+ inline T clamp(const T & x, const T & a, const T & b)
+ {
+ return min(max(x, a), b);
+ }
+
+ /** Return the next power of two.
+ * @see http://graphics.stanford.edu/~seander/bithacks.html
+ * @warning Behaviour for 0 is undefined.
+ * @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x
+ * @note nextPowerOfTwo(x) = 2 << log2(x-1)
+ */
+ inline uint32 nextPowerOfTwo(uint32 x)
+ {
+ nvDebugCheck( x != 0 );
+#if 1 // On modern CPUs this is supposed to be as fast as using the bsr instruction.
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x+1;
+#else
+ uint p = 1;
+ while( x > p ) {
+ p += p;
+ }
+ return p;
+#endif
+ }
+
+ inline uint64 nextPowerOfTwo(uint64 x)
+ {
+ nvDebugCheck(x != 0);
+ uint p = 1;
+ while (x > p) {
+ p += p;
+ }
+ return p;
+ }
+
+ // @@ Should I just use a macro instead?
+ template <typename T>
+ inline bool isPowerOfTwo(T n)
+ {
+ return (n & (n-1)) == 0;
+ }
+
+
+ // @@ Move this to utils?
+ /// Delete all the elements of a container.
+ template <typename T>
+ void deleteAll(T & container)
+ {
+ for (typename T::PseudoIndex i = container.start(); !container.isDone(i); container.advance(i))
+ {
+ delete container[i];
+ }
+ }
+
+
+
+ // @@ Specialize these methods for numeric, pointer, and pod types.
+
+ template <typename T>
+ void construct_range(T * restrict ptr, uint new_size, uint old_size) {
+ for (uint i = old_size; i < new_size; i++) {
+ new(ptr+i) T; // placement new
+ }
+ }
+
+ template <typename T>
+ void construct_range(T * restrict ptr, uint new_size, uint old_size, const T & elem) {
+ for (uint i = old_size; i < new_size; i++) {
+ new(ptr+i) T(elem); // placement new
+ }
+ }
+
+ template <typename T>
+ void construct_range(T * restrict ptr, uint new_size, uint old_size, const T * src) {
+ for (uint i = old_size; i < new_size; i++) {
+ new(ptr+i) T(src[i]); // placement new
+ }
+ }
+
+ template <typename T>
+ void destroy_range(T * restrict ptr, uint new_size, uint old_size) {
+ for (uint i = new_size; i < old_size; i++) {
+ (ptr+i)->~T(); // Explicit call to the destructor
+ }
+ }
+
+ template <typename T>
+ void fill(T * restrict dst, uint count, const T & value) {
+ for (uint i = 0; i < count; i++) {
+ dst[i] = value;
+ }
+ }
+
+ template <typename T>
+ void copy_range(T * restrict dst, const T * restrict src, uint count) {
+ for (uint i = 0; i < count; i++) {
+ dst[i] = src[i];
+ }
+ }
+
+ template <typename T>
+ bool find(const T & element, const T * restrict ptr, uint begin, uint end, uint * index) {
+ for (uint i = begin; i < end; i++) {
+ if (ptr[i] == element) {
+ if (index != NULL) *index = i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+} // nv namespace
+
+#endif // NV_CORE_UTILS_H
diff --git a/thirdparty/thekla_atlas/nvcore/nvcore.h b/thirdparty/thekla_atlas/nvcore/nvcore.h
new file mode 100644
index 0000000000..a3deb66be2
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/nvcore.h
@@ -0,0 +1,357 @@
+// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
+
+#pragma once
+#ifndef NV_CORE_H
+#define NV_CORE_H
+
+// Function linkage
+#if NVCORE_SHARED
+#ifdef NVCORE_EXPORTS
+#define NVCORE_API DLL_EXPORT
+#define NVCORE_CLASS DLL_EXPORT_CLASS
+#else
+#define NVCORE_API DLL_IMPORT
+#define NVCORE_CLASS DLL_IMPORT
+#endif
+#else // NVCORE_SHARED
+#define NVCORE_API
+#define NVCORE_CLASS
+#endif // NVCORE_SHARED
+
+
+// Platform definitions
+#include <posh.h>
+
+// OS:
+// NV_OS_WIN32
+// NV_OS_WIN64
+// NV_OS_MINGW
+// NV_OS_CYGWIN
+// NV_OS_LINUX
+// NV_OS_UNIX
+// NV_OS_DARWIN
+// NV_OS_XBOX
+// NV_OS_ORBIS
+// NV_OS_IOS
+
+#define NV_OS_STRING POSH_OS_STRING
+
+#if defined POSH_OS_LINUX
+# define NV_OS_LINUX 1
+# define NV_OS_UNIX 1
+#elif defined POSH_OS_ORBIS
+# define NV_OS_ORBIS 1
+#elif defined POSH_OS_FREEBSD
+# define NV_OS_FREEBSD 1
+# define NV_OS_UNIX 1
+#elif defined POSH_OS_OPENBSD
+# define NV_OS_OPENBSD 1
+# define NV_OS_UNIX 1
+#elif defined POSH_OS_CYGWIN32
+# define NV_OS_CYGWIN 1
+#elif defined POSH_OS_MINGW
+# define NV_OS_MINGW 1
+# define NV_OS_WIN32 1
+#elif defined POSH_OS_OSX
+# define NV_OS_OSX 1 // IC: Adding this, because iOS defines NV_OS_DARWIN too.
+# define NV_OS_DARWIN 1
+# define NV_OS_UNIX 1
+#elif defined POSH_OS_IOS
+# define NV_OS_DARWIN 1 //ACS should we keep this on IOS?
+# define NV_OS_UNIX 1
+# define NV_OS_IOS 1
+#elif defined POSH_OS_UNIX
+# define NV_OS_UNIX 1
+#elif defined POSH_OS_WIN64
+# define NV_OS_WIN32 1
+# define NV_OS_WIN64 1
+#elif defined POSH_OS_WIN32
+# define NV_OS_WIN32 1
+#elif defined POSH_OS_XBOX
+# define NV_OS_XBOX 1
+#elif defined POSH_OS_DURANGO
+# define NV_OS_DURANGO 1
+#else
+# error "Unsupported OS"
+#endif
+
+
+// Is this a console OS? (i.e. connected to a TV)
+#if NV_OS_ORBIS || NV_OS_XBOX || NV_OS_DURANGO
+# define NV_OS_CONSOLE 1
+#endif
+
+
+// Threading:
+// some platforms don't implement __thread or similar for thread-local-storage
+#if NV_OS_UNIX || NV_OS_ORBIS || NV_OS_IOS //ACStodoIOS darwin instead of ios?
+# define NV_OS_USE_PTHREAD 1
+# if NV_OS_IOS
+# define NV_OS_HAS_TLS_QUALIFIER 0
+# else
+# define NV_OS_HAS_TLS_QUALIFIER 1
+# endif
+#else
+# define NV_OS_USE_PTHREAD 0
+# define NV_OS_HAS_TLS_QUALIFIER 1
+#endif
+
+
+// CPUs:
+// NV_CPU_X86
+// NV_CPU_X86_64
+// NV_CPU_PPC
+// NV_CPU_ARM
+
+#define NV_CPU_STRING POSH_CPU_STRING
+
+#if defined POSH_CPU_X86_64
+//# define NV_CPU_X86 1
+# define NV_CPU_X86_64 1
+#elif defined POSH_CPU_X86
+# define NV_CPU_X86 1
+#elif defined POSH_CPU_PPC
+# define NV_CPU_PPC 1
+#elif defined POSH_CPU_STRONGARM
+# define NV_CPU_ARM 1
+#else
+# error "Unsupported CPU"
+#endif
+
+
+// Compiler:
+// NV_CC_GNUC
+// NV_CC_MSVC
+// NV_CC_CLANG
+
+#if defined POSH_COMPILER_CLANG
+# define NV_CC_CLANG 1
+# define NV_CC_GNUC 1 // Clang is compatible with GCC.
+# define NV_CC_STRING "clang"
+#elif defined POSH_COMPILER_GCC
+# define NV_CC_GNUC 1
+# define NV_CC_STRING "gcc"
+#elif defined POSH_COMPILER_MSVC
+# define NV_CC_MSVC 1
+# define NV_CC_STRING "msvc"
+#else
+# error "Unsupported compiler"
+#endif
+
+#if NV_CC_MSVC
+#define NV_CC_CPP11 (__cplusplus > 199711L || _MSC_VER >= 1800) // Visual Studio 2013 has all the features we use, but doesn't advertise full C++11 support yet.
+#else
+// @@ IC: This works in CLANG, about GCC?
+// @@ ES: Doesn't work in gcc. These 3 features are available in GCC >= 4.4.
+#ifdef __clang__
+#define NV_CC_CPP11 (__has_feature(cxx_deleted_functions) && __has_feature(cxx_rvalue_references) && __has_feature(cxx_static_assert))
+#elif defined __GNUC__
+#define NV_CC_CPP11 ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
+#endif
+#endif
+
+// Endiannes:
+#define NV_LITTLE_ENDIAN POSH_LITTLE_ENDIAN
+#define NV_BIG_ENDIAN POSH_BIG_ENDIAN
+#define NV_ENDIAN_STRING POSH_ENDIAN_STRING
+
+
+// Define the right printf prefix for size_t arguments:
+#if POSH_64BIT_POINTER
+# define NV_SIZET_PRINTF_PREFIX POSH_I64_PRINTF_PREFIX
+#else
+# define NV_SIZET_PRINTF_PREFIX
+#endif
+
+
+// cmake config
+#include "nvconfig.h"
+
+#if NV_OS_DARWIN
+#include <stdint.h>
+//#include <inttypes.h>
+
+// Type definitions:
+typedef uint8_t uint8;
+typedef int8_t int8;
+
+typedef uint16_t uint16;
+typedef int16_t int16;
+
+typedef uint32_t uint32;
+typedef int32_t int32;
+
+typedef uint64_t uint64;
+typedef int64_t int64;
+
+// POSH gets this wrong due to __LP64__
+#undef POSH_I64_PRINTF_PREFIX
+#define POSH_I64_PRINTF_PREFIX "ll"
+
+#else
+
+// Type definitions:
+typedef posh_u8_t uint8;
+typedef posh_i8_t int8;
+
+typedef posh_u16_t uint16;
+typedef posh_i16_t int16;
+
+typedef posh_u32_t uint32;
+typedef posh_i32_t int32;
+
+//#if NV_OS_DARWIN
+// OSX-64 is supposed to be LP64 (longs and pointers are 64 bits), thus uint64 is defined as
+// unsigned long. However, some OSX headers define it as unsigned long long, producing errors,
+// even though both types are 64 bit. Ideally posh should handle that, but it has not been
+// updated in ages, so here I'm just falling back to the standard C99 types defined in inttypes.h
+//#include <inttypes.h>
+//typedef posh_u64_t uint64_t;
+//typedef posh_i64_t int64_t;
+//#else
+typedef posh_u64_t uint64;
+typedef posh_i64_t int64;
+//#endif
+#if NV_OS_DARWIN
+// To avoid duplicate definitions.
+#define _UINT64
+#endif
+#endif
+
+// Aliases
+typedef uint32 uint;
+
+
+// Version string:
+#define NV_VERSION_STRING \
+ NV_OS_STRING "/" NV_CC_STRING "/" NV_CPU_STRING"/" \
+ NV_ENDIAN_STRING"-endian - " __DATE__ "-" __TIME__
+
+
+// Disable copy constructor and assignment operator.
+#if NV_CC_CPP11
+#define NV_FORBID_COPY(C) \
+ C( const C & ) = delete; \
+ C &operator=( const C & ) = delete
+#else
+#define NV_FORBID_COPY(C) \
+ private: \
+ C( const C & ); \
+ C &operator=( const C & )
+#endif
+
+// Disable dynamic allocation on the heap.
+// See Prohibiting Heap-Based Objects in More Effective C++.
+#define NV_FORBID_HEAPALLOC() \
+ private: \
+ void *operator new(size_t size); \
+ void *operator new[](size_t size)
+ //static void *operator new(size_t size); \
+ //static void *operator new[](size_t size);
+
+// String concatenation macros.
+#define NV_STRING_JOIN2(arg1, arg2) NV_DO_STRING_JOIN2(arg1, arg2)
+#define NV_DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
+#define NV_STRING_JOIN3(arg1, arg2, arg3) NV_DO_STRING_JOIN3(arg1, arg2, arg3)
+#define NV_DO_STRING_JOIN3(arg1, arg2, arg3) arg1 ## arg2 ## arg3
+#define NV_STRING2(x) #x
+#define NV_STRING(x) NV_STRING2(x)
+
+#if NV_CC_MSVC
+#define NV_MULTI_LINE_MACRO_BEGIN do {
+#define NV_MULTI_LINE_MACRO_END \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4127)) \
+ } while(false) \
+ __pragma(warning(pop))
+#else
+#define NV_MULTI_LINE_MACRO_BEGIN do {
+#define NV_MULTI_LINE_MACRO_END } while(false)
+#endif
+
+#if NV_CC_CPP11
+#define nvStaticCheck(x) static_assert((x), "Static assert "#x" failed")
+#else
+#define nvStaticCheck(x) typedef char NV_STRING_JOIN2(__static_assert_,__LINE__)[(x)]
+#endif
+#define NV_COMPILER_CHECK(x) nvStaticCheck(x) // I like this name best.
+
+// Make sure type definitions are fine.
+NV_COMPILER_CHECK(sizeof(int8) == 1);
+NV_COMPILER_CHECK(sizeof(uint8) == 1);
+NV_COMPILER_CHECK(sizeof(int16) == 2);
+NV_COMPILER_CHECK(sizeof(uint16) == 2);
+NV_COMPILER_CHECK(sizeof(int32) == 4);
+NV_COMPILER_CHECK(sizeof(uint32) == 4);
+NV_COMPILER_CHECK(sizeof(int32) == 4);
+NV_COMPILER_CHECK(sizeof(uint32) == 4);
+
+#include <stddef.h> // for size_t
+template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+#define NV_ARRAY_SIZE(x) sizeof(ArraySizeHelper(x))
+//#define NV_ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+#if 0 // Disabled in The Witness.
+#if NV_CC_MSVC
+#define NV_MESSAGE(x) message(__FILE__ "(" NV_STRING(__LINE__) ") : " x)
+#else
+#define NV_MESSAGE(x) message(x)
+#endif
+#else
+#define NV_MESSAGE(x)
+#endif
+
+
+// Startup initialization macro.
+#define NV_AT_STARTUP(some_code) \
+ namespace { \
+ static struct NV_STRING_JOIN2(AtStartup_, __LINE__) { \
+ NV_STRING_JOIN2(AtStartup_, __LINE__)() { some_code; } \
+ } \
+ NV_STRING_JOIN3(AtStartup_, __LINE__, Instance); \
+ }
+
+// Indicate the compiler that the parameter is not used to suppress compier warnings.
+#if NV_CC_MSVC
+#define NV_UNUSED(a) ((a)=(a))
+#else
+#define NV_UNUSED(a) _Pragma(NV_STRING(unused(a)))
+#endif
+
+// Null index. @@ Move this somewhere else... it's only used by nvmesh.
+//const unsigned int NIL = unsigned int(~0);
+#define NIL uint(~0)
+
+// Null pointer.
+#ifndef NULL
+#define NULL 0
+#endif
+
+// Platform includes
+#if NV_CC_MSVC
+# if NV_OS_WIN32
+# include "DefsVcWin32.h"
+# elif NV_OS_XBOX
+# include "DefsVcXBox.h"
+# elif NV_OS_DURANGO
+# include "DefsVcDurango.h"
+# else
+# error "MSVC: Platform not supported"
+# endif
+#elif NV_CC_GNUC
+# if NV_OS_LINUX
+# include "DefsGnucLinux.h"
+# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD
+# include "DefsGnucDarwin.h"
+# elif NV_OS_ORBIS
+# include "DefsOrbis.h"
+# elif NV_OS_MINGW
+# include "DefsGnucWin32.h"
+# elif NV_OS_CYGWIN
+# error "GCC: Cygwin not supported"
+# else
+# error "GCC: Platform not supported"
+# endif
+#endif
+
+#endif // NV_CORE_H
diff --git a/thirdparty/thekla_atlas/nvcore/scanf.c b/thirdparty/thekla_atlas/nvcore/scanf.c
new file mode 100644
index 0000000000..bf9d293154
--- /dev/null
+++ b/thirdparty/thekla_atlas/nvcore/scanf.c
@@ -0,0 +1,641 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: Id: vfscanf.c,v 1.13 1998/09/25 12:20:27 obrien Exp
+ * From: static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+ * From: static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma warning(disable : 4244) // conversion from '*' to '*', possible loss of data
+#pragma warning(disable : 4018) // signed/unsigned mismatch
+#pragma warning(disable : 4267) // '=' : conversion from 'size_t' to 'int', possible loss of data
+
+#define strtoq _strtoi64
+#define strtouq _strtoui64
+#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
+
+typedef int long long quad_t;
+typedef unsigned long long u_quad_t;
+typedef unsigned char u_char;
+
+#define BUF 32 /* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define LONG 0x01 /* l: long or double */
+#define SHORT 0x04 /* h: short */
+#define SUPPRESS 0x08 /* suppress assignment */
+#define POINTER 0x10 /* weird %p pointer (`fake hex') */
+#define NOSKIP 0x20 /* do not skip blanks */
+#define QUAD 0x400
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+#define SIGNOK 0x40 /* +/- is (still) legal */
+#define NDIGITS 0x80 /* no digits detected */
+
+#define DPTOK 0x100 /* (float) decimal point is still legal */
+#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
+
+#define PFXOK 0x100 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x200 /* no zero digits detected */
+
+/*
+ * Conversion types.
+ */
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* integer, i.e., strtoq or strtouq */
+typedef u_quad_t (*ccfntype)(const char *, char **, int);
+
+static const u_char *__sccl(char *, const u_char *);
+
+int
+vsscanf(const char *inp, char const *fmt0, va_list ap)
+{
+ int inr;
+ const u_char *fmt = (const u_char *)fmt0;
+ int c; /* character from format, or conversion */
+ size_t width; /* field width, or 0 */
+ char *p; /* points into all kinds of strings */
+ int n; /* handy integer */
+ int flags; /* flags as defined above */
+ char *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nconversions; /* number of conversions */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to strtoq/strtouq */
+ ccfntype ccfn; /* conversion function (strtoq/strtouq) */
+ char ccltab[256]; /* character class table for %[...] */
+ char buf[BUF]; /* buffer for numeric conversions */
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ inr = strlen(inp);
+
+ nassigned = 0;
+ nconversions = 0;
+ nread = 0;
+ base = 0; /* XXX just to keep gcc happy */
+ ccfn = NULL; /* XXX just to keep gcc happy */
+ for (;;) {
+ c = *fmt++;
+ if (c == 0)
+ return (nassigned);
+ if (isspace(c)) {
+ while (inr > 0 && isspace(*inp))
+ nread++, inr--, inp++;
+ continue;
+ }
+ if (c != '%')
+ goto literal;
+ width = 0;
+ flags = 0;
+ /*
+ * switch on the format. continue if done;
+ * break once format type is derived.
+ */
+again: c = *fmt++;
+ switch (c) {
+ case '%':
+literal:
+ if (inr <= 0)
+ goto input_failure;
+ if (*inp != c)
+ goto match_failure;
+ inr--, inp++;
+ nread++;
+ continue;
+
+ case '*':
+ flags |= SUPPRESS;
+ goto again;
+ case 'l':
+ flags |= LONG;
+ goto again;
+ case 'q':
+ flags |= QUAD;
+ goto again;
+ case 'h':
+ flags |= SHORT;
+ goto again;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ width = width * 10 + c - '0';
+ goto again;
+
+ /*
+ * Conversions.
+ *
+ */
+ case 'd':
+ c = CT_INT;
+ ccfn = (ccfntype)strtoq;
+ base = 10;
+ break;
+
+ case 'i':
+ c = CT_INT;
+ ccfn = (ccfntype)strtoq;
+ base = 0;
+ break;
+
+ case 'o':
+ c = CT_INT;
+ ccfn = strtouq;
+ base = 8;
+ break;
+
+ case 'u':
+ c = CT_INT;
+ ccfn = strtouq;
+ base = 10;
+ break;
+
+ case 'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ ccfn = strtouq;
+ base = 16;
+ break;
+
+ case 's':
+ c = CT_STRING;
+ break;
+
+ case '[':
+ fmt = __sccl(ccltab, fmt);
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT;
+ ccfn = strtouq;
+ base = 16;
+ break;
+
+ case 'n':
+ nconversions++;
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+ if (flags & SHORT)
+ *va_arg(ap, short *) = nread;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = nread;
+ else if (flags & QUAD)
+ *va_arg(ap, quad_t *) = nread;
+ else
+ *va_arg(ap, int *) = nread;
+ continue;
+ }
+
+ /*
+ * We have a conversion that requires input.
+ */
+ if (inr <= 0)
+ goto input_failure;
+
+ /*
+ * Consume leading white space, except for formats
+ * that suppress this.
+ */
+ if ((flags & NOSKIP) == 0) {
+ while (isspace(*inp)) {
+ nread++;
+ if (--inr > 0)
+ inp++;
+ else
+ goto input_failure;
+ }
+ /*
+ * Note that there is at least one character in
+ * the buffer, so conversions that do not set NOSKIP
+ * can no longer result in an input failure.
+ */
+ }
+
+ /*
+ * Do the conversion.
+ */
+ switch (c) {
+
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & SUPPRESS) {
+ size_t sum = 0;
+ for (;;) {
+ if ((n = inr) < width) {
+ sum += n;
+ width -= n;
+ inp += n;
+ if (sum == 0)
+ goto input_failure;
+ break;
+ } else {
+ sum += width;
+ inr -= width;
+ inp += width;
+ break;
+ }
+ }
+ nread += sum;
+ } else {
+ bcopy(inp, va_arg(ap, char *), width);
+ inr -= width;
+ inp += width;
+ nread += width;
+ nassigned++;
+ }
+ nconversions++;
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = (size_t)~0; /* `infinity' */
+ /* take only those things in the class */
+ if (flags & SUPPRESS) {
+ n = 0;
+ while (ccltab[(unsigned char)*inp]) {
+ n++, inr--, inp++;
+ if (--width == 0)
+ break;
+ if (inr <= 0) {
+ if (n == 0)
+ goto input_failure;
+ break;
+ }
+ }
+ if (n == 0)
+ goto match_failure;
+ } else {
+ p0 = p = va_arg(ap, char *);
+ while (ccltab[(unsigned char)*inp]) {
+ inr--;
+ *p++ = *inp++;
+ if (--width == 0)
+ break;
+ if (inr <= 0) {
+ if (p == p0)
+ goto input_failure;
+ break;
+ }
+ }
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ *p = 0;
+ nassigned++;
+ }
+ nread += n;
+ nconversions++;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if (flags & SUPPRESS) {
+ n = 0;
+ while (!isspace(*inp)) {
+ n++, inr--, inp++;
+ if (--width == 0)
+ break;
+ if (inr <= 0)
+ break;
+ }
+ nread += n;
+ } else {
+ p0 = p = va_arg(ap, char *);
+ while (!isspace(*inp)) {
+ inr--;
+ *p++ = *inp++;
+ if (--width == 0)
+ break;
+ if (inr <= 0)
+ break;
+ }
+ *p = 0;
+ nread += p - p0;
+ nassigned++;
+ }
+ nconversions++;
+ continue;
+
+ case CT_INT:
+ /* scan an integer as if by strtoq/strtouq */
+#ifdef hardway
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+#else
+ /* size_t is unsigned, hence this optimisation */
+ if (--width > sizeof(buf) - 2)
+ width = sizeof(buf) - 2;
+ width++;
+#endif
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width; width--) {
+ c = *inp;
+ /*
+ * Switch on the character; `goto ok'
+ * if we accept it as a part of number.
+ */
+ switch (c) {
+
+ /*
+ * The digit 0 is always legal, but is
+ * special. For %i conversions, if no
+ * digits (zero or nonzero) have been
+ * scanned (only signs), we will have
+ * base==0. In that case, we should set
+ * it to 8 and enable 0x prefixing.
+ * Also, if we have not scanned zero digits
+ * before this, do not turn off prefixing
+ * (someone else will turn it off if we
+ * have scanned any nonzero digits).
+ */
+ case '0':
+ if (base == 0) {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+ else
+ flags &= ~(SIGNOK|PFXOK|NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case '8': case '9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case '+': case '-':
+ if (flags & SIGNOK) {
+ flags &= ~SIGNOK;
+ goto ok;
+ }
+ break;
+
+ /* x ok iff flag still set & 2nd char */
+ case 'x': case 'X':
+ if (flags & PFXOK && p == buf + 1) {
+ base = 16; /* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ * If we got here, c is not a legal character
+ * for a number. Stop accumulating digits.
+ */
+ break;
+ ok:
+ /*
+ * c is legal: store it and look at the next.
+ */
+ *p++ = c;
+ if (--inr > 0)
+ inp++;
+ else
+ break; /* end of input */
+ }
+ /*
+ * If we had only a sign, it is no good; push
+ * back the sign. If the number ends in `x',
+ * it was [sign] '0' 'x', so push back the x
+ * and treat it as [sign] '0'.
+ */
+ if (flags & NDIGITS) {
+ if (p > buf) {
+ inp--;
+ inr++;
+ }
+ goto match_failure;
+ }
+ c = ((u_char *)p)[-1];
+ if (c == 'x' || c == 'X') {
+ --p;
+ inp--;
+ inr++;
+ }
+ if ((flags & SUPPRESS) == 0) {
+ u_quad_t res;
+
+ *p = 0;
+ res = (*ccfn)(buf, (char **)NULL, base);
+ if (flags & POINTER)
+ *va_arg(ap, void **) =
+ (void *)(uintptr_t)res;
+ else if (flags & SHORT)
+ *va_arg(ap, short *) = res;
+ else if (flags & LONG)
+ *va_arg(ap, long *) = res;
+ else if (flags & QUAD)
+ *va_arg(ap, quad_t *) = res;
+ else
+ *va_arg(ap, int *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ nconversions++;
+ break;
+
+ }
+ }
+input_failure:
+ return (nconversions != 0 ? nassigned : -1);
+match_failure:
+ return (nassigned);
+}
+
+
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `['). Return a pointer to the character past the
+ * closing `]'. The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+static const u_char *
+__sccl(char *tab, const u_char *fmt)
+{
+ int c, n, v;
+
+ /* first `clear' the whole table */
+ c = *fmt++; /* first char hat => negated scanset */
+ if (c == '^') {
+ v = 1; /* default => accept */
+ c = *fmt++; /* get new first char */
+ } else
+ v = 0; /* default => reject */
+
+ /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
+ for (n = 0; n < 256; n++)
+ tab[n] = v; /* memset(tab, v, 256) */
+
+ if (c == 0)
+ return (fmt - 1);/* format ended before closing ] */
+
+ /*
+ * Now set the entries corresponding to the actual scanset
+ * to the opposite of the above.
+ *
+ * The first character may be ']' (or '-') without being special;
+ * the last character may be '-'.
+ */
+ v = 1 - v;
+ for (;;) {
+ tab[c] = v; /* take character c */
+doswitch:
+ n = *fmt++; /* and examine the next */
+ switch (n) {
+
+ case 0: /* format ended too soon */
+ return (fmt - 1);
+
+ case '-':
+ /*
+ * A scanset of the form
+ * [01+-]
+ * is defined as `the digit 0, the digit 1,
+ * the character +, the character -', but
+ * the effect of a scanset such as
+ * [a-zA-Z0-9]
+ * is implementation defined. The V7 Unix
+ * scanf treats `a-z' as `the letters a through
+ * z', but treats `a-a' as `the letter a, the
+ * character -, and the letter a'.
+ *
+ * For compatibility, the `-' is not considerd
+ * to define a range if the character following
+ * it is either a close bracket (required by ANSI)
+ * or is not numerically greater than the character
+ * we just stored in the table (c).
+ */
+ n = *fmt;
+ if (n == ']' || n < c) {
+ c = '-';
+ break; /* resume the for(;;) */
+ }
+ fmt++;
+ /* fill in the range */
+ do {
+ tab[++c] = v;
+ } while (c < n);
+ c = n;
+ /*
+ * Alas, the V7 Unix scanf also treats formats
+ * such as [a-c-e] as `the letters a through e'.
+ * This too is permitted by the standard....
+ */
+ goto doswitch;
+ break;
+
+ case ']': /* end of scanset */
+ return (fmt);
+
+ default: /* just another character */
+ c = n;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+
+/*
+int
+sscanf(const char *ibuf, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vsscanf(ibuf, fmt, ap);
+ va_end(ap);
+
+ return(ret);
+}
+*/
+
+#ifdef __cplusplus
+}
+#endif