From 5fb8c15e15626a84af5ac3b2f4f5cc22c4357442 Mon Sep 17 00:00:00 2001 From: Martijn Courteaux Date: Sat, 1 Feb 2025 01:14:20 +0100 Subject: [PATCH] TinySTL attempt 3. (#342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update TinySTL (attempt 2). * Fix MSVC compilation issue for TinySTL. * Fix MSVC warning. * Favor ptrdiff_t for sizes in string. * Update genie.lua * Update math_test.cpp * Update test.h * Update test.h --------- Co-authored-by: Бранимир Караџић --- include/tinystl/LICENSE | 2 +- include/tinystl/allocator.h | 9 +- include/tinystl/buffer.h | 79 +++++++---- include/tinystl/hash.h | 4 +- include/tinystl/hash_base.h | 94 ++++++++++--- include/tinystl/new.h | 4 +- include/tinystl/stddef.h | 7 +- include/tinystl/string.h | 238 +++++++++++++++++++------------- include/tinystl/string_view.h | 147 ++++++++++++++++++++ include/tinystl/traits.h | 46 +++++- include/tinystl/unordered_map.h | 159 ++++++++++++++------- include/tinystl/unordered_set.h | 144 +++++++++++++------ include/tinystl/vector.h | 56 +++++--- scripts/genie.lua | 4 + scripts/update_tinystl.sh | 16 +++ tests/math_test.cpp | 1 + tests/string_test.cpp | 91 ++++++++++++ tests/test.h | 2 + tests/unordered_map_test.cpp | 205 +++++++++++++++++++++++++++ tests/unordered_set_test.cpp | 191 +++++++++++++++++++++++++ 20 files changed, 1229 insertions(+), 270 deletions(-) create mode 100644 include/tinystl/string_view.h create mode 100755 scripts/update_tinystl.sh create mode 100644 tests/unordered_map_test.cpp create mode 100644 tests/unordered_set_test.cpp diff --git a/include/tinystl/LICENSE b/include/tinystl/LICENSE index f03d947b0..bfea5915f 100644 --- a/include/tinystl/LICENSE +++ b/include/tinystl/LICENSE @@ -1,4 +1,4 @@ - Copyright 2012 Matthew Endsley + Copyright 2012-2018 Matthew Endsley All rights reserved Redistribution and use in source and binary forms, with or without diff --git a/include/tinystl/allocator.h b/include/tinystl/allocator.h index a0cce7ba3..ce3efe0a3 100644 --- a/include/tinystl/allocator.h +++ b/include/tinystl/allocator.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,9 +27,7 @@ #ifndef TINYSTL_ALLOCATOR_H #define TINYSTL_ALLOCATOR_H -#include "stddef.h" - -#ifndef TINYSTL_ALLOCATOR +#include namespace tinystl { @@ -44,7 +42,8 @@ namespace tinystl { }; } +#ifndef TINYSTL_ALLOCATOR # define TINYSTL_ALLOCATOR ::tinystl::allocator -#endif // TINYSTL_ALLOCATOR +#endif #endif diff --git a/include/tinystl/buffer.h b/include/tinystl/buffer.h index 4351ec202..efc5c9cc6 100644 --- a/include/tinystl/buffer.h +++ b/include/tinystl/buffer.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012-1015 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,8 +27,9 @@ #ifndef TINYSTL_BUFFER_H #define TINYSTL_BUFFER_H -#include "new.h" -#include "traits.h" +#include +#include +#include namespace tinystl { @@ -140,7 +141,7 @@ namespace tinystl { template static inline void buffer_reserve(buffer* b, size_t capacity) { - if (b->first + capacity <= b->capacity) + if (b->first && b->first + capacity <= b->capacity) return; typedef T* pointer; @@ -174,19 +175,21 @@ namespace tinystl { template static inline void buffer_shrink_to_fit(buffer* b) { - if (b->last == b->first) { - const size_t capacity = (size_t)(b->last - b->first); - Alloc::static_deallocate(b->first, sizeof(T)*capacity); - b->capacity = b->first; - } else if (b->capacity != b->last) { - const size_t capacity = (size_t)(b->capacity - b->first); - const size_t size = (size_t)(b->last - b->first); - T* newfirst = (T*)Alloc::static_allocate(sizeof(T) * size); - buffer_move_urange(newfirst, b->first, b->last); - Alloc::static_deallocate(b->first, sizeof(T) * capacity); - b->first = newfirst; - b->last = newfirst + size; - b->capacity = b->last; + if (b->capacity != b->last) { + if (b->last == b->first) { + const size_t capacity = (size_t)(b->capacity - b->first); + Alloc::static_deallocate(b->first, sizeof(T)*capacity); + b->capacity = b->first = b->last = nullptr; + } else { + const size_t capacity = (size_t)(b->capacity - b->first); + const size_t size = (size_t)(b->last - b->first); + T* newfirst = (T*)Alloc::static_allocate(sizeof(T) * size); + buffer_move_urange(newfirst, b->first, b->last); + Alloc::static_deallocate(b->first, sizeof(T) * capacity); + b->first = newfirst; + b->last = newfirst + size; + b->capacity = b->last; + } } } @@ -200,7 +203,7 @@ namespace tinystl { static inline T* buffer_insert_common(buffer* b, T* where, size_t count) { const size_t offset = (size_t)(where - b->first); const size_t newsize = (size_t)((b->last - b->first) + count); - if (b->first + newsize > b->capacity) + if (!b->first || b->first + newsize > b->capacity) buffer_reserve(b, (newsize * 3) / 2); where = b->first + offset; @@ -215,7 +218,21 @@ namespace tinystl { template static inline void buffer_insert(buffer* b, T* where, const Param* first, const Param* last) { - where = buffer_insert_common(b, where, last - first); + typedef const char* pointer; + const size_t count = last - first; + const bool frombuf = ((pointer)b->first <= (pointer)first && (pointer)b->last >= (pointer)last); + size_t offset; + if (frombuf) { + offset = (pointer)first - (pointer)b->first; + if ((pointer)where <= (pointer)first) + offset += count * sizeof(T); + where = buffer_insert_common(b, where, count); + first = (Param*)((pointer)b->first + offset); + last = first + count; + } + else { + where = buffer_insert_common(b, where, count); + } for (; first != last; ++first, ++where) new(placeholder(), where) T(*first); } @@ -223,7 +240,7 @@ namespace tinystl { template static inline void buffer_insert(buffer* b, T* where, size_t count) { where = buffer_insert_common(b, where, count); - for (size_t i = 0; i < count; ++i) + for (T* end = where+count; where != end; ++where) new(placeholder(), where) T(); } @@ -250,28 +267,28 @@ namespace tinystl { template static inline T* buffer_erase(buffer* b, T* first, T* last) { typedef T* pointer; - const size_t range = (last - first); + const size_t count = (last - first); for (pointer it = last, end = b->last, dest = first; it != end; ++it, ++dest) move(*dest, *it); - buffer_destroy_range(b->last - range, b->last); + buffer_destroy_range(b->last - count, b->last); - b->last -= range; + b->last -= count; return first; } template static inline T* buffer_erase_unordered(buffer* b, T* first, T* last) { typedef T* pointer; - const size_t range = (last - first); + const size_t count = (last - first); const size_t tail = (b->last - last); - pointer it = b->last - ((range < tail) ? range : tail); + pointer it = b->last - ((count < tail) ? count : tail); for (pointer end = b->last, dest = first; it != end; ++it, ++dest) move(*dest, *it); - buffer_destroy_range(b->last - range, b->last); + buffer_destroy_range(b->last - count, b->last); - b->last -= range; + b->last -= count; return first; } @@ -282,6 +299,12 @@ namespace tinystl { b->first = other->first, b->last = other->last, b->capacity = other->capacity; other->first = tfirst, other->last = tlast, other->capacity = tcapacity; } + + template + static inline void buffer_move(buffer* dst, buffer* src) { + dst->first = src->first, dst->last = src->last, dst->capacity = src->capacity; + src->first = src->last = src->capacity = nullptr; + } } -#endif +#endif //TINYSTL_BUFFER_H diff --git a/include/tinystl/hash.h b/include/tinystl/hash.h index 787ddae7c..55f97881e 100644 --- a/include/tinystl/hash.h +++ b/include/tinystl/hash.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ #ifndef TINYSTL_STRINGHASH_H #define TINYSTL_STRINGHASH_H -#include "stddef.h" +#include namespace tinystl { diff --git a/include/tinystl/hash_base.h b/include/tinystl/hash_base.h index f20675db4..386da28ea 100644 --- a/include/tinystl/hash_base.h +++ b/include/tinystl/hash_base.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,79 +27,134 @@ #ifndef TINYSTL_HASH_BASE_H #define TINYSTL_HASH_BASE_H -#include "stddef.h" +#include +#include namespace tinystl { template struct pair { - typedef Key first_type; - typedef Value second_type; - pair(); + pair(const pair& other); + pair(pair&& other); pair(const Key& key, const Value& value); + pair(Key&& key, Value&& value); + + pair& operator=(const pair& other); + pair& operator=(pair&& other); Key first; Value second; + + using first_type = Key; + using second_type = Value; }; template - pair::pair() { + inline pair::pair() { + } + + template + inline pair::pair(const pair& other) + : first(other.first) + , second(other.second) + { + } + + template + inline pair::pair(pair&& other) + : first(static_cast(other.first)) + , second(static_cast(other.second)) + { } template - pair::pair(const Key& key, const Value& value) + inline pair::pair(const Key& key, const Value& value) : first(key) , second(value) { } template - static inline pair make_pair(const Key& key, const Value& value) { - return pair(key, value); + inline pair::pair(Key&& key, Value&& value) + : first(static_cast(key)) + , second(static_cast(value)) + { + } + + template + inline pair& pair::operator=(const pair& other) { + first = other.first; + second = other.second; + return *this; + } + + template + inline pair& pair::operator=(pair&& other) { + first = static_cast(other.first); + second = static_cast(other.second); + return *this; + } + + template + static inline pair::type, typename remove_const_reference::type> + make_pair(Key&& key, Value&& value) { + return pair::type, typename remove_const_reference::type>( + static_cast(key) + , static_cast(value) + ); } template struct unordered_hash_node { unordered_hash_node(const Key& key, const Value& value); + unordered_hash_node(Key&& key, Value&& value); const Key first; Value second; unordered_hash_node* next; unordered_hash_node* prev; - - private: - unordered_hash_node& operator=(const unordered_hash_node&); }; template - unordered_hash_node::unordered_hash_node(const Key& key, const Value& value) + inline unordered_hash_node::unordered_hash_node(const Key& key, const Value& value) : first(key) , second(value) { } + template + inline unordered_hash_node::unordered_hash_node(Key&& key, Value&& value) + : first(static_cast(key)) + , second(static_cast(value)) + { + } + template struct unordered_hash_node { - unordered_hash_node(const Key& key); + explicit unordered_hash_node(const Key& key); + explicit unordered_hash_node(Key&& key); const Key first; unordered_hash_node* next; unordered_hash_node* prev; - - private: - unordered_hash_node& operator=(const unordered_hash_node&); }; template - unordered_hash_node::unordered_hash_node(const Key& key) + inline unordered_hash_node::unordered_hash_node(const Key& key) : first(key) { } + template + inline unordered_hash_node::unordered_hash_node(Key&& key) + : first(static_cast(key)) + { + } + template - static void unordered_hash_node_insert(unordered_hash_node* node, size_t hash, unordered_hash_node** buckets, size_t nbuckets) { + static inline void unordered_hash_node_insert(unordered_hash_node* node, size_t hash, unordered_hash_node** buckets, size_t nbuckets) { size_t bucket = hash & (nbuckets - 1); unordered_hash_node* it = buckets[bucket + 1]; @@ -223,6 +278,7 @@ namespace tinystl { template static inline Node unordered_hash_find(const Key& key, Node* buckets, size_t nbuckets) { + if (!buckets) return 0; const size_t bucket = hash(key) & (nbuckets - 2); for (Node it = buckets[bucket], end = buckets[bucket+1]; it != end; it = it->next) if (it->first == key) diff --git a/include/tinystl/new.h b/include/tinystl/new.h index 9c86dd8c2..62bb072d7 100644 --- a/include/tinystl/new.h +++ b/include/tinystl/new.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ #ifndef TINYSTL_NEW_H #define TINYSTL_NEW_H -#include "stddef.h" +#include namespace tinystl { diff --git a/include/tinystl/stddef.h b/include/tinystl/stddef.h index 21c1b1ec9..a31dd347b 100644 --- a/include/tinystl/stddef.h +++ b/include/tinystl/stddef.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -29,10 +29,13 @@ #if defined(_WIN64) typedef long long unsigned int size_t; + typedef long long int ptrdiff_t; #elif defined(_WIN32) typedef unsigned int size_t; -#elif defined (__linux__) && defined(__SIZE_TYPE__) + typedef int ptrdiff_t; +#elif defined (__linux__) && defined(__SIZE_TYPE__) && defined(__PTRDIFF_TYPE__) typedef __SIZE_TYPE__ size_t; + typedef __PTRDIFF_TYPE__ ptrdiff_t; #else # include #endif diff --git a/include/tinystl/string.h b/include/tinystl/string.h index 4d90c2ae4..889d726df 100644 --- a/include/tinystl/string.h +++ b/include/tinystl/string.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,34 +27,37 @@ #ifndef TINYSTL_STRING_H #define TINYSTL_STRING_H -#include // strlen -#include "stddef.h" -#include "hash.h" +#include +#include +#include namespace tinystl { - template - class stringT { + template + class basic_string { public: - stringT(); - stringT(const stringT& other); - stringT(const char* sz); - stringT(const char* sz, size_t len); - ~stringT(); + basic_string(); + basic_string(const basic_string& other); + basic_string(basic_string&& other); + basic_string(const char* sz); + basic_string(const char* sz, size_t len); + ~basic_string(); - stringT& operator=(const stringT& other); + basic_string& operator=(const basic_string& other); + basic_string& operator=(basic_string&& other); const char* c_str() const; size_t size() const; - bool empty() const; - void reserve(size_t _size); - void resize(size_t _size); + void reserve(size_t size); + void resize(size_t size); + void clear(); void append(const char* first, const char* last); - void append(const char* str); + void assign(const char* s, size_t n); - void swap(stringT& other); + void shrink_to_fit(); + void swap(basic_string& other); private: typedef char* pointer; @@ -63,13 +66,11 @@ namespace tinystl { pointer m_capacity; static const size_t c_nbuffer = 12; - char m_buffer[12]; + char m_buffer[12]{0}; }; - typedef stringT string; - - template - inline stringT::stringT() + template + inline basic_string::basic_string() : m_first(m_buffer) , m_last(m_buffer) , m_capacity(m_buffer + c_nbuffer) @@ -77,8 +78,8 @@ namespace tinystl { resize(0); } - template - inline stringT::stringT(const stringT& other) + template + inline basic_string::basic_string(const basic_string& other) : m_first(m_buffer) , m_last(m_buffer) , m_capacity(m_buffer + c_nbuffer) @@ -87,8 +88,27 @@ namespace tinystl { append(other.m_first, other.m_last); } - template - inline stringT::stringT(const char* sz) + template + inline basic_string::basic_string(basic_string&& other) + { + if (other.m_first == other.m_buffer) { + m_first = m_buffer; + m_last = m_buffer; + m_capacity = m_buffer + c_nbuffer; + reserve(other.size()); + append(other.m_first, other.m_last); + } else { + m_first = other.m_first; + m_last = other.m_last; + m_capacity = other.m_capacity; + } + other.m_first = other.m_last = other.m_buffer; + other.m_capacity = other.m_buffer + c_nbuffer; + other.resize(0); + } + + template + inline basic_string::basic_string(const char* sz) : m_first(m_buffer) , m_last(m_buffer) , m_capacity(m_buffer + c_nbuffer) @@ -101,8 +121,8 @@ namespace tinystl { append(sz, sz + len); } - template - inline stringT::stringT(const char* sz, size_t len) + template + inline basic_string::basic_string(const char* sz, size_t len) : m_first(m_buffer) , m_last(m_buffer) , m_capacity(m_buffer + c_nbuffer) @@ -111,69 +131,75 @@ namespace tinystl { append(sz, sz + len); } - template - inline stringT::~stringT() { + template + inline basic_string::~basic_string() { if (m_first != m_buffer) - Alloc::static_deallocate(m_first, m_capacity - m_first); + allocator::static_deallocate(m_first, m_capacity - m_first); } - template - inline stringT& stringT::operator=(const stringT& other) { - stringT(other).swap(*this); + template + inline basic_string& basic_string::operator=(const basic_string& other) { + basic_string(other).swap(*this); return *this; } - template - inline const char* stringT::c_str() const { - return m_first; + template + inline basic_string& basic_string::operator=(basic_string&& other) { + basic_string(static_cast(other)).swap(*this); + return *this; } - template - inline size_t stringT::size() const - { - return (size_t)(m_last - m_first); + template + inline const char* basic_string::c_str() const { + return m_first; } - template - inline bool stringT::empty() const + template + inline size_t basic_string::size() const { - return 0 == size(); + ptrdiff_t size = m_last - m_first; + return (size_t)size; } - template - inline void stringT::reserve(size_t capacity) { - if (m_first + capacity + 1 <= m_capacity) { + template + inline void basic_string::reserve(size_t capacity) { + if (m_first + capacity + 1 <= m_capacity) return; - } - const size_t _size = (size_t)(m_last - m_first); + const ptrdiff_t size = m_last - m_first; - pointer newfirst = (pointer)Alloc::static_allocate(capacity + 1); - for (pointer it = m_first, newit = newfirst, end = m_last; it != end; ++it, ++newit) { + pointer newfirst = (pointer)allocator::static_allocate(capacity + 1); + for (pointer it = m_first, newit = newfirst, end = m_last; it != end; ++it, ++newit) *newit = *it; - } - - if (m_first != m_buffer) { - Alloc::static_deallocate(m_first, m_capacity - m_first); - } + if (m_first != m_buffer) + allocator::static_deallocate(m_first, m_capacity - m_first); m_first = newfirst; - m_last = newfirst + _size; + m_last = newfirst + size; m_capacity = m_first + capacity; } - template - inline void stringT::resize(size_t _size) { - reserve(_size); - for (pointer it = m_last, end = m_first + _size + 1; it < end; ++it) - *it = 0; + template + inline void basic_string::resize(size_t size) { + const ptrdiff_t prevSize = m_last-m_first; + reserve(size); + if (size > (size_t)prevSize) + for (pointer it = m_last, end = m_first + size + 1; it < end; ++it) + *it = 0; + else if (m_last != m_first) + m_first[size] = 0; + + m_last = m_first + size; + } - m_last += _size; + template + inline void basic_string::clear() { + resize(0); } - template - inline void stringT::append(const char* first, const char* last) { - const size_t newsize = (size_t)((m_last - m_first) + (last - first) + 1); + template + inline void basic_string::append(const char* first, const char* last) { + const ptrdiff_t newsize = ((m_last - m_first) + (last - first) + 1); if (m_first + newsize > m_capacity) reserve((newsize * 3) / 2); @@ -182,46 +208,62 @@ namespace tinystl { *m_last = 0; } - template - inline void stringT::append(const char* str) { - append(str, str + strlen(str) ); + template + inline void basic_string::assign(const char* sz, size_t n) { + clear(); + append(sz, sz+n); } - template - inline void stringT::swap(stringT& other) { - const pointer tfirst = m_first, tlast = m_last, tcapacity = m_capacity; - m_first = other.m_first, m_last = other.m_last, m_capacity = other.m_capacity; - other.m_first = tfirst, other.m_last = tlast, other.m_capacity = tcapacity; - - char tbuffer[c_nbuffer]; - - if (m_first == other.m_buffer) - for (pointer it = other.m_buffer, end = m_last, out = tbuffer; it != end; ++it, ++out) - *out = *it; - - if (other.m_first == m_buffer) { - other.m_last = other.m_last - other.m_first + other.m_buffer; - other.m_first = other.m_buffer; - other.m_capacity = other.m_buffer + c_nbuffer; + template + inline void basic_string::shrink_to_fit() { + if (m_first == m_buffer) { + } else if (m_last == m_first) { + const ptrdiff_t capacity = m_capacity - m_first; + if (capacity) + allocator::static_deallocate(m_first, capacity+1); + m_capacity = m_first; + } else if (m_capacity != m_last) { + const ptrdiff_t size = m_last - m_first; + char* newfirst = (pointer)allocator::static_allocate(size+1); + for (pointer in = m_first, out = newfirst; in != m_last + 1; ++in, ++out) + *out = *in; + if (m_first != m_capacity) + allocator::static_deallocate(m_first, m_capacity+1-m_first); + m_first = newfirst; + m_last = newfirst+size; + m_capacity = m_last; + } + } - for (pointer it = other.m_first, end = other.m_last, in = m_buffer; it != end; ++it, ++in) - *it = *in; - *other.m_last = 0; + template + inline void basic_string::swap(basic_string& other) { + { + const pointer tfirst = m_first, tlast = m_last, tcapacity = m_capacity; + m_first = other.m_first, m_last = other.m_last, m_capacity = other.m_capacity; + other.m_first = tfirst, other.m_last = tlast, other.m_capacity = tcapacity; } + for (size_t i = 0; i < c_nbuffer; ++i) { + const char temp = m_buffer[i]; + m_buffer[i] = other.m_buffer[i]; + other.m_buffer[i] = temp; + } if (m_first == other.m_buffer) { - m_last = m_last - m_first + m_buffer; + ptrdiff_t len = m_last - m_first; m_first = m_buffer; + m_last = m_buffer + len; m_capacity = m_buffer + c_nbuffer; - - for (pointer it = m_first, end = m_last, in = tbuffer; it != end; ++it, ++in) - *it = *in; - *m_last = 0; + } + if (other.m_first == m_buffer) { + ptrdiff_t len = other.m_last - other.m_first; + other.m_first = other.m_buffer; + other.m_last = other.m_buffer + len; + other.m_capacity = other.m_buffer + c_nbuffer; } } - template - inline bool operator==(const stringT& lhs, const stringT& rhs) { + template + inline bool operator==(const basic_string& lhs, const basic_string& rhs) { typedef const char* pointer; const size_t lsize = lhs.size(), rsize = rhs.size(); @@ -237,10 +279,12 @@ namespace tinystl { return true; } - template - static inline size_t hash(const stringT& value) { + template + static inline size_t hash(const basic_string& value) { return hash_string(value.c_str(), value.size()); } + + typedef basic_string string; } #endif diff --git a/include/tinystl/string_view.h b/include/tinystl/string_view.h new file mode 100644 index 000000000..34d8528d6 --- /dev/null +++ b/include/tinystl/string_view.h @@ -0,0 +1,147 @@ +/*- + * Copyright 2012-1017 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef TINYSTL_STRING_VIEW_H +#define TINYSTL_STRING_VIEW_H + +#include + +namespace tinystl { + + class string_view + { + public: + typedef char value_type; + typedef char* pointer; + typedef const char* const_pointer; + typedef char& reference; + typedef const char& const_reference; + typedef const_pointer iterator; + typedef const_pointer const_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + static constexpr size_type npos = size_type(-1); + + constexpr string_view(); + constexpr string_view(const char* s, size_type count); + constexpr string_view(const char* s); + constexpr string_view(const string_view&) = default; + string_view& operator=(const string_view&) = default; + + constexpr const char* data() const; + constexpr char operator[](size_type pos) const; + constexpr size_type size() const; + constexpr bool empty() const; + constexpr iterator begin() const; + constexpr const_iterator cbegin() const; + constexpr iterator end() const; + constexpr const_iterator cend() const; + constexpr string_view substr(size_type pos = 0, size_type count = npos) const; + constexpr void swap(string_view& v); + + private: + string_view(decltype(nullptr)) = delete; + + static constexpr size_type strlen(const char*); + + const char* m_str; + size_type m_size; + }; + + constexpr string_view::string_view() + : m_str(nullptr) + , m_size(0) + { + } + + constexpr string_view::string_view(const char* s, size_type count) + : m_str(s) + , m_size(count) + { + } + + constexpr string_view::string_view(const char* s) + : m_str(s) + , m_size(strlen(s)) + { + } + + constexpr const char* string_view::data() const { + return m_str; + } + + constexpr char string_view::operator[](size_type pos) const { + return m_str[pos]; + } + + constexpr string_view::size_type string_view::size() const { + return m_size; + } + + constexpr bool string_view::empty() const { + return 0 == m_size; + } + + constexpr string_view::iterator string_view::begin() const { + return m_str; + } + + constexpr string_view::const_iterator string_view::cbegin() const { + return m_str; + } + + constexpr string_view::iterator string_view::end() const { + return m_str + m_size; + } + + constexpr string_view::const_iterator string_view::cend() const { + return m_str + m_size; + } + + constexpr string_view string_view::substr(size_type pos, size_type count) const { + return string_view(m_str + pos, npos == count ? m_size - pos : count); + } + + constexpr void string_view::swap(string_view& v) { + const char* strtmp = m_str; + size_type sizetmp = m_size; + m_str = v.m_str; + m_size = v.m_size; + v.m_str = strtmp; + v.m_size = sizetmp; + } + + constexpr string_view::size_type string_view::strlen(const char* s) { + for (size_t len = 0; ; ++len) { + if (0 == s[len]) { + return len; + } + } + } +} + +#endif // TINYSTL_STRING_VIEW_H diff --git a/include/tinystl/traits.h b/include/tinystl/traits.h index 11b18e70c..b598403cb 100644 --- a/include/tinystl/traits.h +++ b/include/tinystl/traits.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,9 +27,9 @@ #ifndef TINYSTL_TRAITS_H #define TINYSTL_TRAITS_H -#include "new.h" +#include -#if defined(__GNUC__) && defined(__is_pod) +#if defined(__GNUC__) # define TINYSTL_TRY_POD_OPTIMIZATION(t) __is_pod(t) #elif defined(_MSC_VER) # define TINYSTL_TRY_POD_OPTIMIZATION(t) (!__is_class(t) || __is_pod(t)) @@ -80,6 +80,46 @@ namespace tinystl { static inline void move_construct(T* a, T& b) { move_construct_impl(a, b, (T*)0); } + + template + struct remove_reference { + typedef T type; + }; + + template + struct remove_reference { + typedef T type; + }; + + template + struct remove_reference { + typedef T type; + }; + + template + struct remove_const { + typedef T type; + }; + + template + struct remove_const { + typedef T type; + }; + + template + struct remove_const { + typedef T& type; + }; + + template + struct remove_const { + typedef T&& type; + }; + + template + struct remove_const_reference { + typedef typename remove_reference::type>::type type; + }; } #endif diff --git a/include/tinystl/unordered_map.h b/include/tinystl/unordered_map.h index 64f845749..8d2a7b38f 100644 --- a/include/tinystl/unordered_map.h +++ b/include/tinystl/unordered_map.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,9 +27,10 @@ #ifndef TINYSTL_UNORDERED_MAP_H #define TINYSTL_UNORDERED_MAP_H -#include "buffer.h" -#include "hash.h" -#include "hash_base.h" +#include +#include +#include +#include namespace tinystl { @@ -38,13 +39,14 @@ namespace tinystl { public: unordered_map(); unordered_map(const unordered_map& other); + unordered_map(unordered_map&& other); ~unordered_map(); unordered_map& operator=(const unordered_map& other); - + unordered_map& operator=(unordered_map&& other); typedef pair value_type; - + typedef unordered_hash_iterator > const_iterator; typedef unordered_hash_iterator > iterator; @@ -61,6 +63,7 @@ namespace tinystl { const_iterator find(const Key& key) const; iterator find(const Key& key); pair insert(const pair& p); + pair emplace(pair&& p); void erase(const_iterator where); Value& operator[](const Key& key); @@ -69,73 +72,99 @@ namespace tinystl { private: + void rehash(size_t nbuckets); + typedef unordered_hash_node* pointer; size_t m_size; - buffer m_buckets; + tinystl::buffer m_buckets; }; template - unordered_map::unordered_map() + inline unordered_map::unordered_map() : m_size(0) { buffer_init(&m_buckets); - buffer_resize(&m_buckets, 9, 0); } template - unordered_map::unordered_map(const unordered_map& other) + inline unordered_map::unordered_map(const unordered_map& other) : m_size(other.m_size) { const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first); buffer_init(&m_buckets); buffer_resize(&m_buckets, nbuckets, 0); - for (pointer it = *other.m_buckets.first; it; it = it->next) { - unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(it->first, it->second); - newnode->next = newnode->prev = 0; + if (other.m_buckets.first) { + for (pointer it = *other.m_buckets.first; it; it = it->next) { + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(it->first, it->second); + newnode->next = newnode->prev = 0; - unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); + unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); + } } } template - unordered_map::~unordered_map() { - clear(); + inline unordered_map::unordered_map(unordered_map&& other) + : m_size(other.m_size) + { + buffer_move(&m_buckets, &other.m_buckets); + other.m_size = 0; + } + + template + inline unordered_map::~unordered_map() { + if (m_buckets.first != m_buckets.last) + clear(); buffer_destroy(&m_buckets); } template - unordered_map& unordered_map::operator=(const unordered_map& other) { + inline unordered_map& unordered_map::operator=(const unordered_map& other) { unordered_map(other).swap(*this); return *this; } + template + inline unordered_map& unordered_map::operator=(unordered_map&& other) { + unordered_map(static_cast(other)).swap(*this); + return *this; + } + template inline typename unordered_map::iterator unordered_map::begin() { iterator it; - it.node = *m_buckets.first; + if (m_buckets.first) { + it.node = *m_buckets.first; + } else { + it.node = nullptr; + } return it; } template inline typename unordered_map::iterator unordered_map::end() { iterator it; - it.node = 0; + it.node = nullptr; return it; } template inline typename unordered_map::const_iterator unordered_map::begin() const { const_iterator cit; - cit.node = *m_buckets.first; + if (m_buckets.first) { + cit.node = *m_buckets.first; + } else { + cit.node = nullptr; + } return cit; } template inline typename unordered_map::const_iterator unordered_map::end() const { const_iterator cit; - cit.node = 0; + cit.node = nullptr; return cit; } @@ -151,13 +180,15 @@ namespace tinystl { template inline void unordered_map::clear() { - pointer it = *m_buckets.first; - while (it) { - const pointer next = it->next; - it->~unordered_hash_node(); - Alloc::static_deallocate(it, sizeof(unordered_hash_node)); - - it = next; + if (m_buckets.first) { + pointer it = *m_buckets.first; + while (it) { + const pointer next = it->next; + it->~unordered_hash_node(); + Alloc::static_deallocate(it, sizeof(unordered_hash_node)); + + it = next; + } } m_buckets.last = m_buckets.first; @@ -180,24 +211,11 @@ namespace tinystl { } template - inline pair::iterator, bool> unordered_map::insert(const pair& p) { - pair result; - result.second = false; - - result.first = find(p.first); - if (result.first.node != 0) - return result; - - unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(p.first, p.second); - newnode->next = newnode->prev = 0; - - const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); - unordered_hash_node_insert(newnode, hash(p.first), m_buckets.first, nbuckets - 1); - - ++m_size; + inline void unordered_map::rehash(size_t nbuckets) { + if (!m_buckets.first) return; if (m_size + 1 > 4 * nbuckets) { pointer root = *m_buckets.first; - + const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8; m_buckets.last = m_buckets.first; buffer_resize(&m_buckets, newnbuckets + 1, 0); @@ -205,11 +223,56 @@ namespace tinystl { while (root) { const pointer next = root->next; - root->next = root->prev = 0; + root->next = root->prev = nullptr; unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets); root = next; } } + } + + template + inline pair::iterator, bool> unordered_map::insert(const pair& p) { + pair result; + result.second = false; + + result.first = find(p.first); + if (result.first.node != nullptr) + return result; + + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(p.first, p.second); + newnode->next = newnode->prev = nullptr; + + if(!m_buckets.first) buffer_resize(&m_buckets, 9, 0); + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, hash(p.first), m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); + + result.first.node = newnode; + result.second = true; + return result; + } + + template + inline pair::iterator, bool> unordered_map::emplace(pair&& p) { + pair result; + result.second = false; + + result.first = find(p.first); + if (result.first.node != nullptr) + return result; + + const size_t keyhash = hash(p.first); + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(static_cast(p.first), static_cast(p.second)); + newnode->next = newnode->prev = 0; + + if (!m_buckets.first) buffer_resize(&m_buckets, 9, 0); + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, keyhash, m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); result.first.node = newnode; result.second = true; @@ -217,7 +280,7 @@ namespace tinystl { } template - void unordered_map::erase(const_iterator where) { + inline void unordered_map::erase(const_iterator where) { unordered_hash_node_erase(where.node, hash(where->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1); where->~unordered_hash_node(); @@ -226,12 +289,12 @@ namespace tinystl { } template - Value& unordered_map::operator[](const Key& key) { + inline Value& unordered_map::operator[](const Key& key) { return insert(pair(key, Value())).first->second; } template - void unordered_map::swap(unordered_map& other) { + inline void unordered_map::swap(unordered_map& other) { size_t tsize = other.m_size; other.m_size = m_size, m_size = tsize; buffer_swap(&m_buckets, &other.m_buckets); diff --git a/include/tinystl/unordered_set.h b/include/tinystl/unordered_set.h index 976a412b1..d1eb57987 100644 --- a/include/tinystl/unordered_set.h +++ b/include/tinystl/unordered_set.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,9 +27,10 @@ #ifndef TINYSTL_UNORDERED_SET_H #define TINYSTL_UNORDERED_SET_H -#include "buffer.h" -#include "hash.h" -#include "hash_base.h" +#include +#include +#include +#include namespace tinystl { @@ -38,9 +39,11 @@ namespace tinystl { public: unordered_set(); unordered_set(const unordered_set& other); + unordered_set(unordered_set&& other); ~unordered_set(); unordered_set& operator=(const unordered_set& other); + unordered_set& operator=(unordered_set&& other); typedef unordered_hash_iterator > const_iterator; typedef const_iterator iterator; @@ -54,6 +57,7 @@ namespace tinystl { iterator find(const Key& key) const; pair insert(const Key& key); + pair emplace(Key&& key); void erase(iterator where); size_t erase(const Key& key); @@ -61,58 +65,80 @@ namespace tinystl { private: + void rehash(size_t nbuckets); + typedef unordered_hash_node* pointer; size_t m_size; - buffer m_buckets; + tinystl::buffer m_buckets; }; template - unordered_set::unordered_set() + inline unordered_set::unordered_set() : m_size(0) { buffer_init(&m_buckets); - buffer_resize(&m_buckets, 9, 0); } template - unordered_set::unordered_set(const unordered_set& other) + inline unordered_set::unordered_set(const unordered_set& other) : m_size(other.m_size) { const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first); buffer_init(&m_buckets); buffer_resize(&m_buckets, nbuckets, 0); - for (pointer it = *other.m_buckets.first; it; it = it->next) { - unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(*it); - newnode->next = newnode->prev = 0; - unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); + if (other.m_buckets.first) { + for (pointer it = *other.m_buckets.first; it; it = it->next) { + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(*it); + newnode->next = newnode->prev = 0; + unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); + } } } template - unordered_set::~unordered_set() { - clear(); + inline unordered_set::unordered_set(unordered_set&& other) + : m_size(other.m_size) + { + buffer_move(&m_buckets, &other.m_buckets); + other.m_size = 0; + } + + template + inline unordered_set::~unordered_set() { + if (m_buckets.first != m_buckets.last) + clear(); buffer_destroy(&m_buckets); } template - unordered_set& unordered_set::operator=(const unordered_set& other) { + inline unordered_set& unordered_set::operator=(const unordered_set& other) { unordered_set(other).swap(*this); return *this; } + template + inline unordered_set& unordered_set::operator=(unordered_set&& other) { + unordered_set(static_cast(other)).swap(*this); + return *this; + } + template inline typename unordered_set::iterator unordered_set::begin() const { - iterator cit; - cit.node = *m_buckets.first; - return cit; + iterator it; + if (m_buckets.first) { + it.node = *m_buckets.first; + } else { + it.node = nullptr; + } + return it; } template inline typename unordered_set::iterator unordered_set::end() const { iterator cit; - cit.node = 0; + cit.node = nullptr; return cit; } @@ -128,13 +154,15 @@ namespace tinystl { template inline void unordered_set::clear() { - pointer it = *m_buckets.first; - while (it) { - const pointer next = it->next; - it->~unordered_hash_node(); - Alloc::static_deallocate(it, sizeof(unordered_hash_node)); - - it = next; + if (m_buckets.first) { + pointer it = *m_buckets.first; + while (it) { + const pointer next = it->next; + it->~unordered_hash_node(); + Alloc::static_deallocate(it, sizeof(unordered_hash_node)); + + it = next; + } } m_buckets.last = m_buckets.first; @@ -149,37 +177,69 @@ namespace tinystl { return result; } + template + inline void unordered_set::rehash(size_t nbuckets) { + if (!m_buckets.first) return; + if (m_size + 1 > 4 * nbuckets) { + pointer root = *m_buckets.first; + + const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8; + m_buckets.last = m_buckets.first; + buffer_resize(&m_buckets, newnbuckets + 1, 0); + unordered_hash_node** buckets = m_buckets.first; + + while (root) { + const pointer next = root->next; + root->next = root->prev = nullptr; + unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets); + root = next; + } + } + } + template inline pair::iterator, bool> unordered_set::insert(const Key& key) { pair result; result.second = false; result.first = find(key); - if (result.first.node != 0) + if (result.first.node != nullptr) return result; unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(key); - newnode->next = newnode->prev = 0; + newnode->next = newnode->prev = nullptr; + if(!m_buckets.first) buffer_resize(&m_buckets, 9, 0); const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); unordered_hash_node_insert(newnode, hash(key), m_buckets.first, nbuckets - 1); ++m_size; - if (m_size + 1 > 4 * nbuckets) { - pointer root = *m_buckets.first; + rehash(nbuckets); - const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8; - m_buckets.last = m_buckets.first; - buffer_resize(&m_buckets, newnbuckets + 1, 0); - unordered_hash_node** buckets = m_buckets.first; + result.first.node = newnode; + result.second = true; + return result; + } - while (root) { - const pointer next = root->next; - root->next = root->prev = 0; - unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets); - root = next; - } - } + template + inline pair::iterator, bool> unordered_set::emplace(Key&& key) { + pair result; + result.second = false; + + result.first = find(key); + if (result.first.node != nullptr) + return result; + + const size_t keyhash = hash(key); + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(static_cast(key)); + newnode->next = newnode->prev = nullptr; + + if(!m_buckets.first) buffer_resize(&m_buckets, 9, 0); + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, keyhash, m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); result.first.node = newnode; result.second = true; @@ -198,7 +258,7 @@ namespace tinystl { template inline size_t unordered_set::erase(const Key& key) { const iterator it = find(key); - if (it.node == 0) + if (it.node == nullptr) return 0; erase(it); diff --git a/include/tinystl/vector.h b/include/tinystl/vector.h index 6885feb4f..e248f626e 100644 --- a/include/tinystl/vector.h +++ b/include/tinystl/vector.h @@ -1,5 +1,5 @@ /*- - * Copyright 2012-1015 Matthew Endsley + * Copyright 2012-2018 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without @@ -27,23 +27,25 @@ #ifndef TINYSTL_VECTOR_H #define TINYSTL_VECTOR_H -#include "buffer.h" -#include "new.h" -#include "stddef.h" +#include +#include +#include +#include namespace tinystl { - template class vector { public: vector(); vector(const vector& other); - vector(size_t _size); - vector(size_t _size, const T& value); + vector(vector&& other); + vector(size_t size); + vector(size_t size, const T& value); vector(const T* first, const T* last); ~vector(); vector& operator=(const vector& other); + vector& operator=(vector&& other); void assign(const T* first, const T* last); @@ -64,7 +66,7 @@ namespace tinystl { void resize(size_t size); void resize(size_t size, const T& value); void clear(); - void reserve(size_t _capacity); + void reserve(size_t capacity); void push_back(const T& t); void pop_back(); @@ -117,15 +119,20 @@ namespace tinystl { } template - inline vector::vector(size_t _size) { + inline vector::vector(vector&& other) { + buffer_move(&m_buffer, &other.m_buffer); + } + + template + inline vector::vector(size_t size) { buffer_init(&m_buffer); - buffer_resize(&m_buffer, _size); + buffer_resize(&m_buffer, size); } template - inline vector::vector(size_t _size, const T& value) { + inline vector::vector(size_t size, const T& value) { buffer_init(&m_buffer); - buffer_resize(&m_buffer, _size, value); + buffer_resize(&m_buffer, size, value); } template @@ -145,6 +152,13 @@ namespace tinystl { return *this; } + template + vector& vector::operator=(vector&& other) { + buffer_destroy(&m_buffer); + buffer_move(&m_buffer, &other.m_buffer); + return *this; + } + template inline void vector::assign(const T* first, const T* last) { buffer_clear(&m_buffer); @@ -207,13 +221,13 @@ namespace tinystl { } template - inline void vector::resize(size_t _size) { - buffer_resize(&m_buffer, _size); + inline void vector::resize(size_t size) { + buffer_resize(&m_buffer, size); } template - inline void vector::resize(size_t _size, const T& value) { - buffer_resize(&m_buffer, _size, value); + inline void vector::resize(size_t size, const T& value) { + buffer_resize(&m_buffer, size, value); } template @@ -222,8 +236,8 @@ namespace tinystl { } template - inline void vector::reserve(size_t _capacity) { - buffer_reserve(&m_buffer, _capacity); + inline void vector::reserve(size_t capacity) { + buffer_reserve(&m_buffer, capacity); } template @@ -278,7 +292,7 @@ namespace tinystl { } template - inline void vector::insert(iterator where) { + inline void vector::insert(typename vector::iterator where) { buffer_insert(&m_buffer, where, 1); } @@ -314,9 +328,9 @@ namespace tinystl { template template - void vector::emplace(iterator where, const Param& param) { + void vector::emplace(typename vector::iterator where, const Param& param) { buffer_insert(&m_buffer, where, ¶m, ¶m + 1); } } -#endif +#endif // TINYSTL_VECTOR_H diff --git a/scripts/genie.lua b/scripts/genie.lua index a06fc61eb..1babf0ab7 100644 --- a/scripts/genie.lua +++ b/scripts/genie.lua @@ -45,6 +45,10 @@ project "bx.test" debugdir (path.join(BX_DIR, "tests")) + flags { + "FatalWarnings", + } + removeflags { "NoExceptions", } diff --git a/scripts/update_tinystl.sh b/scripts/update_tinystl.sh new file mode 100755 index 000000000..a748b9eca --- /dev/null +++ b/scripts/update_tinystl.sh @@ -0,0 +1,16 @@ +#!/bin/bash -eux + +if [ $# != 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +SRC_DIR=$1 +DST_DIR="include/tinystl" + +pushd $(dirname $0)/.. + +cp $SRC_DIR/include/TINYSTL/*.h $DST_DIR/ +find $DST_DIR -iname "*.h" -exec sed --in-place 's/ #include #include +#include bx::AllocatorI* g_allocator; @@ -637,3 +638,93 @@ TEST_CASE("0terminated", "[string]") REQUIRE(2 == st.getLength() ); REQUIRE(st.is0Terminated() ); } + +TEST(tinystl_string_constructor) { + using tinystl::string; + { + string s; + CHECK( s.size() == 0 ); + } + { + string s("hello"); + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "hello") ); + } + { + string s("hello world", 5); + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "hello") ); + } + { + const string other("hello"); + string s = other; + + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "hello") ); + } + { + string other("hello"); + string s = std::move(other); + + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "hello") ); + CHECK( other.size() == 0 ); + } +} + +TEST(tinystl_string_assign) { + using tinystl::string; + { + const string other("hello"); + string s("new"); + s = other; + + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "hello") ); + } + { + string other("hello"); + string s("new"); + s = std::move(other); + + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "hello") ); + CHECK( other.size() == 0 ); + } + + { + const string other("hello longer string here"); + string s("short"); + s = other; + + CHECK( s.size() == 24 ); + CHECK( 0 == strcmp(s.c_str(), "hello longer string here") ); + } + { + string other("hello longer string here"); + string s("short"); + s = std::move(other); + + CHECK( s.size() == 24 ); + CHECK( 0 == strcmp(s.c_str(), "hello longer string here") ); + CHECK( other.size() == 0 ); + } + + { + const string other("short"); + string s("hello longer string here"); + s = other; + + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "short") ); + } + { + string other("short"); + string s("hello longer string here"); + s = std::move(other); + + CHECK( s.size() == 5 ); + CHECK( 0 == strcmp(s.c_str(), "short") ); + CHECK( other.size() == 0 ); + } +} diff --git a/tests/test.h b/tests/test.h index 8598da9a3..acb7883ad 100644 --- a/tests/test.h +++ b/tests/test.h @@ -10,6 +10,8 @@ BX_PRAGMA_DIAGNOSTIC_PUSH(); BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4312); // warning C4312 : 'reinterpret_cast' : conversion from 'int' to 'const char *' of greater size +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wno-unknown-warning-option"); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wno-nan-infinity-disabled"); #include BX_PRAGMA_DIAGNOSTIC_POP(); diff --git a/tests/unordered_map_test.cpp b/tests/unordered_map_test.cpp new file mode 100644 index 000000000..0c6865b14 --- /dev/null +++ b/tests/unordered_map_test.cpp @@ -0,0 +1,205 @@ +/*- +* Copyright 2012-2018 Matthew Endsley +* All rights reserved +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted providing 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. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "test.h" + +#include +#include +#include + +template +static void comparemaps(const tinystl::unordered_map& m, const tinystl::unordered_map& expected) { + CHECK( m.size() == expected.size() ); + + typedef typename tinystl::unordered_map::const_iterator iterator; + for (iterator it = expected.begin(), end = expected.end(); it != end; ++it) { + iterator found = m.find((*it).first); + CHECK( found != m.end() ); + CHECK( (*found).second == (*it).second ); + } +} + +TEST(uomap_constructor) { + typedef tinystl::unordered_map unordered_map; + using tinystl::make_pair; + + unordered_map baseline; + comparemaps(baseline, baseline); // test with empty maps + baseline.insert(make_pair(5, 1)); + baseline.insert(make_pair(6, 2)); + CHECK( 2 == baseline.size() ); + CHECK( baseline.find(5) != baseline.end() ); + CHECK( baseline[5] == 1 ); + CHECK( baseline.find(6) != baseline.end() ); + CHECK( baseline[6] == 2 ); + comparemaps(baseline, baseline); + + { + unordered_map m; + + CHECK( m.empty() ); + CHECK( m.size() == 0 ); + } + + { + unordered_map m = baseline; + + comparemaps(m, baseline); + } + + { + unordered_map other = baseline; + unordered_map m = std::move(other); + + comparemaps(m, baseline); + CHECK( other.empty() ); + } +} + +TEST(uomap_assign) { + typedef tinystl::unordered_map unordered_map; + using tinystl::make_pair; + + unordered_map baseline; + baseline.insert(make_pair(5, 1)); + baseline.insert(make_pair(6, 2)); + CHECK( 2 == baseline.size() ); + CHECK( baseline.find(5) != baseline.end() ); + CHECK( baseline[5] == 1 ); + CHECK( baseline.find(6) != baseline.end() ); + CHECK( baseline[6] == 2 ); + comparemaps(baseline, baseline); + + { + unordered_map m; + m = baseline; + + comparemaps(m, baseline); + } + + { + unordered_map m; + for (int ii = 0; ii != 10; ++ii) + m.insert(make_pair(ii, 10*ii)); + + m = baseline; + + comparemaps(m, baseline); + } + + { + unordered_map other = baseline; + unordered_map m; + m = std::move(other); + + comparemaps(m, baseline); + CHECK( other.empty() ); + } + + { + unordered_map other = baseline; + unordered_map m; + for (int ii = 0; ii != 10; ++ii) + m.insert(make_pair(ii, 10*ii)); + + m = std::move(other); + + comparemaps(m, baseline); + CHECK( other.empty() ); + } +} + +TEST(uomap_insert) { + using tinystl::string; + using tinystl::pair; + typedef tinystl::unordered_map unordered_map; + typedef pair inspair; + + { + unordered_map m; + m.insert(make_pair(string("hello"), string("world"))); + CHECK( m.find("hello") != m.end() ); + } + + { + const pair p("hello", "world"); + unordered_map m; + inspair p1 = m.insert(p); + CHECK( p1.second ); + CHECK( (*p1.first).first == tinystl::string("hello") ); + CHECK( (*p1.first).second == tinystl::string("world") ); + + inspair p2 = m.insert(p); + CHECK( !p2.second ); + CHECK( p2.first == p1.first ); + } + + { + unordered_map m; + m.emplace(pair("hello", "world")); + + CHECK( m.find("hello") != m.end() ); + } + + { + unordered_map m; + inspair p1 = m.emplace(pair("hello", "world")); + CHECK( p1.second ); + CHECK( (*p1.first).first == tinystl::string("hello") ); + CHECK( (*p1.first).second == tinystl::string("world") ); + + inspair p2 = m.emplace(pair("hello", "world")); + CHECK( !p2.second ); + CHECK( p2.first == p1.first ); + } + + { + unordered_map m; + pair p("hello", "world"); + m.emplace(std::move(p)); + + CHECK( m.find("hello") != m.end() ); + CHECK( p.first.size() == 0 ); + CHECK( p.second.size() == 0 ); + } +} + +TEST(uomap_iterate) { + typedef tinystl::unordered_map unordered_map; + { + unordered_map m; + for (size_t i = 0; i < 1000; ++i) { + CHECK( m.size() == i ); + size_t count = 0; + for (auto it = m.begin(); it != m.end(); ++it) { + count++; + } + CHECK( count == i ); + + m.insert(tinystl::make_pair(17 * i, 101 * i)); + } + } +} diff --git a/tests/unordered_set_test.cpp b/tests/unordered_set_test.cpp new file mode 100644 index 000000000..54caa5817 --- /dev/null +++ b/tests/unordered_set_test.cpp @@ -0,0 +1,191 @@ +/*- +* Copyright 2012-2018 Matthew Endsley +* All rights reserved +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted providing 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. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +*/ + +#include "test.h" + +#include +#include +#include + +template +static void comparesets(const tinystl::unordered_set& s, const tinystl::unordered_set& expected) { + CHECK( s.size() == expected.size() ); + + typedef typename tinystl::unordered_set::const_iterator iterator; + for (iterator it = expected.begin(), end = expected.end(); it != end; ++it) { + CHECK( s.find(*it) != s.end() ); + } +} + +TEST(uoset_constructor) { + typedef tinystl::unordered_set unordered_set; + + unordered_set baseline; + comparesets(baseline, baseline); // test on empty + baseline.insert(5); + baseline.insert(6); + CHECK( 2 == baseline.size() ); + CHECK( baseline.find(5) != baseline.end() ); + CHECK( baseline.find(6) != baseline.end() ); + comparesets(baseline, baseline); + + { + unordered_set s; + + CHECK( s.empty() ); + CHECK( s.size() == 0 ); + } + + { + unordered_set s = baseline; + + comparesets(s, baseline); + } + + { + unordered_set other = baseline; + unordered_set s = std::move(other); + + comparesets(s, baseline); + CHECK( other.empty() ); + } +} + +TEST(uoset_assign) { + typedef tinystl::unordered_set unordered_set; + + unordered_set baseline; + baseline.insert(5); + baseline.insert(6); + CHECK( 2 == baseline.size() ); + CHECK( baseline.find(5) != baseline.end() ); + CHECK( baseline.find(6) != baseline.end() ); + comparesets(baseline, baseline); + + { + unordered_set s; + s = baseline; + + comparesets(s, baseline); + } + + { + unordered_set s; + for (int ii = 0; ii != 10; ++ii) + s.insert(ii); + + s = baseline; + + comparesets(s, baseline); + } + + { + unordered_set other = baseline; + unordered_set s; + s = std::move(other); + + comparesets(s, baseline); + CHECK( other.empty() ); + } + + { + unordered_set other = baseline; + unordered_set s; + for (int ii = 0; ii != 10; ++ii) + s.insert(ii); + + s = std::move(other); + + comparesets(s, baseline); + CHECK( other.empty() ); + } +} + +TEST(uoset_insert) { + typedef tinystl::unordered_set unordered_set; + typedef tinystl::pair pair; + + { + unordered_set s; + s.insert("hello"); + CHECK( s.find("hello") != s.end() ); + } + + { + unordered_set s; + pair p1 = s.insert("hello"); + CHECK( p1.second ); + CHECK( (*p1.first) == tinystl::string("hello") ); + + pair p2 = s.insert("hello"); + CHECK( !p2.second ); + CHECK( p2.first == p1.first ); + } + + { + unordered_set s; + s.emplace("hello"); + + CHECK( s.find("hello") != s.end() ); + } + + { + unordered_set s; + pair p1 = s.emplace("hello"); + CHECK( p1.second ); + CHECK( (*p1.first) == tinystl::string("hello") ); + + pair p2 = s.emplace("hello"); + CHECK( !p2.second ); + CHECK( p2.first == p1.first ); + } + + { + unordered_set s; + tinystl::string key("hello"); + s.emplace(std::move(key)); + + CHECK( s.find("hello") != s.end() ); + CHECK( key.size() == 0 ); + } +} + +TEST(uoset_iterate) { + typedef tinystl::unordered_set unordered_set; + { + unordered_set s; + for (size_t i = 0; i < 1000; ++i) { + CHECK( s.size() == i ); + size_t count = 0; + for (auto it = s.begin(); it != s.end(); ++it) { + count++; + } + CHECK( count == i ); + + s.insert(int(17 * i)); + } + } +}