├── .gitignore ├── CMakeLists.txt ├── Jenkinsfile ├── LICENSE ├── NOTICE ├── README.md ├── include └── nstd │ ├── Array.hpp │ ├── Atomic.hpp │ ├── Base.hpp │ ├── Buffer.hpp │ ├── Call.hpp │ ├── Callback.hpp │ ├── Console.hpp │ ├── Crypto │ └── Sha256.hpp │ ├── Debug.hpp │ ├── Directory.hpp │ ├── Document │ ├── Json.hpp │ └── Xml.hpp │ ├── Error.hpp │ ├── File.hpp │ ├── Future.hpp │ ├── HashMap.hpp │ ├── HashSet.hpp │ ├── Library.hpp │ ├── List.hpp │ ├── Log.hpp │ ├── Map.hpp │ ├── Math.hpp │ ├── Memory.hpp │ ├── Monitor.hpp │ ├── MultiMap.hpp │ ├── Mutex.hpp │ ├── PoolList.hpp │ ├── PoolMap.hpp │ ├── Process.hpp │ ├── RefCount.hpp │ ├── Semaphore.hpp │ ├── Signal.hpp │ ├── Socket │ ├── Server.hpp │ └── Socket.hpp │ ├── String.hpp │ ├── System.hpp │ ├── Thread.hpp │ ├── Time.hpp │ ├── Unicode.hpp │ └── Variant.hpp ├── src ├── CMakeLists.txt ├── Callback.cpp ├── Console.cpp ├── Crypto │ ├── CMakeLists.txt │ └── Sha256.cpp ├── Debug.cpp ├── Directory.cpp ├── Document │ ├── CMakeLists.txt │ ├── Json.cpp │ └── Xml.cpp ├── Error.cpp ├── File.cpp ├── Future.cpp ├── Library.cpp ├── Log.cpp ├── Math.cpp ├── Memory.cpp ├── Monitor.cpp ├── Mutex.cpp ├── Process.cpp ├── Semaphore.cpp ├── Signal.cpp ├── Socket │ ├── CMakeLists.txt │ ├── Server.cpp │ └── Socket.cpp ├── String.cpp ├── System.cpp ├── Thread.cpp ├── Time.cpp └── Variant.cpp └── test ├── CMakeLists.txt ├── Console ├── CMakeLists.txt └── Main.cpp ├── Performance ├── CMakeLists.txt ├── FutureNStd.cpp ├── FutureStd.cpp ├── HashMapNStd.cpp ├── HashMapStd.cpp ├── MapNStd.cpp ├── MapStd.cpp ├── Performance.cpp ├── StringNStd.cpp └── StringStd.cpp └── UnitTest ├── CMakeLists.txt ├── TestArray.cpp ├── TestAtomic.cpp ├── TestBuffer.cpp ├── TestCallback.cpp ├── TestConsole.cpp ├── TestDebug.cpp ├── TestDirectory.cpp ├── TestError.cpp ├── TestFile.cpp ├── TestFuture.cpp ├── TestHashMap.cpp ├── TestHashSet.cpp ├── TestJson.cpp ├── TestList.cpp ├── TestLog.cpp ├── TestMap.cpp ├── TestMonitor.cpp ├── TestMultiMap.cpp ├── TestMutex.cpp ├── TestPoolList.cpp ├── TestPoolMap.cpp ├── TestProcess.cpp ├── TestRefCount.cpp ├── TestSemaphore.cpp ├── TestServer.cpp ├── TestSha256.cpp ├── TestSignal.cpp ├── TestSocket.cpp ├── TestString.cpp ├── TestThread.cpp ├── TestTime.cpp ├── TestUnicode.cpp ├── TestVariant.cpp └── TestXml.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | lib/ 2 | build* 3 | *.sdf 4 | *.opensdf 5 | *.suo 6 | *.vcxproj.user 7 | *.vcxproj.filters 8 | *.vcxproj 9 | *.sln 10 | *.VC.opendb 11 | 12 | .* 13 | *.mk 14 | *.project 15 | *.workspace 16 | Makefile 17 | 18 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(libnstd) 4 | 5 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 6 | set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER ".cmake") 7 | 8 | enable_testing() 9 | 10 | add_subdirectory(src) 11 | add_subdirectory(test) 12 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('All') { 5 | matrix { 6 | agent { 7 | label "${platform}" 8 | } 9 | axes { 10 | axis { 11 | name 'platform' 12 | values 'ubuntu22.04-x86_64', 'ubuntu20.04-x86_64', 'ubuntu18.04-x86_64', 'raspbian10-armv7l', 'windows10-x64', 'windows10-x86' 13 | } 14 | } 15 | stages { 16 | stage('Build') { 17 | steps { 18 | cmakeBuild buildDir: 'build', installation: 'InSearchPath', buildType: 'Release', cmakeArgs: '-G Ninja' 19 | cmake workingDir: 'build', arguments: '--build .', installation: 'InSearchPath' 20 | } 21 | } 22 | stage('Test') { 23 | steps { 24 | ctest workingDir: 'build', installation: 'InSearchPath', arguments: '--output-on-failure' 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2013 Colin Graf 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /include/nstd/Array.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | template class Array 7 | { 8 | public: 9 | class Iterator 10 | { 11 | public: 12 | Iterator() : item(0) {} 13 | const T& operator*() const {return *item;} 14 | T& operator*() {return *item;} 15 | const T* operator->() const {return item;} 16 | T* operator->() {return item;} 17 | const Iterator& operator++() {++item; return *this;} 18 | const Iterator& operator--() {--item; return *this;} 19 | Iterator operator++() const {return item + 1;} 20 | Iterator operator--() const {return item - 1;} 21 | bool operator==(const Iterator& other) const {return item == other.item;} 22 | bool operator!=(const Iterator& other) const {return item != other.item;} 23 | 24 | private: 25 | T* item; 26 | 27 | Iterator(T* item) : item(item) {} 28 | 29 | friend class Array; 30 | }; 31 | 32 | Array() : _capacity(0) {} 33 | 34 | explicit Array(usize capacity) : _capacity(capacity) {} 35 | 36 | Array(const Array& other) : _capacity(0) 37 | { 38 | reserve(other.capacity()); 39 | T* dest = _begin.item; 40 | for(T* src = other._begin.item, * end = other._end.item; src != end; ++src, ++dest) 41 | { 42 | #ifdef VERIFY 43 | VERIFY(new(dest)T(*src) == dest); 44 | #else 45 | new(dest)T(*src); 46 | #endif 47 | } 48 | _end.item = dest; 49 | } 50 | 51 | ~Array() 52 | { 53 | if(_begin.item) 54 | { 55 | for(T* i = _begin.item, * end = _end.item; i != end; ++i) 56 | i->~T(); 57 | delete[] (char*)_begin.item; 58 | } 59 | } 60 | 61 | Array& operator=(const Array& other) 62 | { 63 | clear(); 64 | reserve(other.capacity()); 65 | T* dest = _begin.item; 66 | for(T* src = other._begin.item, * end = other._end.item; src != end; ++src, ++dest) 67 | { 68 | #ifdef VERIFY 69 | VERIFY(new(dest)T(*src) == dest); 70 | #else 71 | new(dest)T(*src); 72 | #endif 73 | } 74 | _end.item = dest; 75 | return *this; 76 | } 77 | 78 | const Iterator& begin() const {return _begin;} 79 | const Iterator& end() const {return _end;} 80 | 81 | const T& front() const {return *_begin.item;} 82 | const T& back() const {return _end.item[-1];} 83 | 84 | T& front() {return *_begin.item;} 85 | T& back() {return _end.item[-1];} 86 | 87 | Iterator removeFront() {return remove(_begin);} 88 | Iterator removeBack() {return remove(_end.item - 1);} 89 | 90 | operator const T*() const {return _begin.item;} 91 | 92 | operator T*() {return _begin.item;} 93 | 94 | usize size() const {return _end.item - _begin.item;} 95 | bool isEmpty() const {return _begin.item == _end.item;} 96 | 97 | void reserve(usize size) 98 | { 99 | if(size > _capacity || (!_begin.item && size > 0)) 100 | { 101 | if (size > _capacity) 102 | _capacity = size; 103 | _capacity |= 0x03; 104 | T* newData = (T*)new char[sizeof(T) * _capacity]; 105 | T* dest = newData; 106 | if(_begin.item) 107 | { 108 | for (T* src = _begin.item, * end = _end.item; src != end; ++src, ++dest) 109 | { 110 | #ifdef VERIFY 111 | VERIFY(new(dest)T(*src) == dest); 112 | #else 113 | new(dest)T(*src); 114 | #endif 115 | src->~T(); 116 | } 117 | delete[] (char*)_begin.item; 118 | } 119 | _begin.item = newData; 120 | _end.item = dest; 121 | } 122 | } 123 | 124 | void resize(usize size, const T& value = T()) 125 | { 126 | usize _size = _end.item - _begin.item; 127 | if (size < _size) 128 | { 129 | T* newEnd = _begin.item + size; 130 | for (T* i = newEnd, *end = _end.item; i != end; ++i) 131 | i->~T(); 132 | _end.item = newEnd; 133 | } 134 | else 135 | { 136 | reserve(size); 137 | T* end = _begin.item + size; 138 | for (T* i = _begin.item + _size; i != end; ++i) 139 | { 140 | #ifdef VERIFY 141 | VERIFY(new(i)T(value) == i); 142 | #else 143 | new(i)T(value); 144 | #endif 145 | } 146 | _end.item = end; 147 | } 148 | } 149 | 150 | usize capacity() const {return _capacity;} 151 | 152 | void clear() 153 | { 154 | if(_begin.item) 155 | { 156 | for(T* i = _begin.item, * end = _end.item; i != end; ++i) 157 | i->~T(); 158 | _end.item = _begin.item; 159 | } 160 | } 161 | 162 | void swap(Array& other) 163 | { 164 | T* tmpFirst = _begin.item; 165 | T* tmpEnd = _end.item; 166 | usize tmpCapacity = _capacity; 167 | 168 | _begin.item = other._begin.item; 169 | _end.item = other._end.item; 170 | _capacity = other._capacity; 171 | 172 | other._begin.item = tmpFirst; 173 | other._end.item = tmpEnd; 174 | other._capacity = tmpCapacity; 175 | } 176 | 177 | T& append(const T& value) 178 | { 179 | usize size = _end.item - _begin.item; 180 | reserve(size + 1); 181 | T* item = _end.item; 182 | #ifdef VERIFY 183 | VERIFY(new(item) T(value) == item); 184 | #else 185 | new(item) T(value); 186 | #endif 187 | ++_end.item; 188 | return *item; 189 | } 190 | 191 | void append(const Array& values) 192 | { 193 | usize size = _end.item - _begin.item; 194 | usize valuesSize = values.size(); 195 | reserve(size + valuesSize); 196 | T* item = _end.item; 197 | for(T* end = item + valuesSize, *src = values._begin.item; item < end; ++item, ++src) 198 | { 199 | #ifdef VERIFY 200 | VERIFY(new(item) T(*src) == item); 201 | #else 202 | new(item) T(*src); 203 | #endif 204 | } 205 | _end.item = item; 206 | } 207 | 208 | void append(const T* values, usize size) 209 | { 210 | usize oldSize = _end.item - _begin.item; 211 | reserve(oldSize + size); 212 | T* item = _end.item; 213 | for(T* end = item + size; item < end; ++item, ++values) 214 | { 215 | #ifdef VERIFY 216 | VERIFY(new(item) T(*values) == item); 217 | #else 218 | new(item) T(*values); 219 | #endif 220 | } 221 | _end.item = item; 222 | } 223 | 224 | void remove(usize index) 225 | { 226 | usize size = _end.item - _begin.item; 227 | if(index < size) 228 | { 229 | T* pos = _begin.item + index; 230 | for(T* end = --_end.item, * dest; pos < end;) 231 | { 232 | dest = pos; 233 | *dest = *(++pos); 234 | } 235 | pos->~T(); 236 | } 237 | } 238 | 239 | Iterator remove(const Iterator& it) 240 | { 241 | T* pos = it.item; 242 | for(T* end = --_end.item, * dest; pos < end;) 243 | { 244 | dest = pos; 245 | *dest = *(++pos); 246 | } 247 | pos->~T(); 248 | return it.item; 249 | } 250 | 251 | Iterator find(const T& value) const 252 | { 253 | for(T* pos = _begin.item, * end = _end.item; pos < end; ++pos) 254 | if(*pos == value) 255 | return pos; 256 | return _end; 257 | } 258 | 259 | private: 260 | Iterator _begin; 261 | Iterator _end; 262 | usize _capacity; 263 | }; 264 | 265 | -------------------------------------------------------------------------------- /include/nstd/Base.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #if (defined(_M_AMD64) || defined(__amd64__)) && !defined(_AMD64) 5 | #define _AMD64 6 | #endif 7 | #if defined(__arm__) && !defined(_ARM) 8 | #define _ARM 9 | #endif 10 | #if defined(__PPC64__) && !defined(_PPC64) 11 | #define _PPC64 12 | #endif 13 | #if defined(__aarch64__) && !defined(_AARCH64) 14 | #define _AARCH64 15 | #endif 16 | 17 | typedef signed char int8; 18 | typedef short int16; 19 | typedef int int32; 20 | 21 | typedef unsigned char uint8; 22 | typedef unsigned short uint16; 23 | typedef unsigned int uint32; 24 | 25 | typedef unsigned char byte; 26 | typedef unsigned char uchar; 27 | typedef unsigned int uint; 28 | 29 | #if defined(_AMD64) || defined(_PPC64) || defined(_AARCH64) 30 | #ifdef _WIN32 31 | typedef long long int int64; 32 | typedef unsigned long long int uint64; 33 | typedef unsigned long long int usize; 34 | typedef long long int ssize; 35 | #else 36 | typedef long int int64; 37 | typedef unsigned long int uint64; 38 | typedef unsigned long int usize; 39 | typedef long int ssize; 40 | #endif 41 | #else 42 | typedef long long int int64; 43 | typedef unsigned long long int uint64; 44 | typedef unsigned int usize; 45 | typedef int ssize; 46 | #endif 47 | 48 | void* operator new(usize size); 49 | void* operator new [](usize size); 50 | void operator delete(void* buffer); 51 | void operator delete[](void* buffer); 52 | 53 | inline void* operator new(usize, void* buffer) {return buffer;} 54 | inline void operator delete(void* p, void*) {} 55 | 56 | inline usize hash(int8 v) {return (usize)v;} 57 | inline usize hash(uint8 v) {return (usize)v;} 58 | inline usize hash(int16 v) {return (usize)v;} 59 | inline usize hash(uint16 v) {return (usize)v;} 60 | inline usize hash(int32 v) {return (usize)v;} 61 | inline usize hash(uint32 v) {return (usize)v;} 62 | inline usize hash(int64 v) {return (usize)v;} 63 | inline usize hash(uint64 v) {return (usize)v;} 64 | inline usize hash(const void* v) {return (usize)v >> (sizeof(void*) / 4 + 1);} 65 | #if defined(_WIN32) || (!defined(_AMD64) && !defined(_PPC64) && !defined(_AARCH64)) 66 | inline usize hash(long v) {return (usize)v;} 67 | inline usize hash(unsigned long v) {return (usize)v;} 68 | #endif 69 | -------------------------------------------------------------------------------- /include/nstd/Call.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | template struct Call 5 | { 6 | template struct Member 7 | { 8 | struct Func0 9 | { 10 | C* c; 11 | A (C::*a)(); 12 | A call() {return (c->*a)();} 13 | Func0(C& c, A (C::*a)()) : c(&c), a(a) {} 14 | Func0() {} 15 | }; 16 | 17 | template struct Func1 18 | { 19 | C* c; 20 | A (C::*a)(D); 21 | A call(D d) {return (c->*a)(d);} 22 | Func1(C& c, A (C::*a)(D)) : c(&c), a(a) {} 23 | }; 24 | 25 | template struct Func2 26 | { 27 | C* c; 28 | A (C::*a)(D, E); 29 | A call(D d, E e) {return (c->*a)(d, e);} 30 | Func2(C& c, A (C::*a)(D, E)) : c(&c), a(a) {} 31 | }; 32 | 33 | template struct Func3 34 | { 35 | C* c; 36 | A (C::*a)(D, E, F); 37 | A call(D d, E e, F f) {return (c->*a)(d, e, f);} 38 | Func3(C& c, A (C::*a)(D, E, F)) : c(&c), a(a) {} 39 | }; 40 | 41 | template struct Func4 42 | { 43 | C* c; 44 | A (C::*a)(D, E, F, G); 45 | A call(D d, E e, F f, G g) {return (c->*a)(d, e, f, g);} 46 | Func4(C& c, A (C::*a)(D, E, F, G)) : c(&c), a(a) {} 47 | }; 48 | 49 | struct Args0 : public Func0 50 | { 51 | void* z; 52 | A call() {return (Func0::c->*Func0::a)();} 53 | Args0(C& c, A (C::*a)(), void* z) : Func0(c, a), z(z) {} 54 | }; 55 | 56 | template struct Args1 : public Func1 57 | { 58 | P p; 59 | void* z; 60 | A call() {return (Func1::c->*Func1::a)(p);} 61 | Args1(C& c, A (C::*a)(D), const P& p, void* z) : Func1(c, a), p(p), z(z) {} 62 | }; 63 | 64 | template struct Args2 : public Func2 65 | { 66 | P p; Q q; 67 | void* z; 68 | A call() {return (Func2::c->*Func2::a)(p, q);} 69 | Args2(C& c, A (C::*a)(D, E), const P& p, const Q& q, void* z) : Func2(c, a), p(p), q(q), z(z) {} 70 | }; 71 | 72 | template struct Args3 : public Func3 73 | { 74 | P p; Q q; R r; 75 | void* z; 76 | A call() {return (Func3::c->*Func3::a)(p, q, r);} 77 | Args3(C& c, A (C::*a)(D, E, F), const P& p, const Q& q, const R& r, void* z) : Func3(c, a), p(p), q(q), r(r), z(z) {} 78 | }; 79 | 80 | template struct Args4 : public Func4 81 | { 82 | P p; Q q; R r; S s; 83 | void* z; 84 | A call() {return (Func4::c->*Func4::a)(p, q, r, s);} 85 | Args4(C& c, A (C::*a)(D, E, F, G), const P& p, const Q& q, const R& r, const S& s, void* z) : Func4(c, a), p(p), q(q), r(r), s(s), z(z) {} 86 | }; 87 | }; 88 | 89 | struct Func0 90 | { 91 | A (*a)(); 92 | A call() {return a();} 93 | Func0(A (*a)()) : a(a) {} 94 | }; 95 | 96 | template struct Func1 97 | { 98 | A (*a)(D); 99 | A call(D d) {return a(d);} 100 | Func1(A (*a)(D)) : a(a) {} 101 | }; 102 | 103 | template struct Func2 104 | { 105 | A (*a)(D, E); 106 | A call(D d, E e) {return a(d, e);} 107 | Func2(A (*a)(D, E)) : a(a) {} 108 | }; 109 | 110 | template struct Func3 111 | { 112 | A (*a)(D, E, F); 113 | A call(D d, E e, F f) {return a(d, e, f);} 114 | Func3(A (*a)(D, E, F)) : a(a) {} 115 | }; 116 | 117 | template struct Func4 118 | { 119 | A (*a)(D, E, F, G); 120 | A call(D d, E e, F f, G g) {return a(d, e, f, g);} 121 | Func4(A (*a)(D, E, F, G)) : a(a) {} 122 | }; 123 | 124 | template struct Func5 125 | { 126 | A (*a)(D, E, F, G, H); 127 | A call(D d, E e, F f, G g, H h) {return a(d, e, f, g, h);} 128 | Func5(A (*a)(D, E, F, G, H)) : a(a) {} 129 | }; 130 | 131 | struct Args0 : public Func0 132 | { 133 | void* z; 134 | A call() {return Func0::a();} 135 | Args0(A (*a)(), void* z) : Func0(a), z(z) {} 136 | }; 137 | 138 | template struct Args1 : public Func1 139 | { 140 | P p; 141 | void* z; 142 | A call() {return Func1::a(p);} 143 | Args1(A (*a)(D), const P& p, void* z) : Func1(a), p(p), z(z) {} 144 | }; 145 | 146 | template struct Args2 : public Func2 147 | { 148 | P p; Q q; 149 | void* z; 150 | A call() {return Func2::a(p, q);} 151 | Args2(A (*a)(D, E), const P& p, const Q& q, void* z) : Func2(a), p(p), q(q), z(z) {} 152 | }; 153 | 154 | template struct Args3 : public Func3 155 | { 156 | P p; Q q; R r; 157 | void* z; 158 | A call() {return Func3::a(p, q, r);} 159 | Args3(A (*a)(D, E, F), const P& p, const Q& q, const R& r, void* z) : Func3(a), p(p), q(q), r(r), z(z) {} 160 | }; 161 | 162 | template struct Args4 : public Func4 163 | { 164 | P p; Q q; R r; S s; 165 | void* z; 166 | A call() {return Func4::a(p, q, r, s);} 167 | Args4(A (*a)(D, E, F, G), const P& p, const Q& q, const R& r, const S& s, void* z) : Func4(a), p(p), q(q), r(r), s(s), z(z) {} 168 | }; 169 | 170 | template struct Args5 : public Func5 171 | { 172 | P p; Q q; R r; S s; T t; 173 | void* z; 174 | A call() {return Func5::a(p, q, r, s, t);} 175 | Args5(A (*a)(D, E, F, G, H), const P& p, const Q& q, const R& r, const S& s, const T& t, void* z) : Func5(a), p(p), q(q), r(r), s(s), t(t), z(z) {} 176 | }; 177 | }; 178 | -------------------------------------------------------------------------------- /include/nstd/Console.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Console 7 | { 8 | public: 9 | static int print(const char* str); 10 | static int printf(const char* format, ...); 11 | static int error(const char* str); 12 | static int errorf(const char* format, ...); 13 | 14 | class Prompt 15 | { 16 | public: 17 | Prompt(); 18 | ~Prompt(); 19 | 20 | String getLine(const String& prompt); 21 | 22 | private: 23 | Prompt(const Prompt&); 24 | Prompt& operator=(const Prompt&); 25 | 26 | private: 27 | class Private; 28 | Private* p; 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /include/nstd/Crypto/Sha256.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Sha256 7 | { 8 | public: 9 | static const usize blockSize = 64; 10 | static const usize digestSize = 32; 11 | 12 | Sha256() {reset();} 13 | 14 | void reset(); 15 | 16 | void update(const byte* data, usize size); 17 | void finalize(byte (&digest)[digestSize]); 18 | 19 | static void hash(const byte* data, usize size, byte (&result)[digestSize]) 20 | { 21 | Sha256 sha256; 22 | sha256.update(data, size); 23 | sha256.finalize(result); 24 | } 25 | 26 | static void hmac(const byte* key, usize keySize, const byte* message, usize messageSize, byte (&result)[digestSize]) 27 | { 28 | Sha256 sha256; 29 | byte hashKey[blockSize]; 30 | if(keySize > blockSize) 31 | { 32 | sha256.update(key, keySize); 33 | sha256.finalize((byte (&)[digestSize])hashKey); 34 | Memory::zero(hashKey + 32, 32); 35 | } 36 | else 37 | { 38 | Memory::copy(hashKey, key, keySize); 39 | if(keySize < blockSize) 40 | Memory::zero(hashKey + keySize, blockSize - keySize); 41 | } 42 | 43 | byte oKeyPad[blockSize]; 44 | byte iKeyPad[blockSize]; 45 | for(int i = 0; i < 64; ++i) 46 | { 47 | oKeyPad[i] = hashKey[i] ^ 0x5c; 48 | iKeyPad[i] = hashKey[i] ^ 0x36; 49 | } 50 | byte hash[digestSize]; 51 | sha256.update(iKeyPad, blockSize); 52 | sha256.update(message, messageSize); 53 | sha256.finalize(hash); 54 | sha256.update(oKeyPad, blockSize); 55 | sha256.update(hash, digestSize); 56 | sha256.finalize(result); 57 | } 58 | 59 | private: 60 | uint32 state[8]; 61 | uint64 count; 62 | byte buffer[64]; 63 | 64 | private: 65 | class Private; 66 | }; 67 | -------------------------------------------------------------------------------- /include/nstd/Debug.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class String; 7 | 8 | class Debug 9 | { 10 | public: 11 | static int print(const char* str); 12 | static int printf(const char* format, ...); 13 | 14 | #ifndef NDEBUG 15 | static bool getSourceLine(void* addr, String& file, int& line); 16 | #endif 17 | }; 18 | 19 | #ifdef _MSC_VER 20 | void __cdecl __debugbreak(void); 21 | #define TRAP() __debugbreak() 22 | #else 23 | #if defined(__GNUC__) && defined(_ARM) 24 | __attribute__((gnu_inline, always_inline)) static void __inline__ TRAP(void) {__asm__ volatile("BKPT");} 25 | #else 26 | #define TRAP() __builtin_trap() 27 | #endif 28 | #endif 29 | 30 | #if defined(NDEBUG) && !defined(DEBUG) 31 | #undef TRAP 32 | #define TRAP() ((void)0) 33 | #define ASSERT(exp) ((void)1) 34 | #define VERIFY(exp) ((void)(exp)) 35 | #else 36 | #ifdef _MSC_VER 37 | #define ASSERT(exp) ((void)(!(exp) && Debug::printf("%s(%u): assertion failed: %s\n", __FILE__, __LINE__, #exp) && (TRAP(), 1))) 38 | #define VERIFY(exp) ((void)(!(exp) && Debug::printf("%s(%u): verification failed: %s\n", __FILE__, __LINE__, #exp) && (TRAP(), 1))) 39 | #else 40 | #define ASSERT(exp) ((void)(!(exp) && Debug::printf("%s:%u: assertion failed: %s\n", __FILE__, __LINE__, #exp) && (TRAP(), 1))) 41 | #define VERIFY(exp) ((void)(!(exp) && Debug::printf("%s:%u: verification failed: %s\n", __FILE__, __LINE__, #exp) && (TRAP(), 1))) 42 | #endif 43 | #endif 44 | -------------------------------------------------------------------------------- /include/nstd/Directory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Declaration of an object to access a directory. 4 | * @author Colin Graf 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | /** An object to access a directory. */ 12 | class Directory 13 | { 14 | public: 15 | 16 | /** Default constructor. */ 17 | Directory(); 18 | 19 | /** Destructor. */ 20 | ~Directory(); 21 | 22 | /** 23 | * Open a directory to search for files in this directory. 24 | * @param [in] dirPath The path to the directory to be searched. 25 | * @param [in] pattern A search pattern (e.g. "*.inf"). 26 | * @param [in] dirsOnly Whether the search should ignore files and should only return directories. 27 | * @return \c true when the directory was successfully opened. If directory could not be opened, Error::getLastError() can be used for further information on the error. 28 | */ 29 | bool open(const String& dirPath, const String& pattern = String(), bool dirsOnly = false); 30 | 31 | /** 32 | * Close the opened directory. 33 | */ 34 | void close(); 35 | 36 | /** 37 | * Search for the next matching entry in the opened directory. 38 | * @param [out] name The name of the next matching entry. 39 | * @param [out] isDir Whether the entry is a directory. 40 | * @return \c true when a matching entry was found. \c false indicates that there are no more matching entries or that another error occurred. Error::getLastError() can be used for further information on the error. 41 | */ 42 | bool read(String& name, bool& isDir); 43 | 44 | /** 45 | * Check if directory exists. 46 | * @param [in] dirPath The directory. 47 | * @return \c true if it exists. 48 | */ 49 | static bool exists(const String& dirPath); 50 | 51 | /** 52 | * Create a directory. The parent directories in the path are created if they do not exist. 53 | * @ param [in] dirPath The path of the directory to be created. 54 | * @return \c true if the directory was created successfully. 55 | */ 56 | static bool create(const String& dirPath); 57 | 58 | /** 59 | * Remove a directory from the file system. If \c recursive is not set to \c true, the function will fail if the directory is not empty. 60 | * @param [in] dirPath The path to the directory to be removed. 61 | * @param [in] recursive Whether the directory should be removed removed recursively. 62 | * @return \c true when the directory was successfully deleted. If directory was not successfully deleted, Error::getLastError() can be used for further information on the error. 63 | */ 64 | static bool unlink(const String& dirPath, bool recursive = false); 65 | 66 | /** 67 | * Remove a directory including its parents. If \c recursive is not set to \c true, the function will fail if the directory is not empty. Parent directories are removed if they would remain empty. 68 | * @param [in] dirPath The path to be removed. 69 | * @param [in] recursive Whether the directory should be removed removed recursively. 70 | * @return \c true when the directories was successfully deleted. If directory was not successfully deleted, Error::getLastError() can be used for further information on the error. Parent directories may still exist even when this function returned \c true. 71 | */ 72 | static bool purge(const String& dirPath, bool recursive = false); 73 | 74 | /** 75 | * Change current working directory. 76 | * @note This affects all threads of the process. 77 | * @param [in] dirPath The directory to change to. This can be an absolute or relative path. 78 | * @return \c true if the working directory was changed successfully. If it could not be changed, Error::getLastError() can be used for further information on the error. 79 | */ 80 | static bool change(const String& dirPath); 81 | 82 | /** 83 | * Get current working directory. 84 | * @return The absolute path of the current working directory. 85 | */ 86 | static String getCurrentDirectory(); 87 | 88 | /** 89 | * Get directory for temporary data. 90 | * @return The absolute path to the temp directory. 91 | */ 92 | static String getTempDirectory(); 93 | 94 | /** 95 | * Get the home directory of the current user. 96 | * @return The absolute path to the home directory. 97 | */ 98 | static String getHomeDirectory(); 99 | 100 | private: 101 | bool dirsOnly; 102 | #ifdef _WIN32 103 | void* findFile; /**< Win32 FindFirstFile HANDLE */ 104 | #ifdef _UNICODE 105 | char ffd[592]; /**< Buffer for WIN32_FIND_DATA */ 106 | #else 107 | char ffd[320]; /**< Buffer for WIN32_FIND_DATA */ 108 | #endif 109 | bool bufferedEntry; /**< Whether there is a buffered search result in ffd. */ 110 | String dirpath; /**< The path to the directory to be searched. */ 111 | String pattern; /**< A search pattern (e.g. "*.inf") */ 112 | #else 113 | void* dp; /**< Directory descriptor. */ 114 | String dirpath; /**< The path to the directory to be searched. */ 115 | String pattern; /**< A search pattern (e.g. "*.inf"). */ 116 | #endif 117 | 118 | Directory(const Directory&); 119 | Directory& operator=(const Directory&); 120 | }; 121 | -------------------------------------------------------------------------------- /include/nstd/Document/Json.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Json 7 | { 8 | public: 9 | class Parser 10 | { 11 | public: 12 | Parser(); 13 | ~Parser(); 14 | 15 | int getErrorLine() const; 16 | int getErrorColumn() const; 17 | String getErrorString() const; 18 | 19 | bool parse(const char* data, Variant& result); 20 | bool parse(const String& data, Variant& result); 21 | 22 | private: 23 | class Private; 24 | Private* p; 25 | }; 26 | 27 | public: 28 | /** 29 | * Strips C/C++ style comments from JSON data without affecting the line in which data is declared. 30 | * 31 | * @param [in] data The JSON data. 32 | * @return The JSON data with stripped comments. 33 | */ 34 | static String stripComments(const String& data); 35 | 36 | static bool parse(const char* data, Variant& result); 37 | static bool parse(const String& data, Variant& result); 38 | 39 | static String toString(const Variant& data); 40 | 41 | private: 42 | class Private; 43 | }; 44 | -------------------------------------------------------------------------------- /include/nstd/Document/Xml.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Xml 9 | { 10 | public: 11 | class Element; 12 | 13 | class Variant 14 | { 15 | public: 16 | enum Type 17 | { 18 | nullType, 19 | elementType, 20 | textType, 21 | }; 22 | 23 | public: 24 | 25 | Variant() : data(&nullData) {} 26 | ~Variant() {clear();} 27 | 28 | Variant(const Variant& other) 29 | { 30 | if(other.data->ref) 31 | { 32 | data = other.data; 33 | Atomic::increment(data->ref); 34 | } 35 | else 36 | data = &nullData; 37 | } 38 | 39 | Variant(const Element& val) 40 | { 41 | data = (Data*)new char[sizeof(Data) + sizeof(Element)]; 42 | Element* element = (Element*)(data + 1); 43 | new (element) Element(val); 44 | data->type = elementType; 45 | data->ref = 1; 46 | } 47 | 48 | Variant(const String& val) 49 | { 50 | data = (Data*)new char[sizeof(Data) + sizeof(String)]; 51 | String* string = (String*)(data + 1); 52 | new (string) String(val); 53 | data->type = textType; 54 | data->ref = 1; 55 | } 56 | 57 | void clear() 58 | { 59 | if(data->ref && Atomic::decrement(data->ref) == 0) 60 | { 61 | switch(data->type) 62 | { 63 | case elementType: ((Element*)(data + 1))->~Element(); break; 64 | case textType: ((String*)(data + 1))->~String(); break; 65 | default: break; 66 | } 67 | delete[] (char*)data; 68 | } 69 | data = &nullData; 70 | } 71 | 72 | Type getType() const {return data->type;} 73 | bool isNull() const {return data->type == nullType;} 74 | 75 | bool isText() const {return data->type == textType;} 76 | 77 | String toString() const 78 | { 79 | if(data->type == textType) 80 | return *(const String*)(data + 1); 81 | return String(); 82 | } 83 | 84 | Variant& operator=(const String& other) 85 | { 86 | if(data->type != textType || data->ref > 1) 87 | { 88 | clear(); 89 | data = (Data*)new char[sizeof(Data) + sizeof(String)]; 90 | String* string = (String*)(data + 1); 91 | new (string) String(other); 92 | data->type = textType; 93 | data->ref = 1; 94 | } 95 | else 96 | *(String*)(data + 1) = other; 97 | return *this; 98 | } 99 | 100 | bool isElement() const {return data->type == elementType;} 101 | 102 | const Element& toElement() const 103 | { 104 | if(data->type == elementType) 105 | return *(const Element*)(data + 1); 106 | static const Element element = Element(); 107 | return element; 108 | } 109 | 110 | Element& toElement() 111 | { 112 | if(data->type != elementType) 113 | { 114 | clear(); 115 | data = (Data*)new char[sizeof(Data) + sizeof(Element)]; 116 | Element* element = (Element*)(data + 1); 117 | new (element) Element; 118 | data->type = elementType; 119 | data->ref = 1; 120 | return *element; 121 | } 122 | else if(data->ref > 1) 123 | { 124 | Data* newData = (Data*)new char[sizeof(Data) + sizeof(Element)]; 125 | Element* element = (Element*)(data + 1); 126 | new (element) Element(*(const Element*)(data + 1)); 127 | clear(); 128 | data = newData; 129 | data->type = elementType; 130 | data->ref = 1; 131 | return *element; 132 | } 133 | return *(Element*)(data + 1); 134 | } 135 | 136 | private: 137 | struct Data 138 | { 139 | Type type; 140 | volatile usize ref; 141 | }; 142 | 143 | static struct NullData : public Data 144 | { 145 | NullData() 146 | { 147 | type = nullType; 148 | ref = 0; 149 | } 150 | } nullData; 151 | 152 | Data* data; 153 | Data _data; 154 | }; 155 | 156 | class Element 157 | { 158 | public: 159 | int line; 160 | int column; 161 | String type; 162 | HashMap attributes; 163 | List content; 164 | 165 | public: 166 | void clear() 167 | { 168 | type.clear(); 169 | attributes.clear(); 170 | content.clear(); 171 | } 172 | 173 | String toString() const; 174 | }; 175 | 176 | class Parser 177 | { 178 | public: 179 | Parser(); 180 | ~Parser(); 181 | 182 | int getErrorLine() const; 183 | int getErrorColumn() const; 184 | String getErrorString() const; 185 | 186 | bool parse(const char* data, Element& element); 187 | bool parse(const String& data, Element& element); 188 | 189 | bool load(const String& file, Element& element); 190 | 191 | private: 192 | class Private; 193 | Private* p; 194 | }; 195 | 196 | public: 197 | static bool parse(const char* data, Element& element); 198 | static bool parse(const String& data, Element& element); 199 | 200 | static bool load(const String& file, Element& element); 201 | static bool save(const Element& element, const String& file); 202 | 203 | static String toString(const Element& element); 204 | 205 | private: 206 | class Private; 207 | }; 208 | -------------------------------------------------------------------------------- /include/nstd/Error.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Error 7 | { 8 | public: 9 | static void setLastError(uint error); 10 | static uint getLastError(); 11 | static String getErrorString(uint error = getLastError()); 12 | static void setErrorString(const String& error); 13 | 14 | private: 15 | class Private; 16 | }; 17 | -------------------------------------------------------------------------------- /include/nstd/File.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class File 7 | { 8 | public: 9 | enum Flags 10 | { 11 | readFlag = 0x0001, 12 | writeFlag = 0x0002, 13 | appendFlag = 0x0004, 14 | openFlag = 0x0008, 15 | }; 16 | 17 | enum Position 18 | { 19 | setPosition, 20 | currentPosition, 21 | endPosition, 22 | }; 23 | 24 | struct Time 25 | { 26 | int64 writeTime; 27 | int64 accessTime; 28 | int64 creationTime; 29 | }; 30 | 31 | File(); 32 | ~File(); 33 | 34 | bool open(const String& file, uint flags = readFlag); 35 | void close(); 36 | bool isOpen() const; 37 | 38 | /** 39 | * Get size of the file. 40 | * @return The size of the file in bytes. In case of an error -1 is returned. 41 | */ 42 | int64 size(); 43 | 44 | /** 45 | * Read a data block from the file at the current read position. 46 | * The file has to be opened with Flags::readFlag. If successful, the read position changes to after 47 | * the block that was read. 48 | * @param [in] buffer A buffer where the data should be stored. It has to be large 49 | * enough to hold \c length bytes. 50 | * @param [in] length The count of the bytes to read. 51 | * @return The amount of bytes that was read. This could be equal 0 or less than \c length when the end of the 52 | * file was reached. In case of an error -1 is returned. 53 | */ 54 | ssize read(void* buffer, usize length); 55 | 56 | /** 57 | * Read all data from current read position till the end of the file. 58 | * @param [out] data The data. 59 | * @return Whether the data was successfully read. 60 | */ 61 | bool readAll(String& data); 62 | 63 | ssize write(const void* buffer, usize length); 64 | 65 | bool write(const String& data); 66 | 67 | /** 68 | * Move the read or write offset position within the file. 69 | * @param [in] offset The offset in bytes from \c start. 70 | * @param [in] start The position from where to start the move operation. 71 | * @return The position in the file relative to the beginning of the file after the seek operation. 72 | */ 73 | int64 seek(int64 offset, Position start = setPosition); 74 | 75 | bool flush(); 76 | 77 | static String getDirectoryName(const String& file); 78 | static String getBaseName(const String& file, const String& extension = String()); 79 | static String getStem(const String& file, const String& extension = String()); 80 | 81 | /** 82 | * Get the extension of a file name or path (without the dot). 83 | * @param [in] file The file name or path off which to get the extension. 84 | */ 85 | static String getExtension(const String& file); 86 | 87 | static String simplifyPath(const String& path); 88 | static bool isAbsolutePath(const String& path); 89 | static String getRelativePath(const String& from, const String& to); 90 | static String getAbsolutePath(const String& path); 91 | 92 | static bool time(const String& file, Time& time); 93 | 94 | static bool exists(const String& file); 95 | static bool unlink(const String& file); 96 | static bool rename(const String& from, const String& to, bool failIfExists = true); 97 | static bool copy(const String& src, const String& destination, bool failIfExists = true); 98 | static bool createSymbolicLink(const String& target, const String& file); 99 | 100 | static bool isExecutable(const String& file); 101 | 102 | static bool readAll(const String& file, String& data); 103 | 104 | private: 105 | void* fp; 106 | 107 | File(const File&); 108 | File& operator=(const File&); 109 | }; 110 | -------------------------------------------------------------------------------- /include/nstd/Library.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Library 7 | { 8 | public: 9 | Library(); 10 | ~Library(); 11 | 12 | bool load(const String& name); 13 | 14 | void* findSymbol(const String& name); 15 | 16 | private: 17 | void* library; 18 | 19 | Library(const Library&); 20 | Library& operator=(const Library&); 21 | }; 22 | -------------------------------------------------------------------------------- /include/nstd/Log.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Log 7 | { 8 | public: 9 | enum Level 10 | { 11 | debug = 10, 12 | info = 20, 13 | warning = 30, 14 | error = 40, 15 | critical = 50, 16 | }; 17 | 18 | enum Device 19 | { 20 | stdOutErr, ///< Write log messages up to log level warning to stdout and errors to stderr 21 | syslog ///< Write log messages to syslog (on Linux) 22 | }; 23 | 24 | public: 25 | /** 26 | * Set logging format. 27 | * 28 | * @param [in] lineFormat The log message format. The following placeholders can be used: 29 | * %l - The log level (e.g. "info", "error", "warning", ...) 30 | * %m - The message text. 31 | * %t - The timestamp. 32 | * %P - The process id. 33 | * %T - The id of the calling thread. 34 | * @param [in] timeFormat The format of the timestamp similar to the format string of Time::toString. 35 | */ 36 | static void setFormat(const String& lineFormat, const String& timeFormat = String("%H:%M:%S")); 37 | 38 | /** 39 | * Controls how log messages are handled. 40 | * The default is @c Log::stdOutErr. 41 | * 42 | * @param [in] device The log output device. 43 | */ 44 | static void setDevice(Device device); 45 | 46 | /** 47 | * Sets the log level minimum . 48 | * Log messages smaller than this level are ignored. 49 | * 50 | * @param [in] level The log level. 51 | */ 52 | static void setLevel(int level); 53 | 54 | static void logf(int level, const char* format, ...); 55 | static void debugf(const char* format, ...); 56 | static void infof(const char* format, ...); 57 | static void warningf(const char* format, ...); 58 | static void errorf(const char* format, ...); 59 | }; 60 | -------------------------------------------------------------------------------- /include/nstd/Math.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Math 7 | { 8 | public: 9 | template static const T& max(const T& a, const T& b) {return a > b ? a : b;} 10 | template static const T& min(const T& a, const T& b) {return a < b ? a : b;} 11 | template static const T abs(const T& v) {return v < 0 ? -v : v;} // TODO: fast abs for double/float 12 | 13 | static double floor(double v); // TODO: inline this 14 | static float floor(float v); // TODO: inline this 15 | static double ceil(double v); // TODO: inline this 16 | static float ceil(float v); // TODO: inline this 17 | static double exp(double v); // TODO: inline this 18 | static float exp(float v); // TODO: inline this 19 | 20 | static uint random(); // TODO: inline this 21 | static uint random(uint seed); 22 | 23 | static const usize randomMax; 24 | }; 25 | -------------------------------------------------------------------------------- /include/nstd/Memory.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Memory 7 | { 8 | public: 9 | static void copy(void* dest, const void* src, usize count); 10 | static void move(void* dest, const void* src, usize count); 11 | static void fill(void* buffer, byte value, usize count); 12 | static void zero(void* buffer, usize count); 13 | static int compare(const void* ptr1, const void* ptr2, usize count); 14 | }; 15 | -------------------------------------------------------------------------------- /include/nstd/Monitor.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Monitor 7 | { 8 | public: 9 | class Guard 10 | { 11 | public: 12 | Guard(Monitor &monitor) : _monitor(monitor) { monitor.lock(); } 13 | ~Guard() { _monitor.unlock(); } 14 | 15 | bool wait() {return _monitor.wait();} 16 | bool wait(int64 timeout) {return _monitor.wait(timeout);} 17 | 18 | private: 19 | Monitor& _monitor; 20 | }; 21 | 22 | public: 23 | Monitor(); 24 | ~Monitor(); 25 | 26 | bool tryLock(); 27 | void lock(); 28 | bool wait(); 29 | bool wait(int64 timeout); 30 | void unlock(); 31 | void set(); 32 | 33 | private: 34 | bool signaled; 35 | #ifdef _WIN32 36 | #ifdef _AMD64 37 | byte cdata[8]; // sizeof(CONDITION_VARIABLE) 38 | byte mdata[40]; // sizeof(CRITICAL_SECTION) 39 | #else 40 | byte cdata[4]; // sizeof(CONDITION_VARIABLE) 41 | byte mdata[24]; // sizeof(CRITICAL_SECTION) 42 | #endif 43 | #else 44 | #ifdef _AMD64 45 | int64 cdata[6]; // sizeof(pthread_cond_t) 46 | int64 mdata[5]; // sizeof(pthread_mutex_t) 47 | #else 48 | int64 cdata[6]; // sizeof(pthread_cond_t) 49 | int64 mdata[3]; // sizeof(pthread_mutex_t) 50 | #endif 51 | #endif 52 | 53 | Monitor(const Monitor&); 54 | Monitor& operator=(const Monitor&); 55 | }; 56 | 57 | 58 | -------------------------------------------------------------------------------- /include/nstd/Mutex.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Mutex 7 | { 8 | public: 9 | class Guard 10 | { 11 | public: 12 | Guard(Mutex &mutex) : _mutex(mutex) { mutex.lock(); } 13 | ~Guard() { _mutex.unlock(); } 14 | 15 | private: 16 | Mutex& _mutex; 17 | }; 18 | 19 | public: 20 | Mutex(); 21 | ~Mutex(); 22 | 23 | void lock(); 24 | bool tryLock(); 25 | void unlock(); 26 | 27 | private: 28 | #ifdef _WIN32 29 | #ifdef _AMD64 30 | byte data[40]; // sizeof(CRITICAL_SECTION) 31 | #else 32 | byte data[24]; // sizeof(CRITICAL_SECTION) 33 | #endif 34 | #else 35 | #ifdef _AMD64 36 | int64 data[5]; // sizeof(pthread_mutex_t) 37 | #else 38 | int64 data[3]; // sizeof(pthread_mutex_t) 39 | #endif 40 | #endif 41 | 42 | Mutex(const Mutex &); 43 | Mutex &operator=(const Mutex &); 44 | }; 45 | -------------------------------------------------------------------------------- /include/nstd/PoolList.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | template class PoolList 7 | { 8 | private: 9 | struct Item; 10 | public: 11 | class Iterator 12 | { 13 | public: 14 | Iterator() : item(0) {} 15 | const T& operator*() const {return *(T*)(item + 1);} 16 | T& operator*() {return *(T*)(item + 1);} 17 | const T* operator->() const {return (T*)(item + 1);} 18 | T* operator->() {return (T*)(item + 1);} 19 | const Iterator& operator++() {item = item->next; return *this;} 20 | const Iterator& operator--() {item = item->prev; return *this;} 21 | Iterator operator++() const {return item->next;} 22 | Iterator operator--() const {return item->prev;} 23 | bool operator==(const Iterator& other) const {return item == other.item;} 24 | bool operator!=(const Iterator& other) const {return item != other.item;} 25 | 26 | private: 27 | Item* item; 28 | 29 | Iterator(Item* item) : item(item) {} 30 | 31 | friend class PoolList; 32 | }; 33 | 34 | PoolList() : _end(&endItem), _begin(&endItem), _size(0), freeItem(0), blocks(0) 35 | { 36 | endItem.prev = 0; 37 | endItem.next = 0; 38 | } 39 | 40 | ~PoolList() 41 | { 42 | for(Item* i = _begin.item, * end = &endItem; i != end; i = i->next) 43 | ((T*)(i + 1))->~T(); 44 | for(ItemBlock* i = blocks, * next; i; i = next) 45 | { 46 | next = i->next; 47 | delete[] (char*)i; 48 | } 49 | } 50 | 51 | const Iterator& begin() const {return _begin;} 52 | const Iterator& end() const {return _end;} 53 | 54 | const T& front() const {return _begin.item->value;} 55 | const T& back() const {return _end.item->prev->value;} 56 | 57 | T& front() { return _begin.item->value; } 58 | T& back() { return _end.item->prev->value; } 59 | 60 | Iterator removeFront() {return remove(_begin);} 61 | Iterator removeBack() {return remove(_end.item->prev);} 62 | 63 | usize size() const {return _size;} 64 | bool isEmpty() const {return endItem.prev == 0;} 65 | 66 | T& append() {return linkFreeItem(new (allocateFreeItem()) T);} 67 | template 68 | T& append(A a) {return linkFreeItem(new (allocateFreeItem()) T(a));} 69 | template 70 | T& append(A a, B b) {return linkFreeItem(new (allocateFreeItem()) T(a, b));} 71 | template 72 | T& append(A a, B b, C c) {return linkFreeItem(new (allocateFreeItem()) T(a, b, c));} 73 | template 74 | T& append(A a, B b, C c, D d) {return linkFreeItem(new (allocateFreeItem()) T(a, b, c, d));} 75 | template 76 | T& append(A a, B b, C c, D d, E e) {return linkFreeItem(new (allocateFreeItem()) T(a, b, c, d, e));} 77 | template 78 | T& append(A a, B b, C c, D d, E e, F f) {return linkFreeItem(new (allocateFreeItem()) T(a, b, c, d, e, f));} 79 | template 80 | T& append(A a, B b, C c, D d, E e, F f, G g) {return linkFreeItem(new (allocateFreeItem()) T(a, b, c, d, e, f, g));} 81 | 82 | void clear() 83 | { 84 | for(Item* i = _begin.item, * end = &endItem; i != end; i = i->next) 85 | { 86 | ((T*)(i + 1))->~T(); 87 | i->prev = freeItem; 88 | freeItem = i; 89 | } 90 | _begin.item = &endItem; 91 | endItem.prev = 0; 92 | _size = 0; 93 | } 94 | 95 | void swap(PoolList& other) 96 | { 97 | Item* tmpFirst = _begin.item; 98 | Item* tmpLast = endItem.prev; 99 | usize tmpSize = _size; 100 | Item* tmpFreeItem = freeItem; 101 | ItemBlock* tmpBlocks = blocks; 102 | 103 | if((endItem.prev = other.endItem.prev)) 104 | { 105 | endItem.prev->next = &endItem; 106 | _begin.item = other._begin.item; 107 | } 108 | else 109 | _begin.item = &endItem; 110 | _size = other._size; 111 | freeItem = other.freeItem; 112 | blocks = other.blocks; 113 | 114 | if((other.endItem.prev = tmpLast)) 115 | { 116 | tmpLast->next = &other.endItem; 117 | other._begin.item = tmpFirst; 118 | } 119 | else 120 | other._begin.item = &other.endItem; 121 | other._size = tmpSize; 122 | other.freeItem = tmpFreeItem; 123 | other.blocks = tmpBlocks; 124 | } 125 | 126 | Iterator remove(const Iterator& it) 127 | { 128 | Item* item = it.item; 129 | remove(*(T*)(item + 1)); 130 | return item->next; 131 | } 132 | 133 | void remove(const T& value) 134 | { 135 | Item* item = (Item*)&value - 1; 136 | 137 | if(!item->prev) 138 | (_begin.item = item->next)->prev = 0; 139 | else 140 | (item->prev->next = item->next)->prev = item->prev; 141 | 142 | --_size; 143 | 144 | ((T*)(item + 1))->~T(); 145 | item->prev = freeItem; 146 | freeItem = item; 147 | } 148 | 149 | private: 150 | struct Item 151 | { 152 | Item* prev; 153 | Item* next; 154 | }; 155 | struct ItemBlock 156 | { 157 | ItemBlock* next; 158 | }; 159 | 160 | private: 161 | Iterator _end; 162 | Iterator _begin; 163 | usize _size; 164 | Item endItem; 165 | Item* freeItem; 166 | ItemBlock* blocks; 167 | 168 | private: 169 | T* allocateFreeItem() 170 | { 171 | Item* item = freeItem; 172 | if(!item) 173 | { 174 | ItemBlock* itemBlock = (ItemBlock*)new char[sizeof(ItemBlock) + (sizeof(Item) + sizeof(T)) * 4]; 175 | itemBlock->next = blocks; 176 | blocks = itemBlock; 177 | for(Item* i = (Item*)(itemBlock + 1), * end = (Item*)((char*)i + 4 * (sizeof(Item) + sizeof(T))); 178 | i < end; 179 | i = (Item*)((char*)i + (sizeof(Item) + sizeof(T)))) 180 | { 181 | i->prev = item; 182 | item = i; 183 | } 184 | freeItem = item; 185 | } 186 | return (T*)(item + 1); 187 | } 188 | 189 | T& linkFreeItem(T* t) 190 | { 191 | Item* item = freeItem; 192 | freeItem = item->prev; 193 | Item* insertPos = _end.item; 194 | if((item->prev = insertPos->prev)) 195 | insertPos->prev->next = item; 196 | else 197 | _begin.item = item; 198 | item->next = insertPos; 199 | insertPos->prev = item; 200 | ++_size; 201 | return *t; 202 | } 203 | 204 | private: 205 | PoolList(const PoolList&); 206 | PoolList& operator=(const PoolList&); 207 | }; 208 | -------------------------------------------------------------------------------- /include/nstd/PoolMap.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | template class PoolMap 7 | { 8 | private: 9 | struct Item; 10 | public: 11 | class Iterator 12 | { 13 | public: 14 | Iterator() : item(0) {} 15 | const T& key() const {return item->key;} 16 | const V& operator*() const {return item->value;} 17 | V& operator*() {return item->value;} 18 | const V* operator->() const {return &item->value;} 19 | V* operator->() {return &item->value;} 20 | const Iterator& operator++() {item = item->next; return *this;} 21 | const Iterator& operator--() {item = item->prev; return *this;} 22 | Iterator operator++() const {return item->next;} 23 | Iterator operator--() const {return item->prev;} 24 | bool operator==(const Iterator& other) const {return item == other.item;} 25 | bool operator!=(const Iterator& other) const {return item != other.item;} 26 | 27 | private: 28 | Item* item; 29 | 30 | Iterator(Item* item) : item(item) {} 31 | 32 | friend class PoolMap; 33 | }; 34 | 35 | PoolMap() : _end(&endItem), _begin(&endItem), _size(0), capacity(500), data(0), freeItem(0), blocks(0) 36 | { 37 | endItem.prev = 0; 38 | endItem.next = 0; 39 | } 40 | 41 | explicit PoolMap(usize capacity) : _end(&endItem), _begin(&endItem), _size(0), capacity(capacity), data(0), freeItem(0), blocks(0) 42 | { 43 | endItem.prev = 0; 44 | endItem.next = 0; 45 | this->capacity |= (usize)!capacity; 46 | } 47 | 48 | ~PoolMap() 49 | { 50 | delete[] (char*)data; 51 | for(Item* i = _begin.item, * end = &endItem; i != end; i = i->next) 52 | i->~Item(); 53 | for(ItemBlock* i = blocks, * next; i; i = next) 54 | { 55 | next = i->next; 56 | delete[] (char*)i; 57 | } 58 | } 59 | 60 | const Iterator& begin() const {return _begin;} 61 | const Iterator& end() const {return _end;} 62 | 63 | const T& front() const { return _begin.item->value; } 64 | const T& back() const { return _end.item->prev->value; } 65 | 66 | V& front() { return _begin.item->value; } 67 | V& back() { return _end.item->prev->value; } 68 | 69 | Iterator removeFront() {return remove(_begin);} 70 | Iterator removeBack() {return remove(_end.item->prev);} 71 | 72 | usize size() const {return _size;} 73 | bool isEmpty() const {return endItem.prev == 0;} 74 | 75 | V& append(const T& key) {return insert(_end, key).item->value;} 76 | 77 | void clear() 78 | { 79 | for(Item* i = _begin.item, * end = &endItem; i != end; i = i->next) 80 | { 81 | i->~Item(); 82 | *i->cell = 0; 83 | i->prev = freeItem; 84 | freeItem = i; 85 | } 86 | _begin.item = &endItem; 87 | endItem.prev = 0; 88 | _size = 0; 89 | } 90 | 91 | void swap(PoolMap& other) 92 | { 93 | Item* tmpFirst = _begin.item; 94 | Item* tmpLast = endItem.prev; 95 | usize tmpSize = _size; 96 | usize tmpCapacity = capacity; 97 | Item** tmpData = data; 98 | Item* tmpFreeItem = freeItem; 99 | ItemBlock* tmpBlocks = blocks; 100 | 101 | if((endItem.prev = other.endItem.prev)) 102 | { 103 | endItem.prev->next = &endItem; 104 | _begin.item = other._begin.item; 105 | } 106 | else 107 | _begin.item = &endItem; 108 | _size = other._size; 109 | capacity = other.capacity; 110 | data = other.data; 111 | freeItem = other.freeItem; 112 | blocks = other.blocks; 113 | 114 | if((other.endItem.prev = tmpLast)) 115 | { 116 | tmpLast->next = &other.endItem; 117 | other._begin.item = tmpFirst; 118 | } 119 | else 120 | other._begin.item = &other.endItem; 121 | other._size = tmpSize; 122 | other.capacity = tmpCapacity; 123 | other.data = tmpData; 124 | other.freeItem = tmpFreeItem; 125 | other.blocks = tmpBlocks; 126 | } 127 | 128 | Iterator find(const T& key) const 129 | { 130 | if(!data) return _end; 131 | usize hashCode = hash(key); 132 | Item* item = data[hashCode % capacity]; 133 | while(item) 134 | { 135 | if(item->key == key) return item; 136 | item = item->nextCell; 137 | } 138 | return _end; 139 | } 140 | 141 | bool contains(const T& key) const {return find(key) != _end;} 142 | 143 | Iterator insert(const Iterator& position, const T& key) 144 | { 145 | Iterator it = find(key); 146 | if(it != _end) 147 | return it; 148 | 149 | if(!data) 150 | { 151 | data = (Item**)new char[sizeof(Item*) * capacity]; 152 | Memory::zero(data, sizeof(Item*) * capacity); 153 | } 154 | 155 | Item* item = freeItem; 156 | if(!item) 157 | { 158 | ItemBlock* itemBlock = (ItemBlock*)new char[sizeof(ItemBlock) + sizeof(Item) * 4]; 159 | itemBlock->next = blocks; 160 | blocks = itemBlock; 161 | for(Item* i = (Item*)(itemBlock + 1), * end = i + 4; i < end; ++i) 162 | { 163 | i->prev = item; 164 | item = i; 165 | } 166 | freeItem = item; 167 | } 168 | 169 | usize hashCode = hash(key); 170 | new(item) Item(key); 171 | freeItem = item->prev; 172 | 173 | Item** cell; 174 | item->cell = (cell = &data[hashCode % capacity]); 175 | if((item->nextCell = *cell)) 176 | item->nextCell->cell = &item->nextCell; 177 | *cell = item; 178 | 179 | Item* insertPos = position.item; 180 | if((item->prev = insertPos->prev)) 181 | insertPos->prev->next = item; 182 | else 183 | _begin.item = item; 184 | 185 | item->next = insertPos; 186 | insertPos->prev = item; 187 | ++_size; 188 | return item; 189 | } 190 | 191 | Iterator remove(const Iterator& it) 192 | { 193 | Item* item = it.item; 194 | remove(item->value); 195 | return item->next; 196 | } 197 | 198 | void remove(const V& value) 199 | { 200 | Item* item = (Item*)&value; 201 | 202 | if((*item->cell = item->nextCell)) 203 | item->nextCell->cell = item->cell; 204 | 205 | if(!item->prev) 206 | (_begin.item = item->next)->prev = 0; 207 | else 208 | (item->prev->next = item->next)->prev = item->prev; 209 | 210 | --_size; 211 | 212 | item->~Item(); 213 | item->prev = freeItem; 214 | freeItem = item; 215 | } 216 | 217 | void remove(const T& key) 218 | { 219 | Iterator it = find(key); 220 | if(it != _end) 221 | remove(it.item->value); 222 | } 223 | 224 | private: 225 | struct Item 226 | { 227 | V value; 228 | const T key; 229 | Item** cell; 230 | Item* nextCell; 231 | Item* prev; 232 | Item* next; 233 | 234 | Item() : value(), key() {} 235 | 236 | Item(const T& key) : value(), key(key) {} 237 | }; 238 | struct ItemBlock 239 | { 240 | ItemBlock* next; 241 | }; 242 | 243 | Iterator _end; 244 | Iterator _begin; 245 | usize _size; 246 | usize capacity; 247 | Item** data; 248 | Item endItem; 249 | Item* freeItem; 250 | ItemBlock* blocks; 251 | 252 | PoolMap(const PoolMap&); 253 | PoolMap& operator=(const PoolMap&); 254 | }; 255 | -------------------------------------------------------------------------------- /include/nstd/Process.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | class Process 8 | { 9 | public: 10 | 11 | Process(); 12 | ~Process(); 13 | 14 | /** 15 | * Start an external process. 16 | * @param[in] command The command to start the process. The first word in \c command should be the name of the executable or a path 17 | * to the executable. Further words in \c command are considered to be arguments for the process. 18 | * @param[in] environment Environment variables to be used for new process. The environment variable from the current process will be inherited if the map is empty. 19 | * @return The process id of the newly started process or \c 0 if an errors occurred. 20 | */ 21 | uint32 start(const String& command, const Map& environment = Map()); 22 | 23 | /** 24 | * Start an external process. 25 | * @param[in] executable The path to the executable to be started. 26 | * @param[in] argc The amount of parameters in \c argv. 27 | * @param[in] argv Arguments to the process. 28 | * @param[in] environment Environment variables to be used for new process. The environment variable from the current process will be inherited if the map is empty. 29 | * @return The process id of the newly started process or \c 0 if an errors occurred. 30 | */ 31 | uint32 start(const String& executable, int argc, char* const argv[], const Map& environment = Map()); 32 | 33 | /** 34 | * Get id of the process. 35 | * @return The process id or \c 0 if a process was not started. 36 | */ 37 | uint32 getProcessId() const {return pid;} 38 | 39 | /** 40 | * Return the running state of the process. 41 | * @return \c true when the process is currently running and can be joined using \c join(). 42 | */ 43 | bool isRunning() const; 44 | 45 | /** 46 | * Wait for the process to terminate and get its exit code. 47 | * @param[out] exitCode The exit code of the process. 48 | * @return Whether the process terminated properly. 49 | */ 50 | bool join(uint32& exitCode); 51 | 52 | /** 53 | * Wait for the process to terminate. 54 | * @return Whether the process terminated properly. 55 | */ 56 | bool join(); 57 | 58 | /** 59 | * Kill and join the process. The method send a hard KILL signal to the process and waits for it to terminate. 60 | * @return Whether the process terminated properly. 61 | */ 62 | bool kill(); 63 | 64 | enum Stream 65 | { 66 | stdoutStream = 0x01, 67 | stderrStream = 0x02, 68 | stdinStream = 0x04, 69 | }; 70 | 71 | bool open(const String& command, uint streams = stdoutStream, const Map& environment = Map()); 72 | 73 | bool open(const String& executable, int argc, char* const argv[], uint streams = stdoutStream, const Map& environment = Map()); 74 | 75 | bool open(const String& executable, const List& args, uint streams = stdoutStream, const Map& environment = Map()); 76 | 77 | /* 78 | * Closes the streams of an opened process. 79 | * @param [in] streams The streams to be closed. 80 | */ 81 | void close(uint streams = stdoutStream | stderrStream | stdinStream); 82 | 83 | ssize read(void* buffer, usize length); 84 | ssize read(void* buffer, usize length, uint& streams); 85 | ssize write(const void* buffer, usize length); 86 | 87 | static uint32 getCurrentProcessId(); 88 | 89 | static void exit(uint32 exitCode); 90 | 91 | static String getEnvironmentVariable(const String& name, const String& defaultValue = String()); 92 | static bool setEnvironmentVariable(const String& name, const String& value); 93 | static Map getEnvironmentVariables(); 94 | static String getExecutablePath(); 95 | 96 | static Process* wait(Process** processes, usize count); 97 | static void interrupt(); 98 | 99 | #ifndef _WIN32 100 | static bool daemonize(const String& logFile = "/dev/null"); 101 | #endif 102 | 103 | public: 104 | enum OptionFlags 105 | { 106 | optionFlag = 0x0, 107 | argumentFlag = 0x1, 108 | optionalFlag = 0x2, 109 | }; 110 | 111 | struct Option 112 | { 113 | int character; 114 | const char* name; 115 | uint32 flags; 116 | }; 117 | 118 | class Arguments 119 | { 120 | public: 121 | template Arguments(int argc, char* argv[], const Option(&options)[N]) : argv(argv), argvEnd(argv + argc), options(options), optionsEnd(options + N), arg(""), inOpt(false), skipOpt(false) {++this->argv;} 122 | 123 | bool read(int& character, String& argument); 124 | 125 | private: 126 | char** argv; 127 | char** argvEnd; 128 | const Option* options; 129 | const Option* optionsEnd; 130 | const char* arg; 131 | bool inOpt; 132 | bool skipOpt; 133 | 134 | private: 135 | bool nextChar(); 136 | }; 137 | 138 | private: 139 | #ifdef _WIN32 140 | void* hProcess; 141 | void* hStdOutRead; 142 | void* hStdErrRead; 143 | void* hStdInWrite; 144 | #else 145 | int fdStdOutRead; 146 | int fdStdErrRead; 147 | int fdStdInWrite; 148 | #endif 149 | uint32 pid; 150 | 151 | Process(const Process&); 152 | Process& operator=(const Process&); 153 | 154 | private: 155 | class Private; 156 | }; 157 | -------------------------------------------------------------------------------- /include/nstd/RefCount.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class RefCount 7 | { 8 | public: 9 | class Object; 10 | 11 | template class Ptr 12 | { 13 | public: 14 | Ptr() : refObj(0), obj(0) {} 15 | 16 | Ptr(const Ptr& other) : refObj(other.refObj), obj(other.obj) 17 | { 18 | if(refObj) 19 | Atomic::increment(refObj->ref); 20 | } 21 | 22 | template Ptr(D* obj) : refObj(obj), obj(obj) 23 | { 24 | if(refObj) 25 | Atomic::increment(refObj->ref); 26 | } 27 | 28 | template Ptr(const Ptr& other) : refObj(other.refObj), obj(other.obj) 29 | { 30 | if(refObj) 31 | Atomic::increment(refObj->ref); 32 | } 33 | 34 | ~Ptr() 35 | { 36 | if(refObj && Atomic::decrement(refObj->ref) == 0) 37 | delete refObj; 38 | } 39 | 40 | Ptr& operator=(const Ptr& other) 41 | { 42 | if(other.refObj) 43 | Atomic::increment(other.refObj->ref); 44 | if(refObj && Atomic::decrement(refObj->ref) == 0) 45 | delete refObj; 46 | refObj = other.refObj; 47 | obj = other.obj; 48 | return *this; 49 | } 50 | 51 | Ptr& operator=(C* obj) 52 | { 53 | Object* refObj = obj; 54 | if(refObj) 55 | Atomic::increment(refObj->ref); 56 | if(this->refObj && Atomic::decrement(this->refObj->ref) == 0) 57 | delete this->refObj; 58 | this->refObj = refObj; 59 | this->obj = obj; 60 | return *this; 61 | } 62 | 63 | template Ptr& operator=(const Ptr& other) 64 | { 65 | if(other.refObj) 66 | Atomic::increment(other.refObj->ref); 67 | if(refObj && Atomic::decrement(refObj->ref) == 0) 68 | delete refObj; 69 | refObj = other.refObj; 70 | obj = other.obj; 71 | return *this; 72 | } 73 | 74 | C& operator*() const {return *obj;} 75 | C* operator->() const {return obj;} 76 | 77 | template bool operator==(D* other) const {return obj == other;} 78 | template bool operator!=(D* other) const {return obj != other;} 79 | template bool operator==(const Ptr& other) const {return obj == other.obj;} 80 | template bool operator!=(const Ptr& other) const {return obj != other.obj;} 81 | 82 | operator bool() const {return obj != 0;} 83 | 84 | void swap(Ptr& other) 85 | { 86 | C* tmp = other.obj; 87 | other.obj = obj; 88 | obj = tmp; 89 | } 90 | 91 | private: 92 | Object* refObj; 93 | C* obj; 94 | 95 | template friend class Ptr; 96 | }; 97 | 98 | class Object 99 | { 100 | public: 101 | Object() : ref(0) {} 102 | 103 | protected: 104 | virtual ~Object() {} 105 | 106 | private: 107 | usize ref; 108 | 109 | Object(const Object&); 110 | Object& operator=(const Object&); 111 | 112 | template friend class Ptr; 113 | }; 114 | }; 115 | -------------------------------------------------------------------------------- /include/nstd/Semaphore.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * A classic Semaphore for synchronization in multi thread environments. 4 | * @author Colin Graf 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | /** 12 | * Encapsulation of a semaphore object. 13 | */ 14 | class Semaphore 15 | { 16 | public: 17 | /** 18 | * Construct a new semaphore object. 19 | * @param value The initial value of the semaphore counter. 20 | */ 21 | Semaphore(uint value = 0); 22 | 23 | /** Destructor. */ 24 | ~Semaphore(); 25 | 26 | /** 27 | * Increment the semaphore counter. 28 | */ 29 | void signal(); 30 | 31 | /** 32 | * Decrement the semaphore counter. The method returns immediately if the 33 | * counter is greater than zero. Otherwise it blocks the execution of the 34 | * calling thread until another thread increases the semaphore counter. 35 | * @return Whether the semaphore counter was successfully decremented or not. 36 | */ 37 | bool wait(); 38 | 39 | /** 40 | * Decrement the semaphore counter. The method returns immediately if the 41 | * counter is greater than zero. Otherwise it blocks the execution of the 42 | * calling thread until another thread increases the semaphore counter or 43 | * a timeout occurs. 44 | * @param timeout The maximum time to wait. (in ms). 45 | * @return Whether the semaphore counter was successfully decremented or not. 46 | */ 47 | bool wait(int64 timeout); 48 | 49 | /** 50 | * Try to decrement the semaphore counter. This method returns immediately. 51 | * @return Whether the semaphore counter was successfully decremented or not. 52 | */ 53 | bool tryWait(); 54 | 55 | private: 56 | #ifdef _WIN32 57 | void* handle; 58 | #else 59 | int64 data[4]; // sizeof(sem_t) 60 | #endif 61 | 62 | Semaphore(const Semaphore&); 63 | Semaphore& operator=(const Semaphore&); 64 | }; 65 | -------------------------------------------------------------------------------- /include/nstd/Signal.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Signal 7 | { 8 | public: 9 | Signal(bool set = false); 10 | ~Signal(); 11 | 12 | void set(); 13 | void reset(); 14 | bool wait(); 15 | bool wait(int64 timeout); 16 | 17 | private: 18 | #ifdef _WIN32 19 | void* handle; 20 | #else 21 | #ifdef _AMD64 22 | int64 cdata[6]; // sizeof(pthread_cond_t) 23 | int64 mdata[5]; // sizeof(pthread_mutex_t) 24 | #else 25 | int64 cdata[6]; // sizeof(pthread_cond_t) 26 | int64 mdata[3]; // sizeof(pthread_mutex_t) 27 | #endif 28 | bool signaled; 29 | #endif 30 | 31 | Signal(const Signal&); 32 | Signal& operator=(const Signal&); 33 | }; 34 | -------------------------------------------------------------------------------- /include/nstd/Socket/Server.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Socket; 7 | 8 | class Server 9 | { 10 | public: 11 | class Client 12 | { 13 | public: 14 | class ICallback 15 | { 16 | public: 17 | virtual void onRead() = 0; 18 | virtual void onWrite() = 0; 19 | virtual void onClosed() = 0; 20 | 21 | protected: 22 | ICallback() {} 23 | ~ICallback() {} 24 | }; 25 | 26 | public: 27 | bool write(const byte *data, usize size, usize *postponed = 0); 28 | bool read(byte *buffer, usize maxSize, usize &size); 29 | void suspend(); 30 | void resume(); 31 | bool isSuspended() const; 32 | usize getSendBufferSize() const; 33 | Socket& getSocket(); 34 | 35 | private: 36 | Client(const Client &); 37 | Client &operator=(const Client &); 38 | Client(); 39 | ~Client(); 40 | }; 41 | 42 | class Listener 43 | { 44 | public: 45 | class ICallback 46 | { 47 | public: 48 | virtual Client::ICallback *onAccepted(Client &client, uint32 ip, uint16 port) = 0; 49 | 50 | protected: 51 | ICallback() {} 52 | ~ICallback() {} 53 | }; 54 | 55 | private: 56 | Listener(const Listener &); 57 | Listener &operator=(const Listener &); 58 | Listener(); 59 | ~Listener(); 60 | }; 61 | 62 | class Establisher 63 | { 64 | public: 65 | class ICallback 66 | { 67 | public: 68 | virtual Client::ICallback *onConnected(Client &client) = 0; 69 | virtual void onAbolished() = 0; 70 | 71 | protected: 72 | ICallback() {} 73 | ~ICallback() {} 74 | }; 75 | 76 | private: 77 | Establisher(const Establisher &); 78 | Establisher &operator=(const Establisher &); 79 | Establisher(); 80 | ~Establisher(); 81 | }; 82 | 83 | class Timer 84 | { 85 | public: 86 | class ICallback 87 | { 88 | public: 89 | virtual void onActivated() = 0; 90 | 91 | protected: 92 | ICallback() {} 93 | ~ICallback() {} 94 | }; 95 | 96 | private: 97 | Timer(const Timer &); 98 | Timer &operator=(const Timer &); 99 | Timer(); 100 | ~Timer(); 101 | }; 102 | 103 | public: 104 | Server(); 105 | ~Server(); 106 | 107 | void setKeepAlive(bool enable = true); 108 | void setNoDelay(bool enable = true); 109 | void setSendBufferSize(int size); 110 | void setReceiveBufferSize(int size); 111 | void setReuseAddress(bool enable); 112 | 113 | Listener *listen(uint32 addr, uint16 port, Listener::ICallback &callback); 114 | Establisher *connect(uint32 addr, uint16 port, Establisher::ICallback &callback); 115 | Establisher *connect(const String &host, uint16 port, Establisher::ICallback &callback); 116 | Timer *time(int64 interval, Timer::ICallback &callback); 117 | Client *pair(Client::ICallback &callback, Socket &socket); 118 | 119 | void remove(Client &client); 120 | void remove(Listener &listener); 121 | void remove(Establisher &establisher); 122 | void remove(Timer &timer); 123 | 124 | void run(); 125 | void interrupt(); 126 | 127 | void clear(); 128 | 129 | private: 130 | Server(const Server &); 131 | Server &operator=(const Server &); 132 | 133 | private: 134 | class Private; 135 | Private *_p; 136 | }; 137 | -------------------------------------------------------------------------------- /include/nstd/Socket/Socket.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Socket 7 | { 8 | public: 9 | enum Address 10 | { 11 | anyAddress = 0, 12 | loopbackAddress = 0x7f000001, 13 | broadcastAddress = 0xffffffff, 14 | }; 15 | 16 | enum Protocol 17 | { 18 | tcpProtocol, 19 | udpProtocol, 20 | }; 21 | 22 | public: 23 | Socket(); 24 | ~Socket(); 25 | 26 | bool open(Protocol protocol = tcpProtocol); 27 | void close(); 28 | bool isOpen() const; 29 | int64 getFileDescriptor() const; 30 | 31 | void swap(Socket& other); 32 | 33 | bool pair(Socket& other); 34 | bool accept(Socket& to, uint32& ip, uint16& port); 35 | bool bind(uint32 ip, uint16 port); 36 | bool listen(); 37 | bool connect(uint32 ip, uint16 port); 38 | 39 | ssize send(const byte* data, usize size); 40 | ssize recv(byte* data, usize maxSize, usize minSize = 0); 41 | 42 | ssize sendTo(const byte* data, usize size, uint32 ip, uint16 port); 43 | ssize recvFrom(byte* data, usize maxSize, uint32& ip, uint16& port); 44 | 45 | bool setKeepAlive(); 46 | bool setReuseAddress(); 47 | bool setNonBlocking(); 48 | bool setNoDelay(); 49 | bool setSendBufferSize(int size); 50 | bool setReceiveBufferSize(int size); 51 | bool setBroadcast(); 52 | 53 | bool joinMulticastGroup(uint32 ip, uint32 interfaceIp = anyAddress); 54 | bool setMulticastLoopback(bool enable); 55 | 56 | int getAndResetErrorStatus(); 57 | 58 | bool getSockName(uint32& ip, uint16& port); 59 | bool getPeerName(uint32& ip, uint16& port); 60 | 61 | bool getSockOpt(int level, int optname, void *optval, usize& optlen); 62 | 63 | static void setLastError(int error); 64 | static int getLastError(); 65 | static String getErrorString(int error = getLastError()); 66 | static uint32 inetAddr(const String& addr, uint16* port = 0); 67 | static String inetNtoA(uint32 ip); 68 | static String getHostName(); 69 | static bool getHostByName(const String& host, uint32& addr); 70 | 71 | public: 72 | class Poll 73 | { 74 | public: 75 | enum Flag 76 | { 77 | readFlag = 0x01, 78 | writeFlag = 0x02, 79 | acceptFlag = 0x04, 80 | connectFlag = 0x08, 81 | }; 82 | 83 | struct Event 84 | { 85 | uint flags; 86 | Socket* socket; 87 | }; 88 | 89 | public: 90 | Poll(); 91 | ~Poll(); 92 | 93 | void set(Socket& socket, uint flags); 94 | void remove(Socket& socket); 95 | 96 | void clear(); 97 | 98 | bool poll(Event& event, int64 timeout); 99 | bool interrupt(); 100 | 101 | private: 102 | Poll(const Poll&); 103 | Poll& operator=(const Poll&); 104 | 105 | private: 106 | class Private; 107 | Private* p; 108 | }; 109 | 110 | private: 111 | #ifdef _WIN32 112 | #ifdef _AMD64 113 | uint64 s; 114 | #else 115 | uint s; 116 | #endif 117 | #else 118 | int s; 119 | #endif 120 | 121 | private: 122 | Socket(const Socket&); 123 | Socket& operator=(const Socket&); 124 | 125 | private: 126 | class Private; 127 | }; 128 | -------------------------------------------------------------------------------- /include/nstd/System.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class System 7 | { 8 | public: 9 | static uint getProcessorCount(); 10 | }; 11 | -------------------------------------------------------------------------------- /include/nstd/Thread.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | class Thread 8 | { 9 | public: 10 | Thread(); 11 | ~Thread(); 12 | 13 | bool start(uint (*proc)(void*), void* param); 14 | template bool start(X& obj, uint (X::*ptr)()) 15 | { 16 | typename Call::Member::Func0 func(obj, ptr); 17 | this->func = *(Call::Member::Func0*)&func; 18 | return start((uint (*)(void*))&proc< typename Call::Member::Func0 >, &this->func); 19 | } 20 | 21 | uint join(); 22 | 23 | static void yield(); 24 | static void sleep(int64 milliseconds); 25 | 26 | /** 27 | * Get the id of the calling thread. 28 | * 29 | * @return The thread id. 30 | */ 31 | static uint32 getCurrentThreadId(); 32 | 33 | private: 34 | template static uint proc(T* t); 35 | 36 | void* thread; 37 | Call::Member::Func0 func; 38 | 39 | Thread(const Thread&); 40 | Thread& operator=(const Thread&); 41 | }; 42 | 43 | template uint Thread::proc(T* t) 44 | { 45 | return t->call(); 46 | } 47 | -------------------------------------------------------------------------------- /include/nstd/Time.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | class Time 8 | { 9 | public: 10 | int sec; /**< 0 - 59 */ 11 | int min; /**< 0 - 59 */ 12 | int hour; /**< 0 - 23 */ 13 | int day; /**< 1 - 31 */ 14 | int month; /**< 1 - 12 */ 15 | int year; 16 | int wday; /**< The day of week (0 - 6, 0 = Sunday). */ 17 | int yday; /**< The day of year (0 - 365, 0 = First day of the year). */ 18 | bool dst; 19 | bool utc; 20 | 21 | explicit Time(bool utc = false); 22 | Time(int64 time, bool utc = false); 23 | Time(const Time& other); 24 | 25 | Time& toUtc(); 26 | Time& toLocal(); 27 | 28 | String toString(const char* format); 29 | 30 | int64 toTimestamp(); 31 | 32 | bool operator==(const Time& other) const; 33 | bool operator!=(const Time& other) const; 34 | 35 | /** 36 | * Retrieve local system time. The function returns the local system time in milliseconds since 1 January 1970 (Unix time with millisesond precision). 37 | * @return The current local system time (in milliseconds). 38 | */ 39 | static int64 time(); 40 | 41 | /** 42 | * Retrieve ticks (in milliseconds) that have passed since the system was started. 43 | * @return The ticks (in milliseconds) that have currently passed since the system was started. 44 | */ 45 | static int64 ticks(); 46 | 47 | /** 48 | * Retrieve a high resolution time stamp. 49 | * @return The high resolution time stamp (in microseconds). 50 | */ 51 | static int64 microTicks(); 52 | 53 | static String toString(int64 time, const char* format, bool utc = false); 54 | 55 | private: 56 | class Private; 57 | }; 58 | -------------------------------------------------------------------------------- /include/nstd/Unicode.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class Unicode 7 | { 8 | public: 9 | static String toString(uint32 ch) 10 | { 11 | #ifdef _UNICODE 12 | String result(2); 13 | #else 14 | String result(4); 15 | #endif 16 | append(ch, result); 17 | return result; 18 | } 19 | 20 | static String toString(const uint32* data, usize size) 21 | { 22 | String result(size + 200); 23 | append(data, size, result); 24 | return result; 25 | } 26 | 27 | static bool append(uint32 ch, String& str) 28 | { 29 | #ifdef _UNICODE 30 | if((ch & ~(0x10000UL - 1)) == 0) // ch < 0x10000 31 | { 32 | if((ch & 0xF800ULL) != 0xD800ULL) // ch < 0xD800 || ch > 0xDFFF 33 | { 34 | str.append((tchar)ch); 35 | return true; 36 | } 37 | return false; 38 | } 39 | if(ch < 0x110000UL) 40 | { 41 | ch -= 0x10000UL; 42 | str.append((tchar)((ch >> 10) | 0xD800UL)); 43 | str.append((ch & 0x3ffULL) | 0xDC00UL); 44 | return true; 45 | } 46 | #else 47 | if((ch & ~(0x80UL - 1)) == 0) // ch < 0x80 48 | { 49 | str.append((char)ch); 50 | return true; 51 | } 52 | if((ch & ~(0x800UL - 1)) == 0) // ch < 0x800 53 | { 54 | str.append((ch >> 6) | 0xC0); 55 | str.append((ch & 0x3F) | 0x80); 56 | return true; 57 | } 58 | if((ch & ~(0x10000UL - 1)) == 0) // ch < 0x10000 59 | { 60 | str.append((ch >> 12) | 0xE0); 61 | str.append(((ch >> 6) & 0x3F) | 0x80); 62 | str.append((ch & 0x3F) | 0x80); 63 | return true; 64 | } 65 | if(ch < 0x110000UL) 66 | { 67 | str.append((ch >> 18) | 0xF0); 68 | str.append(((ch >> 12) & 0x3F) | 0x80); 69 | str.append(((ch >> 6) & 0x3F) | 0x80); 70 | str.append((ch & 0x3F) | 0x80); 71 | return true; 72 | } 73 | #endif 74 | return false; 75 | } 76 | 77 | static bool append(const uint32* data, usize size, String& str) 78 | { 79 | bool result = true; 80 | for(const uint32* end = data + size; data < end; ++data) 81 | result &= append(*data, str); 82 | return result; 83 | } 84 | 85 | static usize length(char ch) 86 | { 87 | if((ch & 0x80) == 0) 88 | return 1; 89 | if((ch & 0xe0) == 0xc0) 90 | return 2; 91 | if((ch & 0xf0) == 0xe0) 92 | return 3; 93 | if((ch & 0xf8) == 0xf0) 94 | return 4; 95 | return 0; 96 | } 97 | 98 | static uint32 fromString(const char* ch, usize len) 99 | { 100 | if(len == 0) 101 | return 0; 102 | if((*(const uchar*)ch & 0x80) == 0) // ch < 0x80 103 | return *(const uchar*)ch; 104 | usize reqLen = length(*ch); 105 | if(len < reqLen) 106 | return 0; 107 | static const uint32 utf8Offsets[] = {0UL, 0UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL}; 108 | uint32 result = 0; 109 | switch(reqLen) 110 | { 111 | case 4: result = (uint32)*(const uchar*)ch++ << 6; 112 | case 3: result += (uint32)*(const uchar*)ch++; result <<= 6; 113 | case 2: result += (uint32)*(const uchar*)ch++; result <<= 6; 114 | default: result += *(const uchar*)ch; 115 | } 116 | result -= utf8Offsets[reqLen]; 117 | return result; 118 | } 119 | 120 | static uint32 fromString(const String& str) {return fromString(str, str.length());} 121 | 122 | static bool isValid(const char* ch, usize len) 123 | { 124 | for(const char* end = ch + len; ch < end;) 125 | { 126 | usize minLen = length(*ch); 127 | if(len < minLen) 128 | return false; 129 | switch(minLen) 130 | { 131 | case 4: 132 | if(((((const uchar*)ch)[1] | ((uint32)((const uchar*)ch)[2] << 8) | ((uint32)((const uchar*)ch)[3] << 16)) & 0xc0c0c0UL) != 0x808080UL) 133 | return false; 134 | break; 135 | case 3: 136 | if(((((const uchar*)ch)[1] | ((uint32)((const uchar*)ch)[2] << 8)) & 0xc0c0UL) != 0x8080UL) 137 | return false; 138 | break; 139 | case 2: 140 | if((ch[1] & 0xc0) != 0x80) 141 | return false; 142 | break; 143 | case 1: 144 | break; 145 | default: 146 | return false; 147 | } 148 | ch += minLen; 149 | len -= minLen; 150 | } 151 | return true; 152 | } 153 | 154 | static bool isValid(const String& str) {return isValid(str, str.length());} 155 | }; 156 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | find_package(Threads) 3 | 4 | set(sources 5 | Callback.cpp 6 | Console.cpp 7 | Debug.cpp 8 | Directory.cpp 9 | Error.cpp 10 | File.cpp 11 | Future.cpp 12 | Library.cpp 13 | Log.cpp 14 | Math.cpp 15 | Memory.cpp 16 | Monitor.cpp 17 | Mutex.cpp 18 | Process.cpp 19 | Semaphore.cpp 20 | Signal.cpp 21 | String.cpp 22 | System.cpp 23 | Thread.cpp 24 | Time.cpp 25 | Variant.cpp 26 | ../include/nstd/Array.hpp 27 | ../include/nstd/Atomic.hpp 28 | ../include/nstd/Base.hpp 29 | ../include/nstd/Buffer.hpp 30 | ../include/nstd/Call.hpp 31 | ../include/nstd/Callback.hpp 32 | ../include/nstd/Console.hpp 33 | ../include/nstd/Debug.hpp 34 | ../include/nstd/Directory.hpp 35 | ../include/nstd/Error.hpp 36 | ../include/nstd/File.hpp 37 | ../include/nstd/Future.hpp 38 | ../include/nstd/HashMap.hpp 39 | ../include/nstd/HashSet.hpp 40 | ../include/nstd/Library.hpp 41 | ../include/nstd/List.hpp 42 | ../include/nstd/Log.hpp 43 | ../include/nstd/Map.hpp 44 | ../include/nstd/Math.hpp 45 | ../include/nstd/Memory.hpp 46 | ../include/nstd/Monitor.hpp 47 | ../include/nstd/MultiMap.hpp 48 | ../include/nstd/Mutex.hpp 49 | ../include/nstd/PoolList.hpp 50 | ../include/nstd/PoolMap.hpp 51 | ../include/nstd/Process.hpp 52 | ../include/nstd/RefCount.hpp 53 | ../include/nstd/Semaphore.hpp 54 | ../include/nstd/Signal.hpp 55 | ../include/nstd/String.hpp 56 | ../include/nstd/System.hpp 57 | ../include/nstd/Thread.hpp 58 | ../include/nstd/Time.hpp 59 | ../include/nstd/Unicode.hpp 60 | ../include/nstd/Variant.hpp 61 | ) 62 | 63 | add_library(nstd STATIC 64 | ${sources} 65 | ) 66 | add_library(libnstd::Core ALIAS nstd) 67 | 68 | target_include_directories(nstd PUBLIC 69 | ../include 70 | ) 71 | target_link_libraries(nstd PUBLIC 72 | Threads::Threads 73 | ) 74 | if(MSVC) 75 | target_compile_definitions(nstd PRIVATE 76 | _CRT_SECURE_NO_WARNINGS 77 | ) 78 | endif() 79 | if(WIN32) 80 | target_compile_definitions(nstd PRIVATE 81 | _WIN32_WINNT=0x0600 82 | ) 83 | else() 84 | target_link_libraries(nstd PUBLIC 85 | rt 86 | ) 87 | endif() 88 | 89 | set_property(TARGET nstd PROPERTY FOLDER "src") 90 | source_group("" FILES ${sources}) 91 | 92 | add_subdirectory(Crypto) 93 | add_subdirectory(Document) 94 | add_subdirectory(Socket) 95 | -------------------------------------------------------------------------------- /src/Callback.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | Callback::Emitter::~Emitter() 5 | { 6 | for(Map::Iterator i = signalData.begin(); i != signalData.end(); ++i) 7 | { 8 | const MemberFuncPtr& signal = i.key(); 9 | SignalData& data = *i; 10 | if(data.activation) 11 | data.activation->invalidated = true; 12 | for(List::Iterator i = data.slots.begin(), end = data.slots.end(); i != end; ++i) 13 | { 14 | Slot& slotData = *i; 15 | if(slotData.state == Slot::disconnected) 16 | continue; 17 | Map >::Iterator it = slotData.receiver->slotData.find(this); 18 | if(it != slotData.receiver->slotData.end()) 19 | { 20 | List& signals = *it; 21 | for(List::Iterator i = signals.begin(); i != signals.end(); ++i) 22 | if(i->signal == signal && i->slot == slotData.slot) 23 | { 24 | signals.remove(i); 25 | break; 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | Callback::Emitter::SignalActivation::SignalActivation(Callback::Emitter* emitter, const MemberFuncPtr& signal) : invalidated(false) 33 | { 34 | Map::Iterator it = emitter->signalData.find(signal); 35 | if(it == emitter->signalData.end()) 36 | { 37 | data = 0; 38 | next = 0; 39 | } 40 | else 41 | { 42 | data = &*it; 43 | next = data->activation; 44 | data->activation = this; 45 | begin = data->slots.begin(); 46 | end = data->slots.end(); 47 | } 48 | } 49 | 50 | Callback::Emitter::SignalActivation::~SignalActivation() 51 | { 52 | if(!invalidated) 53 | { 54 | if(data && !(data->activation = next) && data->dirty) 55 | { 56 | for(List::Iterator i = data->slots.begin(), end = data->slots.end(); i != end;) 57 | switch(i->state) 58 | { 59 | case Slot::disconnected: 60 | i = data->slots.remove(i); 61 | break; 62 | case Slot::connecting: 63 | i->state = Slot::connected; 64 | default: 65 | ++i; 66 | } 67 | data->dirty = false; 68 | } 69 | } 70 | else if(next) 71 | next->invalidated = true; 72 | } 73 | 74 | 75 | Callback::Listener::~Listener() 76 | { 77 | for(Map >::Iterator i = slotData.begin(); i != slotData.end(); ++i) 78 | { 79 | Callback::Emitter* emitter = i.key(); 80 | const List& signals = *i; 81 | for(List::Iterator i = signals.begin(); i != signals.end(); ++i) 82 | { 83 | Signal& signalData1 = *i; 84 | Map::Iterator it = emitter->signalData.find(signalData1.signal); 85 | if(it != emitter->signalData.end()) 86 | { 87 | Callback::Emitter::SignalData& signalData = *it; 88 | for(List::Iterator i = signalData.slots.begin(); i != signalData.slots.end(); ++i) 89 | if(i->receiver == this && i->slot == signalData1.slot) 90 | { 91 | if(signalData.activation) 92 | { 93 | i->state = Callback::Emitter::Slot::disconnected; 94 | signalData.dirty = true; 95 | } 96 | else 97 | signalData.slots.remove(i); 98 | break; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | void Callback::connect(Callback::Emitter* emitter, const MemberFuncPtr& signal, Callback::Listener* receiver, void* object, const MemberFuncPtr& slot) 106 | { 107 | Map::Iterator it = emitter->signalData.find(signal); 108 | Callback::Emitter::SignalData& signalData = it == emitter->signalData.end() ? *emitter->signalData.insert(signal, Callback::Emitter::SignalData()) : *it; 109 | Callback::Emitter::Slot& slotData = signalData.slots.append(Callback::Emitter::Slot()); 110 | if(signalData.activation) 111 | { 112 | slotData.state = Callback::Emitter::Slot::connecting; 113 | signalData.dirty = true; 114 | } 115 | else 116 | slotData.state = Callback::Emitter::Slot::connected; 117 | slotData.receiver = receiver; 118 | slotData.object = object; 119 | slotData.slot = slot; 120 | 121 | Map >::Iterator it2 = receiver->slotData.find(emitter); 122 | Callback::Listener::Signal& signalData2 = (it2 == receiver->slotData.end() ? receiver->slotData.insert(emitter, List()) : it2)->append(Callback::Listener::Signal()); 123 | signalData2.signal = signal; 124 | signalData2.slot = slot; 125 | } 126 | 127 | void Callback::disconnect(Callback::Emitter* emitter, const MemberFuncPtr& signal, Callback::Listener* receiver, const MemberFuncPtr& slot) 128 | { 129 | Map::Iterator it = emitter->signalData.find(signal); 130 | if(it == emitter->signalData.end()) 131 | return; 132 | 133 | Callback::Emitter::SignalData& signalData = *it; 134 | for(List::Iterator i = signalData.slots.begin(); i != signalData.slots.end(); ++i) 135 | if(i->receiver == receiver && i->slot == slot) 136 | { 137 | if(signalData.activation) 138 | { 139 | i->state = Callback::Emitter::Slot::disconnected; 140 | signalData.dirty = true; 141 | } 142 | else 143 | signalData.slots.remove(i); 144 | break; 145 | } 146 | 147 | Map >::Iterator it2 = receiver->slotData.find(emitter); 148 | List& signals = *it2; 149 | for(List::Iterator i = signals.begin(); i != signals.end(); ++i) 150 | if(i->signal == signal && i->slot == slot) 151 | { 152 | signals.remove(i); 153 | break; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/Crypto/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(sources 3 | Sha256.cpp 4 | ../../include/nstd/Crypto/Sha256.hpp 5 | ) 6 | 7 | add_library(nstdCrypto STATIC 8 | ${sources} 9 | ) 10 | add_library(libnstd::Crypto ALIAS nstdCrypto) 11 | 12 | target_link_libraries(nstdCrypto PUBLIC 13 | nstd 14 | ) 15 | 16 | source_group("" FILES ${sources}) 17 | set_property(TARGET nstdCrypto PROPERTY FOLDER "src") 18 | -------------------------------------------------------------------------------- /src/Crypto/Sha256.cpp: -------------------------------------------------------------------------------- 1 | /* Crypto/Sha256.c -- SHA-256 Hash 2 | 2013-11-27 : Unknown : Public domain 3 | 2010-06-11 : Igor Pavlov : Public domain 4 | This code is based on public domain code from Wei Dai's Crypto++ library. */ 5 | 6 | #ifdef _MSC_VER 7 | 8 | #include 9 | #define rotlFixed(x, n) _rotl((x), (n)) 10 | #define rotrFixed(x, n) _rotr((x), (n)) 11 | 12 | #else 13 | 14 | #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 15 | #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) 16 | 17 | #endif 18 | 19 | #define SHA256_DIGEST_SIZE 32 20 | 21 | typedef unsigned int UInt32; 22 | typedef unsigned char Byte; 23 | typedef unsigned long long UInt64; 24 | #define CSha256 Sha256 25 | 26 | #include 27 | 28 | /* define it for speed optimization */ 29 | /* #define _SHA256_UNROLL */ 30 | /* #define _SHA256_UNROLL2 */ 31 | 32 | #define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) 33 | #define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) 34 | #define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) 35 | #define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) 36 | 37 | #define blk0(i) (W[i] = data[i]) 38 | #define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) 39 | 40 | #define Ch(x,y,z) (z^(x&(y^z))) 41 | #define Maj(x,y,z) ((x&y)|(z&(x|y))) 42 | 43 | #define a(i) T[(0-(i))&7] 44 | #define b(i) T[(1-(i))&7] 45 | #define c(i) T[(2-(i))&7] 46 | #define d(i) T[(3-(i))&7] 47 | #define e(i) T[(4-(i))&7] 48 | #define f(i) T[(5-(i))&7] 49 | #define g(i) T[(6-(i))&7] 50 | #define h(i) T[(7-(i))&7] 51 | 52 | 53 | #ifdef _SHA256_UNROLL2 54 | 55 | #define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ 56 | d += h; h += S0(a) + Maj(a, b, c) 57 | 58 | #define RX_8(i) \ 59 | R(a,b,c,d,e,f,g,h, i); \ 60 | R(h,a,b,c,d,e,f,g, i+1); \ 61 | R(g,h,a,b,c,d,e,f, i+2); \ 62 | R(f,g,h,a,b,c,d,e, i+3); \ 63 | R(e,f,g,h,a,b,c,d, i+4); \ 64 | R(d,e,f,g,h,a,b,c, i+5); \ 65 | R(c,d,e,f,g,h,a,b, i+6); \ 66 | R(b,c,d,e,f,g,h,a, i+7) 67 | 68 | #else 69 | 70 | #define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\ 71 | d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) 72 | 73 | #ifdef _SHA256_UNROLL 74 | 75 | #define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); 76 | 77 | #endif 78 | 79 | #endif 80 | 81 | 82 | class Sha256::Private 83 | { 84 | public: 85 | static const UInt32 K[64]; 86 | 87 | static void Transform(UInt32 *state, const UInt32 *data) 88 | { 89 | UInt32 W[16]; 90 | unsigned j; 91 | #ifdef _SHA256_UNROLL2 92 | UInt32 a,b,c,d,e,f,g,h; 93 | a = state[0]; 94 | b = state[1]; 95 | c = state[2]; 96 | d = state[3]; 97 | e = state[4]; 98 | f = state[5]; 99 | g = state[6]; 100 | h = state[7]; 101 | #else 102 | UInt32 T[8]; 103 | for (j = 0; j < 8; j++) 104 | T[j] = state[j]; 105 | #endif 106 | 107 | for (j = 0; j < 64; j += 16) 108 | { 109 | #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) 110 | RX_8(0); RX_8(8); 111 | #else 112 | unsigned i; 113 | for (i = 0; i < 16; i++) { R(i); } 114 | #endif 115 | } 116 | 117 | #ifdef _SHA256_UNROLL2 118 | state[0] += a; 119 | state[1] += b; 120 | state[2] += c; 121 | state[3] += d; 122 | state[4] += e; 123 | state[5] += f; 124 | state[6] += g; 125 | state[7] += h; 126 | #else 127 | for (j = 0; j < 8; j++) 128 | state[j] += T[j]; 129 | #endif 130 | 131 | /* Wipe variables */ 132 | /* memset(W, 0, sizeof(W)); */ 133 | /* memset(T, 0, sizeof(T)); */ 134 | } 135 | 136 | 137 | static void WriteByteBlock(Sha256* p) 138 | { 139 | UInt32 data32[16]; 140 | unsigned i; 141 | for (i = 0; i < 16; i++) 142 | data32[i] = 143 | ((UInt32)(p->buffer[i * 4 ]) << 24) + 144 | ((UInt32)(p->buffer[i * 4 + 1]) << 16) + 145 | ((UInt32)(p->buffer[i * 4 + 2]) << 8) + 146 | ((UInt32)(p->buffer[i * 4 + 3])); 147 | Transform(p->state, data32); 148 | } 149 | }; 150 | 151 | const UInt32 Sha256::Private::K[64] = { 152 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 153 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 154 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 155 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 156 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 157 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 158 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 159 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 160 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 161 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 162 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 163 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 164 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 165 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 166 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 167 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 168 | }; 169 | 170 | void Sha256::reset() 171 | { 172 | CSha256 *p = this; 173 | p->state[0] = 0x6a09e667; 174 | p->state[1] = 0xbb67ae85; 175 | p->state[2] = 0x3c6ef372; 176 | p->state[3] = 0xa54ff53a; 177 | p->state[4] = 0x510e527f; 178 | p->state[5] = 0x9b05688c; 179 | p->state[6] = 0x1f83d9ab; 180 | p->state[7] = 0x5be0cd19; 181 | p->count = 0; 182 | } 183 | 184 | void Sha256::update(const Byte *data, usize size) 185 | { 186 | CSha256 *p = this; 187 | UInt32 curBufferPos = (UInt32)p->count & 0x3F; 188 | while (size > 0) 189 | { 190 | p->buffer[curBufferPos++] = *data++; 191 | p->count++; 192 | size--; 193 | if (curBufferPos == 64) 194 | { 195 | curBufferPos = 0; 196 | Private::WriteByteBlock(p); 197 | } 198 | } 199 | } 200 | 201 | void Sha256::finalize(byte (&digestBuf)[digestSize]) 202 | { 203 | CSha256 *p = this; 204 | UInt64 lenInBits = (p->count << 3); 205 | UInt32 curBufferPos = (UInt32)p->count & 0x3F; 206 | unsigned i; 207 | p->buffer[curBufferPos++] = 0x80; 208 | while (curBufferPos != (64 - 8)) 209 | { 210 | curBufferPos &= 0x3F; 211 | if (curBufferPos == 0) 212 | Private::WriteByteBlock(p); 213 | p->buffer[curBufferPos++] = 0; 214 | } 215 | for (i = 0; i < 8; i++) 216 | { 217 | p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56); 218 | lenInBits <<= 8; 219 | } 220 | Private::WriteByteBlock(p); 221 | 222 | byte* digest = digestBuf; 223 | for (i = 0; i < 8; i++) 224 | { 225 | *digest++ = (Byte)(p->state[i] >> 24); 226 | *digest++ = (Byte)(p->state[i] >> 16); 227 | *digest++ = (Byte)(p->state[i] >> 8); 228 | *digest++ = (Byte)(p->state[i]); 229 | } 230 | reset(); 231 | } 232 | -------------------------------------------------------------------------------- /src/Debug.cpp: -------------------------------------------------------------------------------- 1 | 2 | #if defined(_WIN32) 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #ifndef NDEBUG 6 | #include 7 | #endif 8 | #ifdef UNICODE 9 | #include 10 | #endif 11 | #else 12 | #ifndef NDEBUG 13 | #include 14 | #include 15 | #include 16 | #endif 17 | #endif 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | int Debug::print(const char* str) 26 | { 27 | #ifdef _MSC_VER 28 | OutputDebugString(str); 29 | return (int)strlen(str); 30 | #else 31 | return fputs(str, stderr); 32 | #endif 33 | } 34 | 35 | int Debug::printf(const char* format, ...) 36 | { 37 | #ifdef _MSC_VER 38 | va_list ap; 39 | va_start(ap, format); 40 | { 41 | char buffer[4096]; 42 | int result = vsnprintf(buffer, sizeof(buffer), format, ap); 43 | if(result >= 0 && result < (int)(sizeof(buffer))) 44 | { 45 | OutputDebugString(buffer); 46 | va_end(ap); 47 | return result; 48 | } 49 | } 50 | 51 | // buffer was too small 52 | { 53 | int result = _vscprintf(format, ap); 54 | usize maxCount = result + 1; 55 | char* buffer = (char*)new char[maxCount]; 56 | result = vsnprintf(buffer, maxCount, format, ap); 57 | va_end(ap); 58 | OutputDebugString(buffer); 59 | delete[] (char*)buffer; 60 | return result; 61 | } 62 | #else 63 | va_list ap; 64 | va_start(ap, format); 65 | int result = vfprintf(stderr, format, ap); 66 | va_end(ap); 67 | return result; 68 | #endif 69 | } 70 | 71 | #ifndef NDEBUG 72 | bool Debug::getSourceLine(void* addr, String& file, int& line) 73 | { 74 | #ifdef _WIN32 75 | typedef BOOL (WINAPI *PSymInitialize)(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess); 76 | typedef BOOL (WINAPI *PSymGetLineFromAddr64)(HANDLE hProcess, DWORD64 qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64); 77 | static PSymInitialize pSymInitialize = 0; 78 | static PSymGetLineFromAddr64 pSymGetLineFromAddr64 = 0; 79 | static bool initialized = false; 80 | HANDLE hProcess = GetCurrentProcess(); 81 | if(!initialized) 82 | { 83 | initialized = true; 84 | HMODULE hModule = LoadLibrary("Dbghelp.dll"); 85 | if(!hModule) 86 | return false; 87 | pSymInitialize = (PSymInitialize)GetProcAddress(hModule, "SymInitialize"); 88 | pSymGetLineFromAddr64 = (PSymGetLineFromAddr64)GetProcAddress(hModule, "SymGetLineFromAddr64"); 89 | if(!pSymInitialize || !pSymGetLineFromAddr64) 90 | return false; 91 | if(!pSymInitialize(hProcess, NULL, TRUE)) 92 | { 93 | pSymGetLineFromAddr64 = 0; 94 | return false; 95 | } 96 | } 97 | if(!pSymGetLineFromAddr64) 98 | return false; 99 | IMAGEHLP_LINE64 ihLine; 100 | ihLine.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 101 | DWORD displacement; 102 | if(!pSymGetLineFromAddr64(hProcess, (DWORD64)addr, &displacement, &ihLine)) 103 | return false; 104 | #ifdef UNICODE 105 | static wchar_t fileName[MAX_PATH]; 106 | size_t len = mbstowcs(fileName, ihLine.FileName, strlen(ihLine.FileName)); 107 | if(len == -1) 108 | return false; 109 | file = String(fileName, len); 110 | #else 111 | file = String::fromCString(ihLine.FileName); 112 | #endif 113 | line = ihLine.LineNumber; 114 | return true; 115 | #else 116 | void* addrs[1]; 117 | addrs[0] = addr; 118 | char** addrStrs = backtrace_symbols(addrs, 1); 119 | if(!addrStrs) 120 | return false; 121 | if(!*addrStrs) 122 | { 123 | free(addrStrs); 124 | return false; 125 | } 126 | String addrStr = String::fromCString(*addrStrs); 127 | free(addrStrs); 128 | const char* addrStart = addrStr.findLast('['); 129 | const char* addrEnd = addrStr.findLast(']'); 130 | if(!addrStart ||!addrEnd || addrEnd < addrStart) 131 | return false; 132 | ++addrStart; 133 | void* relAddr; 134 | if(addrStr.substr(addrStart - (const char*)addrStr, addrEnd - addrStart).scanf("%p", &relAddr) != 1) 135 | return false; 136 | const char* binaryEnd = addrStr.findLast('('); 137 | if(!binaryEnd) 138 | return false; 139 | String bin = addrStr.substr(0, binaryEnd - (const char*)addrStr); 140 | String cmd = String::fromPrintf("addr2line -e \"%s\" %p", (const char*)bin, relAddr); 141 | Process process; 142 | if(!process.open(cmd)) 143 | return false; 144 | String buf; 145 | buf.reserve(1024 * 32); 146 | ssize i = process.read((char*)buf, 1024 * 32); 147 | if(i < 0) 148 | return false; 149 | buf.resize(i); 150 | const char* fileEnd = buf.findLast(':'); 151 | if(!fileEnd) 152 | return false; 153 | file = buf.substr(0, fileEnd - (const char*)buf); 154 | if(buf.substr(fileEnd - (const char*)buf + 1).scanf("%d", &line) != 1) 155 | return false; 156 | return true; 157 | #endif 158 | } 159 | #endif 160 | -------------------------------------------------------------------------------- /src/Document/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(sources 3 | Json.cpp 4 | Xml.cpp 5 | ../../include/nstd/Document/Json.hpp 6 | ../../include/nstd/Document/Xml.hpp 7 | ) 8 | 9 | add_library(nstdDocument STATIC 10 | ${sources} 11 | ) 12 | add_library(libnstd::Document ALIAS nstdDocument) 13 | 14 | target_link_libraries(nstdDocument PUBLIC 15 | nstd 16 | ) 17 | 18 | source_group("" FILES ${sources}) 19 | set_property(TARGET nstdDocument PROPERTY FOLDER "src") 20 | -------------------------------------------------------------------------------- /src/Error.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #else 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | class Error::Private 19 | { 20 | public: 21 | class Str 22 | { 23 | public: 24 | Str() : _ptr(0), _len(0) {} 25 | Str(const String& other) 26 | { 27 | _len = other.length(); 28 | _ptr = new char[_len + 1]; 29 | memcpy(_ptr, (const char*)other, _len + 1); 30 | } 31 | Str(const Str& other) 32 | : _len(other._len) 33 | { 34 | _ptr = new char[_len + 1]; 35 | memcpy(_ptr, other._ptr, _len + 1); 36 | } 37 | Str& operator=(const Str& other) 38 | { 39 | delete []_ptr; 40 | _len = other._len; 41 | _ptr = new char[_len + 1]; 42 | memcpy(_ptr, other._ptr, _len + 1); 43 | return *this; 44 | 45 | } 46 | ~Str() { delete []_ptr;} 47 | operator String() const { return _ptr ? String(_ptr, _len) : String(); } 48 | 49 | private: 50 | char* _ptr; 51 | usize _len; 52 | }; 53 | 54 | public: 55 | #ifdef _WIN32 56 | static CRITICAL_SECTION cs; 57 | #else 58 | static pthread_mutex_t mutex; 59 | #endif 60 | static Map userErrorStrings; 61 | static class Framework 62 | { 63 | public: 64 | Framework() 65 | { 66 | #ifdef _WIN32 67 | InitializeCriticalSection(&cs); 68 | #else 69 | pthread_mutexattr_t attr; // TODO: use global var for this? 70 | pthread_mutexattr_init(&attr); 71 | VERIFY(pthread_mutex_init(&mutex, &attr) == 0); 72 | #endif 73 | } 74 | ~Framework() 75 | { 76 | #ifdef _WIN32 77 | DeleteCriticalSection(&cs); 78 | #else 79 | VERIFY(pthread_mutex_destroy(&mutex) == 0); 80 | #endif 81 | } 82 | } framework; 83 | }; 84 | 85 | #ifdef _WIN32 86 | CRITICAL_SECTION Error::Private::cs; 87 | #else 88 | pthread_mutex_t Error::Private::mutex; 89 | #endif 90 | Map Error::Private::userErrorStrings; 91 | Error::Private::Framework Error::Private::framework; 92 | 93 | void Error::setLastError(uint error) 94 | { 95 | #ifdef _WIN32 96 | SetLastError((DWORD)error); 97 | #else 98 | errno = (int)error; 99 | #endif 100 | } 101 | 102 | uint Error::getLastError() 103 | { 104 | #ifdef _WIN32 105 | return (uint)GetLastError(); 106 | #else 107 | return errno; 108 | #endif 109 | } 110 | 111 | String Error::getErrorString(uint error) 112 | { 113 | if(error == 0x10000) 114 | { 115 | String errorStr; 116 | #ifdef _WIN32 117 | EnterCriticalSection(&Private::cs); 118 | #else 119 | VERIFY(pthread_mutex_lock(&Private::mutex) == 0); 120 | #endif 121 | 122 | #ifdef _WIN32 123 | uint32 threadId = (uint32)GetCurrentThreadId(); 124 | #else 125 | uint32 threadId = (uint32)syscall(__NR_gettid); 126 | #endif 127 | Map::Iterator it = Private::userErrorStrings.find(threadId); 128 | if(it != Private::userErrorStrings.end()) 129 | errorStr = *it; 130 | #ifdef _WIN32 131 | LeaveCriticalSection(&Private::cs); 132 | #else 133 | VERIFY(pthread_mutex_unlock(&Private::mutex) == 0); 134 | #endif 135 | return errorStr; 136 | } 137 | 138 | #ifdef _WIN32 139 | TCHAR errorMessage[256]; 140 | DWORD len = FormatMessage( 141 | FORMAT_MESSAGE_FROM_SYSTEM | 142 | FORMAT_MESSAGE_IGNORE_INSERTS, 143 | NULL, 144 | error, 145 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 146 | (LPTSTR) errorMessage, 147 | 256, NULL ); 148 | ASSERT(len >= 0 && len <= 256); 149 | while(len > 0 && String::isSpace(errorMessage[len - 1])) 150 | --len; 151 | errorMessage[len] = '\0'; 152 | return String(errorMessage, len); 153 | #else 154 | const char* errorMessage = strerror(error); 155 | return String(errorMessage, String::length(errorMessage)); 156 | #endif 157 | } 158 | 159 | void Error::setErrorString(const String& error) 160 | { 161 | #ifdef _WIN32 162 | EnterCriticalSection(&Private::cs); 163 | #else 164 | VERIFY(pthread_mutex_lock(&Private::mutex) == 0); 165 | #endif 166 | 167 | #ifdef _WIN32 168 | uint32 threadId = (uint32)GetCurrentThreadId(); 169 | #else 170 | uint32 threadId = (uint32)syscall(__NR_gettid); 171 | #endif 172 | 173 | Error::Private::Str* threadErrorMsg = 0; 174 | for(Map::Iterator i = Private::userErrorStrings.begin(), end = Private::userErrorStrings.end(), next; i != end; i = next) 175 | { 176 | next = i; 177 | ++next; 178 | 179 | #ifdef _WIN32 180 | HANDLE handle = OpenThread(DELETE, FALSE, i.key()); 181 | if(handle == NULL) 182 | { 183 | Private::userErrorStrings.remove(i); 184 | continue; 185 | } 186 | else 187 | CloseHandle(handle); 188 | #else 189 | cpu_set_t cpuset; 190 | if(sched_getaffinity((pid_t)i.key(), sizeof(cpu_set_t), &cpuset) != 0) 191 | { 192 | Private::userErrorStrings.remove(i); 193 | continue; 194 | } 195 | #endif 196 | if(i.key() == threadId) 197 | threadErrorMsg = &*i; 198 | } 199 | if(threadErrorMsg) 200 | *threadErrorMsg = error; 201 | else 202 | Private::userErrorStrings.insert(threadId, error); 203 | setLastError(0x10000); 204 | #ifdef _WIN32 205 | LeaveCriticalSection(&Private::cs); 206 | #else 207 | VERIFY(pthread_mutex_unlock(&Private::mutex) == 0); 208 | #endif 209 | } 210 | -------------------------------------------------------------------------------- /src/Library.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #ifdef _UNICODE 6 | #include 7 | #endif 8 | #else 9 | #include 10 | #endif 11 | 12 | #include 13 | #include 14 | #ifndef _WIN32 15 | #include 16 | #endif 17 | 18 | Library::Library() : library(0) {} 19 | 20 | Library::~Library() 21 | { 22 | if(library) 23 | { 24 | #ifdef _WIN32 25 | VERIFY(FreeLibrary((HMODULE)library)); 26 | #else 27 | VERIFY(dlclose(library) == 0); 28 | #endif 29 | } 30 | } 31 | 32 | bool Library::load(const String& name) 33 | { 34 | #ifdef _WIN32 35 | if(library) 36 | return false; 37 | library = LoadLibrary((const char*)name); 38 | return library != 0; 39 | #else 40 | if(library) 41 | return false; 42 | library = dlopen((const char*)name, RTLD_NOW | RTLD_GLOBAL); 43 | if(!library) 44 | { 45 | Error::setErrorString(String::fromCString(dlerror())); 46 | return false; 47 | } 48 | return true; 49 | #endif 50 | } 51 | 52 | void* Library::findSymbol(const String& name) 53 | { 54 | #ifdef _WIN32 55 | #ifdef _UNICODE 56 | char mbname[MAX_PATH]; 57 | usize destChars; 58 | if(wcstombs_s(&destChars, mbname, (const char*)name, name.length()) != 0) 59 | return 0; 60 | return (void*)GetProcAddress((HMODULE)library, mbname); 61 | #else 62 | return (void*)GetProcAddress((HMODULE)library, (const char*)name); 63 | #endif 64 | #else 65 | void* sym = dlsym(library, (const char*)name); 66 | if(!sym) 67 | { 68 | Error::setErrorString(String::fromCString(dlerror())); 69 | return 0; 70 | } 71 | return sym; 72 | #endif 73 | } 74 | -------------------------------------------------------------------------------- /src/Log.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #ifndef _WIN32 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | static class _Log 19 | { 20 | public: 21 | static Mutex mutex; 22 | static String lineFormat; 23 | static String timeFormat; 24 | static Log::Device device; 25 | static int level; 26 | 27 | #ifndef _WIN32 28 | ~_Log() 29 | { 30 | if(device == Log::syslog) 31 | ::closelog(); 32 | } 33 | 34 | static int mapLevelToSyslog(int level) 35 | { 36 | if(level <= Log::debug) 37 | return LOG_DEBUG; 38 | if(level <= Log::info) 39 | return LOG_INFO; 40 | if(level <= Log::warning) 41 | return LOG_WARNING; 42 | if(level <= Log::error) 43 | return LOG_ERR; 44 | return LOG_CRIT; 45 | } 46 | #endif 47 | 48 | static void vlogf(int level, const char* format, va_list& vl) 49 | { 50 | int64 time = Time::time(); 51 | String lineFormat; 52 | String timeFormat; 53 | Log::Device device; 54 | 55 | { 56 | Mutex::Guard guard(_Log::mutex); 57 | device = _Log::device; 58 | if (device != Log::syslog) 59 | { 60 | lineFormat = _Log::lineFormat; 61 | timeFormat = _Log::timeFormat; 62 | } 63 | } 64 | 65 | // get message 66 | String data(200); 67 | int result; 68 | { 69 | usize capacity = data.capacity(); 70 | va_list tmp; 71 | va_copy(tmp, vl); 72 | result = vsnprintf((char*)data, capacity, format, tmp); 73 | va_end(tmp); 74 | if(result >= 0 && result < (int)capacity) 75 | data.resize(result); 76 | else // buffer was too small: compute size, reserve buffer, print again 77 | { 78 | va_copy(tmp, vl); 79 | #ifdef _MSC_VER 80 | result = _vscprintf(format, vl); 81 | #else 82 | result = vsnprintf(0, 0, format, vl); 83 | #endif 84 | va_end(tmp); 85 | ASSERT(result >= 0); 86 | if(result >= 0) 87 | { 88 | data.reserve(result); 89 | va_copy(tmp, vl); 90 | result = vsnprintf((char*)data, result + 1, format, vl); 91 | va_end(tmp); 92 | ASSERT(result >= 0); 93 | if(result >= 0) 94 | data.resize(result); 95 | } 96 | } 97 | } 98 | 99 | #ifndef _WIN32 100 | if(_Log::device == Log::syslog) 101 | { 102 | syslog(mapLevelToSyslog(level), "%s", (const char*)data); 103 | return; 104 | } 105 | #endif 106 | 107 | // build line 108 | String line(data.length() + 200); 109 | for(const char* p = lineFormat; *p; ++p) 110 | { 111 | if(*p == '%') 112 | { 113 | ++p; 114 | switch(*p) 115 | { 116 | case '%': 117 | line += '%'; 118 | break; 119 | case 'm': 120 | line += data; 121 | break; 122 | case 't': 123 | line += Time::toString(time, timeFormat); 124 | break; 125 | case 'L': 126 | switch(level) 127 | { 128 | case Log::debug: line += "debug"; break; 129 | case Log::info: line += "info"; break; 130 | case Log::warning: line += "warning"; break; 131 | case Log::error: line += "error"; break; 132 | case Log::critical: line += "critical"; break; 133 | default: line += "unknown"; break; 134 | } 135 | break; 136 | case 'P': 137 | line += String::fromInt(Process::getCurrentProcessId()); 138 | break; 139 | case 'T': 140 | line += String::fromInt(Thread::getCurrentThreadId()); 141 | break; 142 | default: 143 | line += '%'; 144 | line += *p; 145 | break; 146 | } 147 | } 148 | else 149 | line += *p; 150 | } 151 | line += '\n'; 152 | if(level >= Log::warning) 153 | Console::error(line); 154 | else 155 | Console::print(line); 156 | } 157 | 158 | } _log; 159 | 160 | Mutex _Log::mutex; 161 | String _Log::lineFormat("[%t] %L: %m"); 162 | String _Log::timeFormat("%H:%M:%S"); 163 | int _Log::level = Log::info; 164 | Log::Device _Log::device = Log::stdOutErr; 165 | 166 | void Log::setFormat(const String& lineFormat, const String& timeFormat) 167 | { 168 | Mutex::Guard guard(_Log::mutex); 169 | _Log::lineFormat = lineFormat; 170 | _Log::timeFormat = timeFormat; 171 | } 172 | 173 | void Log::setDevice(Device device) 174 | { 175 | Mutex::Guard guard(_Log::mutex); 176 | if(_Log::device != device) 177 | { 178 | #ifndef _WIN32 179 | if(_Log::device == Log::syslog) 180 | ::closelog(); 181 | #endif 182 | _Log::device = device; 183 | #ifndef _WIN32 184 | if(device == Log::syslog) 185 | ::openlog(NULL, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); 186 | #endif 187 | } 188 | } 189 | 190 | void Log::setLevel(int level) 191 | { 192 | _Log::level = level; 193 | } 194 | 195 | void Log::logf(int level, const char* format, ...) 196 | { 197 | if(level < _Log::level) 198 | return; 199 | va_list vl; 200 | va_start(vl, format); 201 | _Log::vlogf(level, format, vl); 202 | va_end(vl); 203 | } 204 | 205 | void Log::debugf(const char* format, ...) 206 | { 207 | if(Log::debug < _Log::level) 208 | return; 209 | va_list vl; 210 | va_start(vl, format); 211 | _Log::vlogf(Log::debug, format, vl); 212 | va_end(vl); 213 | } 214 | 215 | void Log::infof(const char* format, ...) 216 | { 217 | if(Log::info < _Log::level) 218 | return; 219 | va_list vl; 220 | va_start(vl, format); 221 | _Log::vlogf(Log::info, format, vl); 222 | va_end(vl); 223 | } 224 | 225 | void Log::warningf(const char* format, ...) 226 | { 227 | if(Log::warning < _Log::level) 228 | return; 229 | va_list vl; 230 | va_start(vl, format); 231 | _Log::vlogf(Log::warning, format, vl); 232 | va_end(vl); 233 | } 234 | 235 | void Log::errorf(const char* format, ...) 236 | { 237 | if(Log::error < _Log::level) 238 | return; 239 | va_list vl; 240 | va_start(vl, format); 241 | _Log::vlogf(Log::error, format, vl); 242 | va_end(vl); 243 | } 244 | -------------------------------------------------------------------------------- /src/Math.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #ifdef _MSC_VER 5 | #define __PLACEMENT_NEW_INLINE 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | uint Math::random() {return rand();} 12 | uint Math::random(uint seed) {return srand(seed), rand();} 13 | const usize Math::randomMax = RAND_MAX; 14 | double Math::floor(double v) {return std::floor(v);} 15 | float Math::floor(float v) {return std::floor(v);} 16 | double Math::ceil(double v) {return std::ceil(v);} 17 | float Math::ceil(float v) {return std::ceil(v);} 18 | double Math::exp(double v) {return std::exp(v);} 19 | float Math::exp(float v) {return std::exp(v);} 20 | 21 | -------------------------------------------------------------------------------- /src/Memory.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #ifdef _WIN32 5 | #define WIN32_LEAN_AND_MEAN 6 | #define WIN32_LEAN_AND_MEAN 7 | #include 8 | #endif 9 | #include 10 | 11 | void Memory::copy(void* dest, const void* src, usize length) 12 | { 13 | #ifdef _WIN32 14 | CopyMemory(dest, src, length); 15 | #else 16 | memcpy(dest, src, length); 17 | #endif 18 | } 19 | 20 | void Memory::move(void* dest, const void* src, usize length) 21 | { 22 | #ifdef _WIN32 23 | MoveMemory(dest, src, length); 24 | #else 25 | memmove(dest, src, length); 26 | #endif 27 | } 28 | 29 | void Memory::fill(void* buffer, byte value, usize size) 30 | { 31 | #ifdef _WIN32 32 | FillMemory(buffer, size, value); 33 | #else 34 | memset(buffer, value, size); 35 | #endif 36 | } 37 | 38 | void Memory::zero(void* buffer, usize size) 39 | { 40 | #ifdef _WIN32 41 | ZeroMemory(buffer, size); 42 | #else 43 | memset(buffer, 0, size); 44 | #endif 45 | } 46 | 47 | int Memory::compare(const void* ptr1, const void* ptr2, usize count) 48 | { 49 | return memcmp(ptr1, ptr2, count); 50 | } 51 | -------------------------------------------------------------------------------- /src/Monitor.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | Monitor::Monitor() : signaled(false) 13 | { 14 | #ifdef _WIN32 15 | ASSERT(sizeof(cdata) >= sizeof(CONDITION_VARIABLE)); 16 | ASSERT(sizeof(mdata) >= sizeof(CRITICAL_SECTION)); 17 | (CONDITION_VARIABLE&)cdata = CONDITION_VARIABLE_INIT; 18 | InitializeCriticalSection((CRITICAL_SECTION*)mdata); 19 | #else 20 | ASSERT(sizeof(cdata) >= sizeof(pthread_cond_t)); 21 | ASSERT(sizeof(mdata) >= sizeof(pthread_mutex_t)); 22 | pthread_cond_init((pthread_cond_t*)cdata, 0); 23 | pthread_mutex_init((pthread_mutex_t*)mdata, 0); 24 | #endif 25 | } 26 | 27 | Monitor::~Monitor() 28 | { 29 | #ifdef _WIN32 30 | DeleteCriticalSection((CRITICAL_SECTION*)mdata); 31 | #else 32 | VERIFY(pthread_cond_destroy((pthread_cond_t*)cdata) == 0); 33 | VERIFY(pthread_mutex_destroy((pthread_mutex_t*)mdata) == 0); 34 | #endif 35 | } 36 | 37 | bool Monitor::tryLock() 38 | { 39 | #ifdef _WIN32 40 | return TryEnterCriticalSection((CRITICAL_SECTION*)mdata) == TRUE; 41 | #else 42 | return pthread_mutex_trylock((pthread_mutex_t*)mdata) == 0; 43 | #endif 44 | } 45 | 46 | void Monitor::lock() 47 | { 48 | #ifdef _WIN32 49 | EnterCriticalSection((CRITICAL_SECTION*)mdata); 50 | #else 51 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)mdata) == 0); 52 | #endif 53 | } 54 | 55 | bool Monitor::wait() 56 | { 57 | #ifdef _WIN32 58 | for(;;) 59 | { 60 | if(!SleepConditionVariableCS((CONDITION_VARIABLE*)cdata, (CRITICAL_SECTION*)mdata, INFINITE)) 61 | return false; 62 | if(signaled) 63 | { 64 | signaled = false; 65 | return true; 66 | } 67 | } 68 | #else 69 | for(;;) 70 | { 71 | VERIFY(pthread_cond_wait((pthread_cond_t*)cdata, (pthread_mutex_t*)mdata) == 0); 72 | if(signaled) 73 | { 74 | signaled = false; 75 | return true; 76 | } 77 | } 78 | #endif 79 | } 80 | 81 | bool Monitor::wait(int64 timeout) 82 | { 83 | #ifdef _WIN32 84 | for(;;) 85 | { 86 | if(!SleepConditionVariableCS((CONDITION_VARIABLE*)cdata, (CRITICAL_SECTION*)mdata, (DWORD)timeout)) 87 | return false; 88 | if(signaled) 89 | { 90 | signaled = false; 91 | return true; 92 | } 93 | } 94 | #else 95 | struct timespec ts; 96 | clock_gettime(CLOCK_REALTIME, &ts); 97 | ts.tv_nsec += (timeout % 1000) * 1000000; 98 | ts.tv_sec += timeout / 1000 + ts.tv_nsec / 1000000000; 99 | ts.tv_nsec %= 1000000000; 100 | for(;;) 101 | { 102 | if(pthread_cond_timedwait((pthread_cond_t*)cdata, (pthread_mutex_t*)mdata, &ts) != 0) 103 | return false; 104 | if(signaled) 105 | { 106 | signaled = false; 107 | return true; 108 | } 109 | } 110 | #endif 111 | } 112 | 113 | void Monitor::unlock() 114 | { 115 | #ifdef _WIN32 116 | LeaveCriticalSection((CRITICAL_SECTION*)mdata); 117 | #else 118 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 119 | #endif 120 | } 121 | 122 | void Monitor::set() 123 | { 124 | #ifdef _WIN32 125 | EnterCriticalSection((CRITICAL_SECTION*)mdata); 126 | #else 127 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)mdata) == 0); 128 | #endif 129 | signaled = true; 130 | #ifdef _WIN32 131 | LeaveCriticalSection((CRITICAL_SECTION*)mdata); 132 | WakeConditionVariable((CONDITION_VARIABLE*)cdata); 133 | #else 134 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 135 | VERIFY(pthread_cond_signal((pthread_cond_t*)cdata) == 0); 136 | #endif 137 | } 138 | -------------------------------------------------------------------------------- /src/Mutex.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | Mutex::Mutex() 13 | { 14 | #ifdef _WIN32 15 | ASSERT(sizeof(data) >= sizeof(CRITICAL_SECTION)); 16 | InitializeCriticalSection(&(CRITICAL_SECTION&)data); 17 | #else 18 | ASSERT(sizeof(data) >= sizeof(pthread_mutex_t)); 19 | pthread_mutexattr_t attr; // TODO: use global var for this? 20 | pthread_mutexattr_init(&attr); 21 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 22 | VERIFY(pthread_mutex_init((pthread_mutex_t*)data, &attr) == 0); 23 | #endif 24 | } 25 | 26 | Mutex::~Mutex() 27 | { 28 | #ifdef _WIN32 29 | DeleteCriticalSection(&(CRITICAL_SECTION&)data); 30 | #else 31 | VERIFY(pthread_mutex_destroy((pthread_mutex_t*)data) == 0); 32 | #endif 33 | } 34 | 35 | void Mutex::lock() 36 | { 37 | #ifdef _WIN32 38 | EnterCriticalSection(&(CRITICAL_SECTION&)data); 39 | #else 40 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)data) == 0); 41 | #endif 42 | } 43 | 44 | bool Mutex::tryLock() 45 | { 46 | #ifdef _WIN32 47 | return TryEnterCriticalSection(&(CRITICAL_SECTION&)data) == TRUE; 48 | #else 49 | return pthread_mutex_trylock((pthread_mutex_t*)data) == 0; 50 | #endif 51 | } 52 | 53 | void Mutex::unlock() 54 | { 55 | #ifdef _WIN32 56 | LeaveCriticalSection(&(CRITICAL_SECTION&)data); 57 | #else 58 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)data) == 0); 59 | #endif 60 | } 61 | -------------------------------------------------------------------------------- /src/Semaphore.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Implementation of a Semaphore object. 3 | * @author Colin Graf 4 | */ 5 | 6 | #ifdef _WIN32 7 | #include 8 | #define WIN32_LEAN_AND_MEAN 9 | #include 10 | #else 11 | #include 12 | #include 13 | #include 14 | #include // usleep 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | Semaphore::Semaphore(uint value) 21 | { 22 | #ifdef _WIN32 23 | VERIFY(handle = CreateSemaphore(NULL, value, LONG_MAX, NULL)); 24 | #else 25 | ASSERT(sizeof(data) >= sizeof(sem_t)); 26 | VERIFY(sem_init((sem_t*)data, 0, value) != -1); 27 | #endif 28 | } 29 | 30 | Semaphore::~Semaphore() 31 | { 32 | #ifdef _WIN32 33 | VERIFY(CloseHandle(handle)); 34 | #else 35 | VERIFY(sem_destroy((sem_t*)data) != -1); 36 | #endif 37 | } 38 | 39 | void Semaphore::signal() 40 | { 41 | #ifdef _WIN32 42 | VERIFY(ReleaseSemaphore((HANDLE)handle, 1, 0)); 43 | #else 44 | VERIFY(sem_post((sem_t*)data) != -1); 45 | #endif 46 | } 47 | 48 | bool Semaphore::wait() 49 | { 50 | #ifdef _WIN32 51 | return WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0; 52 | #else 53 | return sem_wait((sem_t*)data) != -1; 54 | #endif 55 | } 56 | 57 | bool Semaphore::wait(int64 timeout) 58 | { 59 | #ifdef _WIN32 60 | return WaitForSingleObject((HANDLE)handle, (DWORD)timeout) == WAIT_OBJECT_0; 61 | #else 62 | struct timespec ts; 63 | clock_gettime(CLOCK_REALTIME, &ts); 64 | ts.tv_nsec += (timeout % 1000) * 1000000; 65 | ts.tv_sec += timeout / 1000 + ts.tv_nsec / 1000000000; 66 | ts.tv_nsec %= 1000000000; 67 | for(;;) 68 | { 69 | if(sem_timedwait((sem_t*)data, &ts) == -1) 70 | { 71 | if(errno == EINTR) 72 | continue; 73 | if(errno == ENOSYS) 74 | goto no_sem_timedwait; 75 | return false; 76 | } 77 | return true; 78 | } 79 | no_sem_timedwait: 80 | // TODO: this sucks, find a better way to do something like this: 81 | for(int i = 0; i < timeout; i += 10) 82 | { 83 | if(sem_trywait((sem_t*)data) != -1) 84 | return true; 85 | usleep(10 * 1000); 86 | } 87 | return false; 88 | #endif 89 | } 90 | 91 | bool Semaphore::tryWait() 92 | { 93 | #ifdef _WIN32 94 | return WaitForSingleObject((HANDLE)handle, 0) == WAIT_OBJECT_0; 95 | #else 96 | return sem_trywait((sem_t*)data) != -1; 97 | #endif 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/Signal.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | Signal::Signal(bool set) 13 | { 14 | #ifdef _WIN32 15 | VERIFY(handle = CreateEvent(NULL, TRUE, set ? TRUE : FALSE, NULL)); 16 | #else 17 | ASSERT(sizeof(cdata) >= sizeof(pthread_cond_t)); 18 | ASSERT(sizeof(mdata) >= sizeof(pthread_mutex_t)); 19 | pthread_cond_init((pthread_cond_t*)cdata, 0); 20 | pthread_mutex_init((pthread_mutex_t*)mdata, 0); 21 | signaled = set; 22 | #endif 23 | } 24 | 25 | Signal::~Signal() 26 | { 27 | #ifdef _WIN32 28 | VERIFY(CloseHandle(handle)); 29 | #else 30 | VERIFY(pthread_cond_destroy((pthread_cond_t*)cdata) == 0); 31 | VERIFY(pthread_mutex_destroy((pthread_mutex_t*)mdata) == 0); 32 | #endif 33 | } 34 | 35 | void Signal::set() 36 | { 37 | #ifdef _WIN32 38 | VERIFY(SetEvent(handle)); 39 | #else 40 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)mdata) == 0); 41 | signaled = true; 42 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 43 | VERIFY(pthread_cond_broadcast((pthread_cond_t*)cdata) == 0); 44 | #endif 45 | } 46 | 47 | void Signal::reset() 48 | { 49 | #ifdef _WIN32 50 | VERIFY(ResetEvent(handle)); 51 | #else 52 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)mdata) == 0); 53 | signaled = false; 54 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 55 | #endif 56 | } 57 | 58 | bool Signal::wait() 59 | { 60 | #ifdef _WIN32 61 | return WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0; 62 | #else 63 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)mdata) == 0); 64 | for(;;) 65 | { 66 | if(signaled) 67 | { 68 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 69 | return true; 70 | } 71 | VERIFY(pthread_cond_wait((pthread_cond_t*)cdata, (pthread_mutex_t*)mdata) == 0); 72 | } 73 | #endif 74 | } 75 | 76 | bool Signal::wait(int64 timeout) 77 | { 78 | #ifdef _WIN32 79 | return WaitForSingleObject(handle, (DWORD)timeout) == WAIT_OBJECT_0; 80 | #else 81 | struct timespec ts; 82 | clock_gettime(CLOCK_REALTIME, &ts); 83 | ts.tv_nsec += (timeout % 1000) * 1000000; 84 | ts.tv_sec += timeout / 1000 + ts.tv_nsec / 1000000000; 85 | ts.tv_nsec %= 1000000000; 86 | VERIFY(pthread_mutex_lock((pthread_mutex_t*)mdata) == 0); 87 | for(;;) 88 | { 89 | if(signaled) 90 | { 91 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 92 | return true; 93 | } 94 | if(pthread_cond_timedwait((pthread_cond_t*)cdata, (pthread_mutex_t*)mdata, &ts) != 0) 95 | { 96 | VERIFY(pthread_mutex_unlock((pthread_mutex_t*)mdata) == 0); 97 | return false; 98 | } 99 | } 100 | #endif 101 | } 102 | -------------------------------------------------------------------------------- /src/Socket/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(sources 3 | Server.cpp 4 | Socket.cpp 5 | ../../include/nstd/Socket/Server.hpp 6 | ../../include/nstd/Socket/Socket.hpp 7 | ) 8 | 9 | add_library(nstdSocket STATIC 10 | ${sources} 11 | ) 12 | add_library(libnstd::Socket ALIAS nstdSocket) 13 | 14 | target_link_libraries(nstdSocket PUBLIC 15 | nstd 16 | ) 17 | 18 | if(WIN32) 19 | target_link_libraries(nstdSocket PUBLIC 20 | ws2_32 21 | ) 22 | endif() 23 | if(MSVC AND UNICODE) 24 | target_link_libraries(nstdSocket PUBLIC 25 | ntdll 26 | ) 27 | endif() 28 | 29 | source_group("" FILES ${sources}) 30 | set_property(TARGET nstdSocket PROPERTY FOLDER "src") 31 | -------------------------------------------------------------------------------- /src/System.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | #include 10 | 11 | uint System::getProcessorCount() 12 | { 13 | #ifdef _WIN32 14 | SYSTEM_INFO sysinfo; 15 | GetSystemInfo(&sysinfo); 16 | return sysinfo.dwNumberOfProcessors; 17 | #else 18 | return sysconf(_SC_NPROCESSORS_ONLN); 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /src/Thread.cpp: -------------------------------------------------------------------------------- 1 | 2 | #ifdef _WIN32 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #else 6 | #include 7 | #include // usleep 8 | #include 9 | #endif 10 | 11 | #include 12 | #include 13 | 14 | Thread::Thread() : thread(0)//, threadId(0) 15 | { 16 | #ifdef _WIN32 17 | ASSERT(sizeof(thread) >= sizeof(HANDLE)); 18 | #else 19 | ASSERT(sizeof(thread) >= sizeof(pthread_t)); 20 | #endif 21 | } 22 | 23 | Thread::~Thread() 24 | { 25 | if(thread) 26 | join(); 27 | } 28 | 29 | bool Thread::start(uint (*proc)(void*), void* param) 30 | { 31 | if(thread) 32 | return false; 33 | #ifdef _WIN32 34 | //DWORD threadId; 35 | ASSERT(sizeof(unsigned long) == sizeof(uint)); 36 | 37 | #ifndef __CYGWIN__ 38 | thread = (void*)CreateThread(0, 0, (unsigned long (__stdcall*)(void*)) proc, param, 0, /*&threadId*/0); 39 | if(!thread) 40 | return false; 41 | #else 42 | struct ThreadData 43 | { 44 | static DWORD WINAPI ThreadProc(LPVOID lpParameter) 45 | { 46 | ThreadData& data = *(ThreadData*)lpParameter; 47 | uint (*proc)(void*) = data.proc; 48 | void* param = data.param; 49 | VERIFY(SetEvent(data.hevent)); 50 | // return proc(param); // this does not set the exit code 51 | ExitThread(proc(param)); 52 | } 53 | uint (*proc)(void*); 54 | void* param; 55 | HANDLE hevent; 56 | } data; 57 | 58 | data.proc = proc; 59 | data.param = param; 60 | data.hevent = CreateEvent(NULL, FALSE, FALSE, NULL); 61 | if(data.hevent == NULL) 62 | return false; 63 | thread = (void*)CreateThread(0, 0, ThreadData::ThreadProc, &data, 0, /*&threadId*/0); 64 | if(!thread) 65 | { 66 | VERIFY(CloseHandle(data.hevent)); 67 | return false; 68 | } 69 | VERIFY(WaitForSingleObject(data.hevent, INFINITE) == WAIT_OBJECT_0); 70 | VERIFY(CloseHandle(data.hevent)); 71 | #endif 72 | //this->threadId = threadId; 73 | return true; 74 | #else 75 | pthread_t thread; 76 | if(pthread_create(&thread, 0, (void* (*) (void *)) proc, param) != 0) 77 | return false; 78 | this->thread = (void*)thread; 79 | return true; 80 | #endif 81 | } 82 | 83 | uint Thread::join() 84 | { 85 | if(!thread) 86 | return 0; 87 | #ifdef _WIN32 88 | VERIFY(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0); 89 | DWORD exitCode; 90 | VERIFY(GetExitCodeThread(thread, &exitCode)); 91 | VERIFY(CloseHandle(thread)); 92 | thread = 0; 93 | //threadId = 0; 94 | return exitCode; 95 | #else 96 | void* retval; 97 | VERIFY(pthread_join((pthread_t)thread, &retval) == 0); 98 | thread = 0; 99 | return (uint)(intptr_t)retval; 100 | #endif 101 | } 102 | 103 | void Thread::yield() 104 | { 105 | #ifdef _WIN32 106 | SwitchToThread(); 107 | #else 108 | sched_yield(); 109 | #endif 110 | } 111 | 112 | void Thread::sleep(int64 milliseconds) 113 | { 114 | #ifdef _WIN32 115 | Sleep((DWORD)milliseconds); 116 | #else 117 | usleep(milliseconds * 1000); 118 | #endif 119 | } 120 | 121 | uint32 Thread::getCurrentThreadId() 122 | { 123 | #ifdef _WIN32 124 | return (uint32)GetCurrentThreadId(); 125 | #else 126 | return (uint32)syscall(__NR_gettid); 127 | #endif 128 | } 129 | -------------------------------------------------------------------------------- /src/Time.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #ifdef _WIN32 4 | #define NOMINMAX 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | #endif 8 | 9 | #include 10 | #ifdef _WIN32 11 | #include 12 | #endif 13 | 14 | class Time::Private 15 | { 16 | #ifdef _WIN32 17 | public: 18 | static int64 perfFreq; 19 | static class Framework 20 | { 21 | public: 22 | Framework() 23 | { 24 | LARGE_INTEGER li; 25 | VERIFY(QueryPerformanceFrequency(&li)); 26 | perfFreq = li.QuadPart / 1000000LL; 27 | } 28 | } framework; 29 | #endif 30 | }; 31 | 32 | #ifdef _WIN32 33 | #ifdef _MSC_VER 34 | #pragma warning(disable: 4073) 35 | #pragma init_seg(lib) 36 | Time::Private::Framework Time::Private::framework; 37 | #else 38 | Time::Private::Framework Time::Private::framework __attribute__ ((init_priority (101))); 39 | #endif 40 | int64 Time::Private::perfFreq; 41 | #endif 42 | 43 | Time::Time(bool utc) : utc(utc) 44 | { 45 | time_t now; 46 | ::time(&now); 47 | #ifdef _WIN32 48 | tm* tm = utc ? ::gmtime(&now) : ::localtime(&now); // win32 gmtime and localtime are thread save 49 | #else 50 | struct tm tmBuf; 51 | tm* tm = utc ? ::gmtime_r(&now, &tmBuf) : ::localtime_r(&now, &tmBuf); 52 | #endif 53 | sec = tm->tm_sec; 54 | min = tm->tm_min; 55 | hour = tm->tm_hour; 56 | day = tm->tm_mday; 57 | month = tm->tm_mon + 1; 58 | year = tm->tm_year + 1900; 59 | wday = tm->tm_wday; 60 | yday = tm->tm_yday; 61 | dst = !!tm->tm_isdst; 62 | } 63 | 64 | Time::Time(int64 time, bool utc) : utc(utc) 65 | { 66 | time_t now = (time_t)(time / 1000LL); 67 | #ifdef _WIN32 68 | tm* tm = utc ? ::gmtime(&now) : ::localtime(&now); // win32 gmtime and localtime are thread save 69 | #else 70 | struct tm tmBuf; 71 | tm* tm = utc ? ::gmtime_r(&now, &tmBuf) : ::localtime_r(&now, &tmBuf); 72 | #endif 73 | sec = tm->tm_sec; 74 | min = tm->tm_min; 75 | hour = tm->tm_hour; 76 | day = tm->tm_mday; 77 | month = tm->tm_mon + 1; 78 | year = tm->tm_year + 1900; 79 | wday = tm->tm_wday; 80 | yday = tm->tm_yday; 81 | dst = !!tm->tm_isdst; 82 | } 83 | 84 | Time::Time(const Time& other) : 85 | sec(other.sec), 86 | min(other.min), 87 | hour(other.hour), 88 | day(other.day), 89 | month(other.month), 90 | year(other.year), 91 | wday(other.wday), 92 | yday(other.yday), 93 | dst(other.dst), 94 | utc(other.utc) {} 95 | 96 | int64 Time::toTimestamp() 97 | { 98 | tm tm; 99 | tm.tm_sec = sec; 100 | tm.tm_min = min; 101 | tm.tm_hour = hour; 102 | tm.tm_mday = day; 103 | tm.tm_mon = month - 1; 104 | tm.tm_year = year - 1900; 105 | tm.tm_wday = wday; 106 | tm.tm_yday = yday; 107 | tm.tm_isdst = dst; 108 | if(utc) 109 | #ifdef _MSC_VER 110 | return _mkgmtime(&tm) * 1000LL; 111 | #else 112 | return timegm(&tm) * 1000LL; 113 | #endif 114 | else 115 | return mktime(&tm) * 1000LL; 116 | } 117 | 118 | Time& Time::toUtc() 119 | { 120 | if(!utc) 121 | { 122 | int64 timestamp = toTimestamp(); 123 | *this = Time(timestamp, true); 124 | } 125 | return *this; 126 | } 127 | 128 | Time& Time::toLocal() 129 | { 130 | if(utc) 131 | { 132 | int64 timestamp = toTimestamp(); 133 | *this = Time(timestamp, false); 134 | } 135 | return *this; 136 | } 137 | 138 | bool Time::operator==(const Time& other) const 139 | { 140 | return sec == other.sec && 141 | min == other.min && 142 | hour == other.hour && 143 | day == other.day && 144 | month == other.month && 145 | year == other.year && 146 | wday == other.wday && 147 | yday == other.yday && 148 | dst == other.dst && 149 | utc == other.utc; 150 | } 151 | 152 | bool Time::operator!=(const Time& other) const 153 | { 154 | return sec != other.sec || 155 | min != other.min || 156 | hour != other.hour || 157 | day != other.day || 158 | month != other.month || 159 | year != other.year || 160 | wday != other.wday || 161 | yday != other.yday || 162 | dst != other.dst || 163 | utc != other.utc; 164 | } 165 | 166 | int64 Time::time() 167 | { 168 | return ::time(0) * 1000LL; 169 | } 170 | 171 | int64 Time::ticks() 172 | { 173 | #ifdef _WIN32 174 | return GetTickCount64(); 175 | #else 176 | struct timespec ts; 177 | clock_gettime(CLOCK_MONOTONIC, &ts); 178 | return (int64)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; 179 | #endif 180 | } 181 | 182 | int64 Time::microTicks() 183 | { 184 | #ifdef _WIN32 185 | LARGE_INTEGER li; 186 | VERIFY(QueryPerformanceCounter(&li)); 187 | return li.QuadPart / Private::perfFreq; 188 | #else 189 | struct timespec ts; 190 | clock_gettime(CLOCK_MONOTONIC, &ts); 191 | return (int64)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 192 | #endif 193 | } 194 | 195 | String Time::toString(const char* format) 196 | { 197 | if(!*format) 198 | return String(); 199 | tm tm; 200 | tm.tm_sec = sec; 201 | tm.tm_min = min; 202 | tm.tm_hour = hour; 203 | tm.tm_mday = day; 204 | tm.tm_mon = month - 1; 205 | tm.tm_year = year - 1900; 206 | tm.tm_wday = wday; 207 | tm.tm_yday = yday; 208 | tm.tm_isdst = dst; 209 | 210 | String result(256); 211 | char* buffer; 212 | usize len; 213 | for(;;) 214 | { 215 | buffer = result; 216 | len = strftime(buffer, result.capacity(), format, &tm); 217 | if(len > 0) 218 | break; 219 | result.reserve(result.capacity() * 2); 220 | } 221 | result.resize(len); 222 | return result; 223 | } 224 | 225 | String Time::toString(int64 time, const char* format, bool utc) 226 | { 227 | if(!*format) 228 | return String(); 229 | time_t timet = (time_t)(time / 1000); 230 | const tm* tms = utc ? ::gmtime(&timet) : ::localtime(&timet); 231 | String result(256); 232 | if(!tms) 233 | return result; 234 | char* buffer; 235 | usize len; 236 | for(;;) 237 | { 238 | buffer = result; 239 | len = strftime(buffer, result.capacity(), format, tms); 240 | if(len > 0) 241 | break; 242 | result.reserve(result.capacity() * 2); 243 | } 244 | result.resize(len); 245 | return result; 246 | } 247 | -------------------------------------------------------------------------------- /src/Variant.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | Variant::NullData Variant::nullData; 5 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_subdirectory(Console) 3 | add_subdirectory(Performance) 4 | add_subdirectory(UnitTest) 5 | -------------------------------------------------------------------------------- /test/Console/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(sources 3 | Main.cpp 4 | ) 5 | add_executable(Console ${sources}) 6 | target_link_libraries(Console PRIVATE libnstd::Core) 7 | set_property(TARGET Console PROPERTY FOLDER "test") 8 | source_group("" FILES ${sources}) 9 | -------------------------------------------------------------------------------- /test/Console/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | uint threadProc(void* param) 10 | { 11 | Signal* termSignal = (Signal*)param; 12 | int counter = 0; 13 | while(!termSignal->wait(1000)) 14 | { 15 | if(counter % 5 == 0) 16 | Console::errorf("%d%s", counter, ((counter + 1) % 3) == 0 ? "\n" : " "); 17 | else 18 | Console::printf("%d%s", counter, ((counter + 1) % 3) == 0 ? "\n" : " "); 19 | ++counter; 20 | } 21 | return 0; 22 | } 23 | 24 | int main(int argc, char* argv[]) 25 | { 26 | String password("root"); 27 | String user("root"); 28 | String address("127.0.0.1:13211"); 29 | { 30 | Process::Option options[] = { 31 | {'p', "password", Process::argumentFlag}, 32 | {'u', "user", Process::argumentFlag}, 33 | {'h', "help", Process::optionFlag}, 34 | }; 35 | Process::Arguments arguments(argc, argv, options); 36 | int character; 37 | String argument; 38 | while(arguments.read(character, argument)) 39 | switch(character) 40 | { 41 | case 'p': 42 | password = argument; 43 | break; 44 | case 'u': 45 | user = argument; 46 | break; 47 | case 0: 48 | address = argument; 49 | break; 50 | case '?': 51 | Console::errorf("Unknown option: %s.\n", (const char*)argument); 52 | return 1; 53 | case ':': 54 | Console::errorf("Option %s required an argument.\n", (const char*)argument); 55 | return 1; 56 | default: 57 | Console::errorf("Usage: %s [-u ] [-p ] [
]\n", argv[0]); 58 | return 1; 59 | } 60 | } 61 | 62 | Console::printf("user=%s, password=%s, address=%s\n", 63 | (const char*)user, (const char*)password, (const char*)address); 64 | 65 | Console::printf("Hello World!\n"); 66 | 67 | Console::Prompt prompt; 68 | 69 | Log::infof("Hello World!"); 70 | Log::warningf("%s", "This is a warning!"); 71 | 72 | Thread thread; 73 | Signal termSignal; 74 | thread.start(threadProc, &termSignal); 75 | for(;;) 76 | { 77 | String result = prompt.getLine("test> "); 78 | Console::printf("input: %s\n", (const char*)result); 79 | if(result == "exit") 80 | break; 81 | } 82 | termSignal.set(); 83 | thread.join(); 84 | 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /test/Performance/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(sources 3 | FutureNStd.cpp 4 | FutureStd.cpp 5 | HashMapNStd.cpp 6 | HashMapStd.cpp 7 | MapNStd.cpp 8 | MapStd.cpp 9 | Performance.cpp 10 | StringNStd.cpp 11 | StringStd.cpp 12 | ) 13 | add_executable(Performance ${sources}) 14 | target_link_libraries(Performance PRIVATE libnstd::Core) 15 | set_property(TARGET Performance PROPERTY FOLDER "test") 16 | source_group("" FILES ${sources}) 17 | -------------------------------------------------------------------------------- /test/Performance/FutureNStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testFutureNStd(int iterations) 7 | { 8 | struct A 9 | { 10 | static int64 testProc(int64 i) 11 | { 12 | return i; 13 | } 14 | }; 15 | 16 | int64 result = 0; 17 | for(int i = 0; i < iterations; ++i) 18 | { 19 | Future future; 20 | future.start(&A::testProc, i); 21 | result += future; 22 | } 23 | if(result != (int64)iterations * (int64)(iterations - 1) / 2) 24 | { 25 | Console::printf("fail\n"); 26 | Process::exit(1); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/Performance/FutureStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testFutureStd(int iterations) 7 | { 8 | struct A 9 | { 10 | static int64_t testProc(int64_t i) 11 | { 12 | return i; 13 | } 14 | }; 15 | 16 | int64_t result = 0; 17 | for(int i = 0; i < iterations; ++i) 18 | { 19 | std::future future = std::async(&A::testProc, i); 20 | result += future.get(); 21 | } 22 | if(result != (int64_t)iterations * (int64_t)(iterations - 1) / 2) 23 | { 24 | printf("fail\n"); 25 | std::terminate(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/Performance/HashMapNStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testHashMapNStd(int iterations) 6 | { 7 | srand(100); 8 | HashMap testMap(1000); 9 | for (int i = 0; i < iterations; ++i) 10 | { 11 | testMap.append(rand() % 1000, 0); 12 | } 13 | for (int i = 0; i < iterations; ++i) 14 | { 15 | testMap.append(rand() % 1000, 0); 16 | testMap.remove(rand() % 1000); 17 | } 18 | for (int i = 0; i < iterations; ++i) 19 | { 20 | testMap.remove(rand() % 1000); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/Performance/HashMapStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testHashMapStd(int iterations) 6 | { 7 | srand(100); 8 | std::unordered_map testMap(1000); 9 | for (int i = 0; i < iterations; ++i) 10 | { 11 | testMap.insert(std::make_pair(rand() % 1000, 0)); 12 | } 13 | for (int i = 0; i < iterations; ++i) 14 | { 15 | testMap.insert(std::make_pair(rand() % 1000, 0)); 16 | testMap.erase(rand() % 1000); 17 | } 18 | for (int i = 0; i < iterations; ++i) 19 | { 20 | testMap.erase(rand() % 1000); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /test/Performance/MapNStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testMapNStd(int iterations) 6 | { 7 | srand(100); 8 | Map testMap; 9 | for (int i = 0; i < iterations; ++i) 10 | { 11 | testMap.insert(rand() % 1000, 0); 12 | } 13 | for (int i = 0; i < iterations; ++i) 14 | { 15 | testMap.insert(rand() % 1000, 0); 16 | testMap.remove(rand() % 1000); 17 | } 18 | for (int i = 0; i < iterations; ++i) 19 | { 20 | testMap.remove(rand() % 1000); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/Performance/MapStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testMapStd(int iterations) 6 | { 7 | srand(100); 8 | std::map testMap; 9 | for (int i = 0; i < iterations; ++i) 10 | { 11 | testMap.insert(std::make_pair(rand() % 1000, 0)); 12 | } 13 | for (int i = 0; i < iterations; ++i) 14 | { 15 | testMap.insert(std::make_pair(rand() % 1000, 0)); 16 | testMap.erase(rand() % 1000); 17 | } 18 | for (int i = 0; i < iterations; ++i) 19 | { 20 | testMap.erase(rand() % 1000); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /test/Performance/Performance.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testMapStd(int iterations); 6 | void testMapNStd(int iterations); 7 | void testHashMapStd(int iterations); 8 | void testHashMapNStd(int iterations); 9 | void testStringStd(int iterations); 10 | void testStringNStd(int iterations); 11 | void testFutureStd(int iterations); 12 | void testFutureNStd(int iterations); 13 | 14 | const int mapTestIterations = 1000000; 15 | 16 | int main(int argc, char* argv[]) 17 | { 18 | for (int i = 0; i < 3; ++i) 19 | { 20 | { 21 | Console::printf("testMapStd... "); 22 | int64 startTime = Time::microTicks(); 23 | testMapStd(mapTestIterations); 24 | int64 duration = Time::microTicks() - startTime; 25 | Console::printf("%lld microseconds\n", duration); 26 | } 27 | 28 | { 29 | Console::printf("testMapNStd... "); 30 | int64 startTime = Time::microTicks(); 31 | testMapNStd(mapTestIterations); 32 | int64 duration = Time::microTicks() - startTime; 33 | Console::printf("%lld microseconds\n", duration); 34 | } 35 | { 36 | Console::printf("testHashMapStd... "); 37 | int64 startTime = Time::microTicks(); 38 | testHashMapStd(mapTestIterations); 39 | int64 duration = Time::microTicks() - startTime; 40 | Console::printf("%lld microseconds\n", duration); 41 | } 42 | 43 | { 44 | Console::printf("testHashMapNStd... "); 45 | int64 startTime = Time::microTicks(); 46 | testHashMapNStd(mapTestIterations); 47 | int64 duration = Time::microTicks() - startTime; 48 | Console::printf("%lld microseconds\n", duration); 49 | } 50 | { 51 | Console::printf("testStringStd... "); 52 | int64 startTime = Time::microTicks(); 53 | testStringStd(mapTestIterations); 54 | int64 duration = Time::microTicks() - startTime; 55 | Console::printf("%lld microseconds\n", duration); 56 | } 57 | 58 | { 59 | Console::printf("testStringNStd... "); 60 | int64 startTime = Time::microTicks(); 61 | testStringNStd(mapTestIterations); 62 | int64 duration = Time::microTicks() - startTime; 63 | Console::printf("%lld microseconds\n", duration); 64 | } 65 | 66 | { 67 | Console::printf("testFutureStd... "); 68 | int64 startTime = Time::microTicks(); 69 | testFutureStd(mapTestIterations / 10); 70 | int64 duration = Time::microTicks() - startTime; 71 | Console::printf("%lld microseconds\n", duration); 72 | } 73 | 74 | { 75 | Console::printf("testFutureNStd... "); 76 | int64 startTime = Time::microTicks(); 77 | testFutureNStd(mapTestIterations / 10); 78 | int64 duration = Time::microTicks() - startTime; 79 | Console::printf("%lld microseconds\n", duration); 80 | } 81 | } 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /test/Performance/StringNStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testStringNStd(int iterations) 6 | { 7 | srand(100); 8 | usize val = 0; 9 | String blah[] = { 10 | "12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678", 11 | "12345688 12345688 12345688 12345688 12345688 12345688 12345688 12345688 12345688", 12 | "12345698 12345698 12345698 12345698 12345698 12345698 12345698 12345698 12345698" 13 | }; 14 | for (int i = 0; i < iterations; ++i) 15 | { 16 | if(String("12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678") == blah[rand() % 3]) 17 | val += (String("12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678") + blah[rand() % 3]).length(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/Performance/StringStd.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testStringStd(int iterations) 7 | { 8 | srand(100); 9 | size_t val = 0; 10 | std::string blah[] = { 11 | "12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678", 12 | "12345688 12345688 12345688 12345688 12345688 12345688 12345688 12345688 12345688", 13 | "12345698 12345698 12345698 12345698 12345698 12345698 12345698 12345698 12345698" 14 | }; 15 | for (int i = 0; i < iterations; ++i) 16 | { 17 | if(std::string("12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678") == blah[rand() % 3]) 18 | val += (std::string("12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678 12345678") + blah[rand() % 3]).length(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/UnitTest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | function(add_unit_test name) 3 | add_executable(${name} ${ARGN}) 4 | target_link_libraries(${name} PRIVATE libnstd::Core) 5 | target_compile_definitions(${name} PRIVATE DEBUG) 6 | set_property(TARGET ${name} PROPERTY FOLDER "test") 7 | source_group("" FILES ${ARGN}) 8 | add_test(NAME ${name} COMMAND ${name}) 9 | set_tests_properties(${name} PROPERTIES TIMEOUT 20) 10 | endfunction() 11 | 12 | add_unit_test(TestArray TestArray.cpp) 13 | add_unit_test(TestAtomic TestAtomic.cpp) 14 | add_unit_test(TestBuffer TestBuffer.cpp) 15 | add_unit_test(TestCallback TestCallback.cpp) 16 | add_unit_test(TestConsole TestConsole.cpp) 17 | add_unit_test(TestDebug TestDebug.cpp) 18 | add_unit_test(TestDirectory TestDirectory.cpp) 19 | add_unit_test(TestError TestError.cpp) 20 | add_unit_test(TestFile TestFile.cpp) 21 | add_unit_test(TestFuture TestFuture.cpp) 22 | add_unit_test(TestHashMap TestHashMap.cpp) 23 | add_unit_test(TestHashSet TestHashSet.cpp) 24 | add_unit_test(TestJson TestJson.cpp) 25 | target_link_libraries(TestJson PRIVATE libnstd::Document) 26 | add_unit_test(TestList TestList.cpp) 27 | add_unit_test(TestLog TestLog.cpp) 28 | add_unit_test(TestMap TestMap.cpp) 29 | add_unit_test(TestMonitor TestMonitor.cpp) 30 | add_unit_test(TestMultiMap TestMultiMap.cpp) 31 | add_unit_test(TestMutex TestMutex.cpp) 32 | add_unit_test(TestPoolList TestPoolList.cpp) 33 | add_unit_test(TestPoolMap TestPoolMap.cpp) 34 | add_unit_test(TestProcess TestProcess.cpp) 35 | add_unit_test(TestRefCount TestRefCount.cpp) 36 | add_unit_test(TestSemaphore TestSemaphore.cpp) 37 | add_unit_test(TestServer TestServer.cpp) 38 | target_link_libraries(TestServer PRIVATE libnstd::Socket) 39 | add_unit_test(TestSha256 TestSha256.cpp) 40 | target_link_libraries(TestSha256 PRIVATE libnstd::Crypto) 41 | add_unit_test(TestSignal TestSignal.cpp) 42 | add_unit_test(TestSocket TestSocket.cpp) 43 | target_link_libraries(TestSocket PRIVATE libnstd::Socket) 44 | add_unit_test(TestString TestString.cpp) 45 | add_unit_test(TestThread TestThread.cpp) 46 | add_unit_test(TestTime TestTime.cpp) 47 | add_unit_test(TestUnicode TestUnicode.cpp) 48 | add_unit_test(TestVariant TestVariant.cpp) 49 | add_unit_test(TestXml TestXml.cpp) 50 | target_link_libraries(TestXml PRIVATE libnstd::Document) 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /test/UnitTest/TestArray.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testArray() 7 | { 8 | // test append 9 | Array myArray; 10 | Array emptyArray; 11 | myArray.swap(emptyArray); 12 | ASSERT(myArray.isEmpty()); 13 | ASSERT(myArray.size() == 0); 14 | ASSERT(myArray.append(123) == 123); 15 | ASSERT(myArray.append(124) == 124); 16 | ASSERT(myArray.append(125) == 125); 17 | ASSERT(!myArray.isEmpty()); 18 | ASSERT(myArray.size() == 3); 19 | 20 | // tets clear 21 | myArray.clear(); 22 | ASSERT(myArray.isEmpty()); 23 | ASSERT(myArray.size() == 0); 24 | } 25 | 26 | void testArrayString() 27 | { 28 | // test insert 29 | Array myArray; 30 | ASSERT(myArray.isEmpty()); 31 | ASSERT(myArray.size() == 0); 32 | ASSERT(myArray.append("string1") == "string1"); 33 | ASSERT(myArray.append("string2") == "string2"); 34 | ASSERT(myArray.append("string3") == "string3"); 35 | ASSERT(!myArray.isEmpty()); 36 | ASSERT(myArray.size() == 3); 37 | 38 | // test list copy constructor 39 | Array myArray2(myArray); 40 | ASSERT(myArray2.size() == 3); 41 | ASSERT(*myArray2.begin() == "string1"); 42 | ASSERT(*(++Array::Iterator(myArray2.begin())) == "string2"); 43 | ASSERT(myArray2.back() == "string3"); 44 | 45 | // test list copy operator 46 | Array myArray3; 47 | myArray3 = myArray; 48 | ASSERT(myArray3.size() == 3); 49 | ASSERT(*myArray3.begin() == "string1"); 50 | ASSERT(*(++Array::Iterator(myArray3.begin())) == "string2"); 51 | ASSERT(myArray3.back() == "string3"); 52 | 53 | // test clear 54 | myArray.clear(); 55 | ASSERT(myArray.isEmpty()); 56 | ASSERT(myArray.size() == 0); 57 | 58 | // test iterator 59 | String str; 60 | for(int i = 0; i < 500; ++i) 61 | { 62 | str.printf("test%d", i); 63 | myArray.append(str); 64 | } 65 | ASSERT(myArray.size() == 500); 66 | int count = 0; 67 | for(Array::Iterator i = myArray.begin(), end = myArray.end(); i != end; ++i) 68 | { 69 | str.printf("test%d", count); 70 | ASSERT(*i == str); 71 | ++count; 72 | } 73 | ASSERT(count == 500); 74 | 75 | // test remove 76 | myArray.remove(23); 77 | ASSERT(myArray.size() == 499); 78 | ASSERT(myArray.remove(myArray.begin()) == myArray.begin()); 79 | 80 | // test reserve 81 | myArray.clear(); 82 | myArray.append("test1"); 83 | myArray.reserve(1000); 84 | ASSERT(myArray.capacity() >= 1000); 85 | ASSERT(myArray.size() == 1); 86 | ASSERT(myArray[0] == "test1"); 87 | 88 | // test resize 89 | myArray.clear(); 90 | for (int i = 0; i < 100; ++i) 91 | myArray.append("test"); 92 | ASSERT(myArray.size() == 100); 93 | myArray.resize(110, "dasda"); 94 | ASSERT(myArray.size() == 110); 95 | myArray.resize(90); 96 | ASSERT(myArray.size() == 90); 97 | 98 | // test front and back 99 | myArray.clear(); 100 | myArray.append("1"); 101 | myArray.append("2"); 102 | ASSERT(myArray.front() == "1"); 103 | ASSERT(myArray.back() == "2"); 104 | myArray.append("3"); 105 | ASSERT(myArray.front() == "1"); 106 | ASSERT(myArray.back() == "3"); 107 | 108 | // test remove front and back 109 | myArray.clear(); 110 | myArray.append("1"); 111 | myArray.append("2"); 112 | myArray.append("3"); 113 | myArray.removeFront(); 114 | ASSERT(myArray.size() == 2); 115 | ASSERT(myArray.front() == "2"); 116 | myArray.removeBack(); 117 | ASSERT(myArray.size() == 1); 118 | ASSERT(myArray.front() == "2"); 119 | ASSERT(myArray.back() == "2"); 120 | } 121 | 122 | int main(int argc, char* argv[]) 123 | { 124 | testArray(); 125 | testArrayString(); 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /test/UnitTest/TestAtomic.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testAtomic() 6 | { 7 | { 8 | volatile int32 int32 = 42; 9 | volatile uint32 uint32 = 42; 10 | volatile int64 int64 = 42; 11 | volatile uint64 uint64 = 42; 12 | 13 | ASSERT(Atomic::increment(int32) == 43); 14 | ASSERT(Atomic::increment(uint32) == 43); 15 | ASSERT(Atomic::increment(int64) == 43); 16 | ASSERT(Atomic::increment(uint64) == 43); 17 | 18 | ASSERT(int32 == 43); 19 | ASSERT(uint32 == 43); 20 | ASSERT(int64 == 43); 21 | ASSERT(uint64 == 43); 22 | 23 | int32 = -100; 24 | uint32 = 0xfffffff0; 25 | int64 = -100; 26 | uint64 = 0xfffffffffffffff0; 27 | 28 | ASSERT(Atomic::increment(int32) == -99); 29 | ASSERT(Atomic::increment(uint32) == 0xfffffff1); 30 | ASSERT(Atomic::increment(int64) == -99); 31 | ASSERT(Atomic::increment(uint64) == 0xfffffffffffffff1); 32 | } 33 | 34 | { 35 | volatile int32 int32 = 42; 36 | volatile uint32 uint32 = 42; 37 | volatile int64 int64 = 42; 38 | volatile uint64 uint64 = 42; 39 | 40 | ASSERT(Atomic::decrement(int32) == 41); 41 | ASSERT(Atomic::decrement(uint32) == 41); 42 | ASSERT(Atomic::decrement(int64) == 41); 43 | ASSERT(Atomic::decrement(uint64) == 41); 44 | 45 | ASSERT(int32 == 41); 46 | ASSERT(uint32 == 41); 47 | ASSERT(int64 == 41); 48 | ASSERT(uint64 == 41); 49 | } 50 | 51 | { 52 | volatile int32 int32 = 42; 53 | volatile uint32 uint32 = 42; 54 | volatile int64 int64 = 42; 55 | volatile uint64 uint64 = 42; 56 | void* volatile ptr = (char*)0 + 42; 57 | 58 | ASSERT(Atomic::compareAndSwap(int32, 42, 0) == 42); 59 | ASSERT(Atomic::compareAndSwap(uint32, 42, 0) == 42); 60 | ASSERT(Atomic::compareAndSwap(int64, 42, 0) == 42); 61 | ASSERT(Atomic::compareAndSwap(uint64, 42, 0) == 42); 62 | ASSERT(Atomic::compareAndSwap(ptr, (void*)((char*)0 + 42), (void*)0) == (char*)0 + 42); 63 | 64 | ASSERT(int32 == 0); 65 | ASSERT(uint32 == 0); 66 | ASSERT(int64 == 0); 67 | ASSERT(uint64 == 0); 68 | ASSERT(ptr == 0); 69 | 70 | ASSERT(Atomic::compareAndSwap(int32, 42, 1) == 0); 71 | ASSERT(Atomic::compareAndSwap(uint32, 42, 1) == 0); 72 | ASSERT(Atomic::compareAndSwap(int64, 42, 1) == 0); 73 | ASSERT(Atomic::compareAndSwap(uint64, 42, 1) == 0); 74 | ASSERT(Atomic::compareAndSwap(ptr, (void*)((char*)0 + 42), (void*)((char*)0 + 1)) == 0); 75 | 76 | ASSERT(int32 == 0); 77 | ASSERT(uint32 == 0); 78 | ASSERT(int64 == 0); 79 | ASSERT(uint64 == 0); 80 | ASSERT(ptr == 0); 81 | } 82 | 83 | { 84 | volatile int32 int32 = 42; 85 | volatile uint32 uint32 = 42; 86 | volatile int64 int64 = 42; 87 | volatile uint64 uint64 = 42; 88 | 89 | ASSERT(Atomic::fetchAndAdd(int32, 3) == 42); 90 | ASSERT(Atomic::fetchAndAdd(uint32, 3) == 42); 91 | ASSERT(Atomic::fetchAndAdd(int64, 3) == 42); 92 | ASSERT(Atomic::fetchAndAdd(uint64, 3) == 42); 93 | 94 | ASSERT(int32 == 45); 95 | ASSERT(uint32 == 45); 96 | ASSERT(int64 == 45); 97 | ASSERT(uint64 == 45); 98 | } 99 | 100 | { 101 | volatile int32 int32 = 0; 102 | ASSERT(Atomic::testAndSet(int32) == 0); 103 | ASSERT(int32 != 0); 104 | } 105 | 106 | { 107 | volatile int32 int32 = 0; 108 | volatile uint32 uint32 = 0; 109 | volatile int64 int64 = 0; 110 | volatile uint64 uint64 = 0; 111 | void* volatile ptr = 0; 112 | 113 | ASSERT(Atomic::swap(int32, 1) == 0); 114 | ASSERT(Atomic::swap(uint32, 1) == 0); 115 | ASSERT(Atomic::swap(int64, 1) == 0); 116 | ASSERT(Atomic::swap(uint64, 1) == 0); 117 | ASSERT(Atomic::swap(ptr, (void*)((char*)0 + 1)) == 0); 118 | 119 | ASSERT(int32 == 1); 120 | ASSERT(uint32 == 1); 121 | ASSERT(int64 == 1); 122 | ASSERT(uint64 == 1); 123 | ASSERT(ptr == (char*)0 + 1); 124 | } 125 | 126 | { 127 | volatile int32 int32 = 0; 128 | volatile uint32 uint32 = 0; 129 | volatile int64 int64 = 0; 130 | volatile uint64 uint64 = 0; 131 | void* volatile ptr = 0; 132 | 133 | ASSERT(Atomic::load(int32) == 0); 134 | ASSERT(Atomic::load(uint32) == 0); 135 | ASSERT(Atomic::load(int64) == 0); 136 | ASSERT(Atomic::load(uint64) == 0); 137 | ASSERT(Atomic::load(ptr) == 0); 138 | } 139 | 140 | { 141 | volatile int32 int32 = 0; 142 | volatile uint32 uint32 = 0; 143 | volatile int64 int64 = 0; 144 | volatile uint64 uint64 = 0; 145 | void* volatile ptr = 0; 146 | 147 | Atomic::store(int32, 1); 148 | Atomic::store(uint32, 1); 149 | Atomic::store(int64, 1); 150 | Atomic::store(uint64, 1); 151 | Atomic::store(ptr, (void*)((char*)0 + 1)); 152 | 153 | ASSERT(int32 == 1); 154 | ASSERT(uint32 == 1); 155 | ASSERT(int64 == 1); 156 | ASSERT(uint64 == 1); 157 | ASSERT(ptr == (char*)0 + 1); 158 | } 159 | } 160 | 161 | int main(int argc, char* argv[]) 162 | { 163 | testAtomic(); 164 | return 0; 165 | } 166 | -------------------------------------------------------------------------------- /test/UnitTest/TestBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testBuffer() 6 | { 7 | Buffer buffer1; 8 | Buffer buffer2; 9 | Buffer buffer3; 10 | ASSERT(buffer1 == buffer2); 11 | buffer1 = buffer2; 12 | ASSERT(buffer1 == buffer2); 13 | buffer3.assign((byte*)"123", 3); 14 | buffer3 = buffer2; 15 | ASSERT(buffer3 == buffer2); 16 | } 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | testBuffer(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/UnitTest/TestConsole.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | void testConsole() 5 | { 6 | // test printf 7 | { 8 | Console::printf("%s\n", "Hello world"); 9 | char buffer[5000 * 4]; 10 | usize bufferSize = sizeof(buffer) - 1; 11 | Memory::fill(buffer, 'a', bufferSize - 1); 12 | buffer[bufferSize - 2] = 'b'; 13 | buffer[bufferSize - 1] = '\0'; 14 | Console::printf("%hs%hs\n", buffer, buffer); 15 | } 16 | } 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | testConsole(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/UnitTest/TestDebug.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testDebug() 6 | { 7 | Debug::printf("%s\n", "Hello world"); 8 | char buffer[5000 * 4]; 9 | usize bufferSize = sizeof(buffer) - 1; 10 | Memory::fill(buffer, 'a', bufferSize - 1); 11 | buffer[bufferSize - 2] = 'b'; 12 | buffer[bufferSize - 1] = '\0'; 13 | Debug::printf("%hs%hs\n", buffer, buffer); 14 | } 15 | 16 | int main(int argc, char* argv[]) 17 | { 18 | testDebug(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /test/UnitTest/TestError.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testError() 7 | { 8 | // test system error code 9 | { 10 | File file; 11 | ASSERT(!file.open("thisshouldbeanonexisting file")); 12 | ASSERT(!Error::getErrorString().isEmpty()); 13 | } 14 | 15 | // test user error code 16 | { 17 | Error::setErrorString("blah"); 18 | ASSERT(Error::getErrorString() == "blah"); 19 | } 20 | 21 | // test user error code again 22 | { 23 | Error::setErrorString("blah"); 24 | ASSERT(Error::getErrorString() == "blah"); 25 | } 26 | } 27 | 28 | int main(int argc, char* argv[]) 29 | { 30 | testError(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/UnitTest/TestFile.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void testFile() 8 | { 9 | // test open and close 10 | File::unlink("testfile.file.test"); 11 | ASSERT(!File::exists("testfile.file.test")); 12 | { 13 | File file; 14 | ASSERT(!file.isOpen()); 15 | ASSERT(file.open("testfile.file.test", File::writeFlag)); 16 | ASSERT(file.isOpen()); 17 | file.close(); 18 | ASSERT(!file.isOpen()); 19 | ASSERT(file.open("testfile.file.test", File::writeFlag)); 20 | ASSERT(file.isOpen()); 21 | } 22 | 23 | // test File::time function 24 | { 25 | File::Time time; 26 | ASSERT(File::time("testfile.file.test", time)); 27 | int64 now = Time::time(); 28 | //ASSERT(time.accessTime <= now + 1000 && time.accessTime > now - 10000); 29 | ASSERT(time.writeTime <= now + 1000 && time.writeTime > now - 10000); 30 | //ASSERT(time.creationTime <= now + 1000 && time.creationTime > now - 10000); 31 | } 32 | 33 | // test file exists 34 | ASSERT(File::exists("testfile.file.test")); 35 | ASSERT(!File::exists("dkasdlakshkalal.nonexisting.file")); 36 | 37 | // test file write 38 | char buffer[266]; 39 | char buffer2[300]; 40 | { 41 | File file; 42 | ASSERT(file.open("testfile.file.test", File::writeFlag)); 43 | Memory::fill(buffer, 'a', sizeof(buffer)); 44 | ASSERT(file.write(buffer, sizeof(buffer)) == sizeof(buffer)); 45 | Memory::fill(buffer2, 'b', sizeof(buffer2)); 46 | ASSERT(file.write(buffer2, sizeof(buffer2)) == sizeof(buffer2)); 47 | ASSERT(file.size() == sizeof(buffer) + sizeof(buffer2)); 48 | } 49 | 50 | // test file read 51 | { 52 | File file; 53 | ASSERT(file.open("testfile.file.test", File::readFlag)); 54 | ASSERT(file.size() == sizeof(buffer) + sizeof(buffer2)); 55 | char readBuffer[500]; 56 | ASSERT(file.read(readBuffer, sizeof(readBuffer)) == sizeof(readBuffer)); 57 | ASSERT(Memory::compare(readBuffer, buffer, sizeof(buffer)) == 0); 58 | ASSERT(Memory::compare(readBuffer + sizeof(buffer), buffer2, sizeof(readBuffer) - sizeof(buffer)) == 0); 59 | char readBuffer2[166]; 60 | ASSERT(file.read(readBuffer2, sizeof(readBuffer2)) == sizeof(buffer) + sizeof(buffer2) - sizeof(readBuffer)); 61 | ASSERT(Memory::compare(readBuffer2, buffer2 + sizeof(buffer2) - (sizeof(buffer) + sizeof(buffer2) - sizeof(readBuffer)), sizeof(buffer) + sizeof(buffer2) - sizeof(readBuffer)) == 0); 62 | file.close(); 63 | } 64 | 65 | // test file read all 66 | { 67 | File file; 68 | ASSERT(file.open("testfile.file.test", File::readFlag)); 69 | ASSERT(file.size() == sizeof(buffer) + sizeof(buffer2)); 70 | String data; 71 | ASSERT(file.readAll(data)); 72 | ASSERT(data.length() == sizeof(buffer) + sizeof(buffer2)); 73 | ASSERT(Memory::compare((const char*)data, buffer, sizeof(buffer)) == 0); 74 | ASSERT(Memory::compare((const byte*)(const char*)data + sizeof(buffer), buffer2, sizeof(buffer2)) == 0); 75 | } 76 | 77 | // test unlink 78 | ASSERT(File::unlink("testfile.file.test")); 79 | ASSERT(!File::exists("testfile.file.test")); 80 | 81 | // test append mode 82 | { 83 | char buf1[10]; 84 | char buf2[20]; 85 | Memory::fill(buf1, 1, sizeof(buf1)); 86 | Memory::fill(buf2, 1, sizeof(buf2)); 87 | { 88 | File file; 89 | ASSERT(file.open("testfile.file.test", File::writeFlag)); 90 | ASSERT(file.write(buf1, sizeof(buf1)) == sizeof(buf1)); 91 | } 92 | { 93 | File file; 94 | ASSERT(file.open("testfile.file.test", File::writeFlag | File::appendFlag)); 95 | ASSERT(file.write(buf2, sizeof(buf2)) == sizeof(buf2)); 96 | } 97 | { 98 | File file; 99 | ASSERT(file.open("testfile.file.test", File::readFlag)); 100 | char result[50]; 101 | ASSERT(file.read(result, sizeof(result)) == sizeof(buf1) + sizeof(buf2)); 102 | ASSERT(Memory::compare(result, buf1, sizeof(buf1)) == 0); 103 | ASSERT(Memory::compare(result + sizeof(buf1), buf2, sizeof(buf2)) == 0); 104 | } 105 | } 106 | ASSERT(File::unlink("testfile.file.test")); 107 | 108 | // test rename function 109 | { 110 | File::unlink("testfile.file.test2"); 111 | File file; 112 | ASSERT(file.open("testfile.file.test", File::writeFlag)); 113 | file.close(); 114 | ASSERT(File::rename("testfile.file.test", "testfile.file.test2")); 115 | ASSERT(!File::exists("testfile.file.test")); 116 | ASSERT(!File::rename("testfile.file.test", "testfile.file.test2")); 117 | ASSERT(file.open("testfile.file.test", File::writeFlag)); 118 | file.close(); 119 | ASSERT(!File::rename("testfile.file.test", "testfile.file.test2")); 120 | ASSERT(File::rename("testfile.file.test", "testfile.file.test2", false)); 121 | ASSERT(!File::exists("testfile.file.test")); 122 | File::unlink("testfile.file.test2"); 123 | } 124 | 125 | // test file name functions 126 | { 127 | ASSERT(File::getBaseName("c:\\sadasd\\asdas\\test.blah") == "test.blah"); 128 | ASSERT(File::getBaseName("c:\\sadasd\\asdas\\test") == "test"); 129 | ASSERT(File::getBaseName("c:\\sadasd\\asdas\\test.blah", "blah") == "test"); 130 | ASSERT(File::getBaseName("c:\\sadasd\\asdas\\test.blah", ".blah") == "test"); 131 | ASSERT(File::getBaseName("c:\\sadasd\\asdas\\test.blah", ".xy") == "test.blah"); 132 | ASSERT(File::getStem("c:\\sadasd\\asdas\\test.blah") == "test"); 133 | ASSERT(File::getStem("c:\\sadasd\\asdas\\test") == "test"); 134 | ASSERT(File::getStem("c:\\sadasd\\asdas\\test.blah", "blah") == "test"); 135 | ASSERT(File::getStem("c:\\sadasd\\asdas\\test.blah", ".blah") == "test"); 136 | ASSERT(File::getExtension("c:\\sadasd\\asdas\\test.blah") == "blah"); 137 | ASSERT(File::getDirectoryName("c:\\sadasd\\asdas\\test.blah") == "c:\\sadasd\\asdas"); 138 | ASSERT(File::getDirectoryName("asdas/test.blah") == "asdas"); 139 | 140 | ASSERT(File::simplifyPath("../../dsadsad/2dsads") == "../../dsadsad/2dsads"); 141 | ASSERT(File::simplifyPath("..\\..\\dsadsad\\2dsads") == "../../dsadsad/2dsads"); 142 | ASSERT(File::simplifyPath(".././../dsadsad/2dsads") == "../../dsadsad/2dsads"); 143 | ASSERT(File::simplifyPath("dsadsad/../2dsads") == "2dsads"); 144 | ASSERT(File::simplifyPath("dsadsad/./../2dsads") == "2dsads"); 145 | ASSERT(File::simplifyPath("dsadsad/.././2dsads") == "2dsads"); 146 | ASSERT(File::simplifyPath("/dsadsad/../2dsads") == "/2dsads"); 147 | ASSERT(File::simplifyPath("/../../aaa/2dsads") == "/../../aaa/2dsads"); 148 | ASSERT(File::simplifyPath("/dsadsad/../2dsads/") == "/2dsads"); 149 | ASSERT(File::simplifyPath("dsadsad\\") == "dsadsad"); 150 | 151 | ASSERT(File::isAbsolutePath("/aaa/2dsads")); 152 | ASSERT(File::isAbsolutePath("\\aaa\\2dsads")); 153 | ASSERT(File::isAbsolutePath("c:/aaa/2dsads")); 154 | ASSERT(File::isAbsolutePath("c:\\aaa\\2dsads")); 155 | ASSERT(!File::isAbsolutePath("..\\aaa\\2dsads")); 156 | ASSERT(!File::isAbsolutePath("aaa/2dsads")); 157 | } 158 | } 159 | 160 | int main(int argc, char* argv[]) 161 | { 162 | testFile(); 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /test/UnitTest/TestHashMap.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testHashMap() 7 | { 8 | { 9 | // test append 10 | HashMap myMap; 11 | HashMap emptyMap; 12 | myMap.swap(emptyMap); 13 | ASSERT(myMap.isEmpty()); 14 | myMap.append(123, 123); 15 | ASSERT(myMap.contains(123)); 16 | myMap.append(123, 125); 17 | ASSERT(myMap.size() == 1); 18 | ASSERT(*myMap.find(123) == 125); 19 | 20 | // test clear 21 | myMap.clear(); 22 | ASSERT(myMap.size() == 0); 23 | ASSERT(myMap.isEmpty()); 24 | } 25 | 26 | { 27 | // test append 28 | HashMap myMap; 29 | ASSERT(myMap.isEmpty()); 30 | myMap.append("string1", 120); 31 | myMap.append("string1", 121); 32 | ASSERT(myMap.size() == 1); 33 | myMap.append("string2", 122); 34 | myMap.append("string3", 123); 35 | ASSERT(myMap.size() == 3); 36 | 37 | // test find 38 | ASSERT(*myMap.find("string1") == 121); 39 | ASSERT(*myMap.find("string2") == 122); 40 | ASSERT(*myMap.find("string3") == 123); 41 | ASSERT(myMap.find("dsadasa") == myMap.end()); 42 | 43 | // test list copy constructor 44 | HashMap myMap2(myMap); 45 | ASSERT(myMap2.size() == 3); 46 | ASSERT(*myMap2.begin() == 121); 47 | ASSERT(myMap2.begin().key() == "string1"); 48 | ASSERT(*(++HashMap::Iterator(myMap2.begin())) == 122); 49 | ASSERT(myMap2.back() == 123); 50 | 51 | // test list copy operator 52 | HashMap myMap3; 53 | myMap3 = myMap; 54 | ASSERT(myMap3.size() == 3); 55 | ASSERT(*myMap3.begin() == 121); 56 | ASSERT(myMap3.begin().key() == "string1"); 57 | ASSERT(*(++HashMap::Iterator(myMap3.begin())) == 122); 58 | ASSERT(myMap3.back() == 123); 59 | 60 | // test clear 61 | myMap.clear(); 62 | ASSERT(myMap.size() == 0); 63 | ASSERT(myMap.isEmpty()); 64 | 65 | // test front and back 66 | myMap.clear(); 67 | myMap.append("1", 1); 68 | myMap.append("2", 2); 69 | ASSERT(myMap.front() == 1); 70 | ASSERT(myMap.back() == 2); 71 | myMap.append("3", 3); 72 | ASSERT(myMap.front() == 1); 73 | ASSERT(myMap.back() == 3); 74 | myMap.prepend("0", 0); 75 | ASSERT(myMap.front() == 0); 76 | ASSERT(myMap.back() == 3); 77 | 78 | // test remove front and back 79 | myMap.clear(); 80 | myMap.append("1", 1); 81 | myMap.append("2", 2); 82 | myMap.append("3", 3); 83 | myMap.removeFront(); 84 | ASSERT(myMap.size() == 2); 85 | ASSERT(myMap.front() == 2); 86 | myMap.removeBack(); 87 | ASSERT(myMap.size() == 1); 88 | ASSERT(myMap.front() == 2); 89 | ASSERT(myMap.back() == 2); 90 | } 91 | } 92 | 93 | int main(int argc, char* argv[]) 94 | { 95 | testHashMap(); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /test/UnitTest/TestHashSet.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct TestHashSetDestructor 8 | { 9 | int num; 10 | 11 | TestHashSetDestructor() : num(0) {} 12 | TestHashSetDestructor(int num) : num(num) {} 13 | ~TestHashSetDestructor() {++destructions;} 14 | 15 | operator usize() const {return num;} 16 | 17 | static int destructions; 18 | }; 19 | 20 | int TestHashSetDestructor::destructions = 0; 21 | 22 | void testHashSet() 23 | { 24 | { 25 | HashSet mySet; 26 | HashSet emptySet; 27 | mySet.swap(emptySet); 28 | ASSERT(mySet.isEmpty()); 29 | ASSERT(mySet.begin() == mySet.end()); 30 | mySet.append(1); 31 | ASSERT(mySet.contains(1)); 32 | mySet.append(2); 33 | mySet.append(3); 34 | ASSERT(mySet.begin() != mySet.end()); 35 | HashSet::Iterator it = mySet.begin(); 36 | ASSERT(*it == 1); 37 | ASSERT(*(++it) == 2); 38 | ASSERT(*(++it) == 3); 39 | ASSERT(++it == mySet.end()); 40 | ASSERT(mySet.size() == 3); 41 | ASSERT(mySet.find(2) != mySet.end()); 42 | ASSERT(mySet.find(5) == mySet.end()); 43 | mySet.remove(3); 44 | mySet.remove(1); 45 | mySet.append(5); 46 | mySet.append(6); 47 | ASSERT(mySet.find(3) == mySet.end()); 48 | ASSERT(mySet.find(1) == mySet.end()); 49 | ASSERT(mySet.find(5) != mySet.end()); 50 | ASSERT(mySet.find(6) != mySet.end()); 51 | it = mySet.begin(); 52 | ASSERT(*it == 2); 53 | ASSERT(*(++it) == 5); 54 | ASSERT(*(++it) == 6); 55 | for(int i = 0; i < 300; ++i) 56 | mySet.append((Math::random() % 30) + 10); 57 | for(int i = 0; i < 300; ++i) 58 | mySet.remove((Math::random() % 30) + 10); 59 | for(HashSet::Iterator it = mySet.begin(), end = mySet.end(), next; it != end; it = next) 60 | { 61 | next = it; ++next; 62 | if(*it >= 10) 63 | mySet.remove(it); 64 | } 65 | it = mySet.begin(); 66 | ASSERT(*it == 2); 67 | ASSERT(*(++it) == 5); 68 | ASSERT(*(++it) == 6); 69 | mySet.append(400); 70 | mySet.append(400); 71 | mySet.remove(400); 72 | ASSERT(mySet.find(400) == mySet.end()); 73 | mySet.clear(); 74 | ASSERT(mySet.size() == 0); 75 | ASSERT(mySet.isEmpty()); 76 | 77 | // test front and back 78 | mySet.clear(); 79 | mySet.append(1); 80 | mySet.append(2); 81 | ASSERT(mySet.front() == 1); 82 | ASSERT(mySet.back() == 2); 83 | 84 | // test remove front and back 85 | mySet.clear(); 86 | mySet.append(1); 87 | mySet.append(2); 88 | mySet.append(3); 89 | mySet.removeFront(); 90 | ASSERT(mySet.size() == 2); 91 | ASSERT(mySet.front() == 2); 92 | mySet.removeBack(); 93 | ASSERT(mySet.size() == 1); 94 | ASSERT(mySet.front() == 2); 95 | ASSERT(mySet.back() == 2); 96 | } 97 | 98 | // ?? 99 | { 100 | { 101 | HashSet mySet; 102 | mySet.append(1); 103 | mySet.append(2); 104 | mySet.append(3); 105 | mySet.remove(1); 106 | ASSERT(mySet.size() == 2); 107 | } 108 | ASSERT(TestHashSetDestructor::destructions == 8); 109 | } 110 | 111 | // with string 112 | { 113 | // test append 114 | HashSet mySet; 115 | ASSERT(mySet.isEmpty()); 116 | mySet.append("string1"); 117 | mySet.append("string2"); 118 | mySet.append("string3"); 119 | ASSERT(mySet.size() == 3); 120 | ASSERT(!mySet.isEmpty()); 121 | 122 | // test find 123 | ASSERT(mySet.find("string1") != mySet.end()); 124 | ASSERT(mySet.find("string2") != mySet.end()); 125 | ASSERT(*mySet.find("string2") == "string2"); 126 | ASSERT(mySet.find("string3") != mySet.end()); 127 | ASSERT(mySet.find("wdashat") == mySet.end()); 128 | 129 | // test list copy constructor 130 | HashSet mySet2(mySet); 131 | ASSERT(mySet2.size() == 3); 132 | ASSERT(*mySet2.begin() == "string1"); 133 | ASSERT(*(++HashSet::Iterator(mySet2.begin())) == "string2"); 134 | ASSERT(mySet2.back() == "string3"); 135 | 136 | // test list copy operator 137 | HashSet mySet3; 138 | mySet3 = mySet; 139 | ASSERT(mySet3.size() == 3); 140 | ASSERT(*mySet3.begin() == "string1"); 141 | ASSERT(*(++HashSet::Iterator(mySet3.begin())) == "string2"); 142 | ASSERT(mySet3.back() == "string3"); 143 | } 144 | } 145 | 146 | int main(int argc, char* argv[]) 147 | { 148 | testHashSet(); 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /test/UnitTest/TestJson.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testJson() 7 | { 8 | Json::Parser parser; 9 | Variant data; 10 | String input("{\n" 11 | " \"title\": \"Example Schema\",\n" 12 | " \"surrogatePair\": \"aa\\uD834\\uDD1Ebb\",\n" 13 | " \"type\": \"object\",\n" 14 | " \"properties\": {\n" 15 | " \"firstName\": {\n" 16 | " \"type\": \"string\"\n" 17 | " },\n" 18 | " \"lastName\": {\n" 19 | " \"type\": \"string\"\n" 20 | " },\n" 21 | " \"age\": {\n" 22 | " \"description\": \"Age in years\",\n" 23 | " \"type\": \"integer\",\n" 24 | " \"minimum\": 0\n" 25 | " }\n" 26 | " },\n" 27 | " \"required\": [\"firstName\", \"lastName\"]\n" 28 | "}\n"); 29 | ASSERT(parser.parse(input, data)); 30 | ASSERT(data.toMap().find("title")->toString() == "Example Schema"); 31 | String surrogatePairCheck; 32 | surrogatePairCheck.append("aa"); 33 | Unicode::append(0x1d11e, surrogatePairCheck); 34 | surrogatePairCheck.append("bb"); 35 | ASSERT(data.toMap().find("surrogatePair")->toString() == surrogatePairCheck); 36 | ASSERT(data.toMap().find("type")->toString() == "object"); 37 | ASSERT(data.toMap().find("properties")->toMap().find("firstName")->toMap().find("type")->toString() == "string"); 38 | ASSERT(data.toMap().find("properties")->toMap().find("lastName")->toMap().find("type")->toString() == "string"); 39 | ASSERT(data.toMap().find("properties")->toMap().find("age")->toMap().find("description")->toString() == "Age in years"); 40 | ASSERT(data.toMap().find("properties")->toMap().find("age")->toMap().find("type")->toString() == "integer"); 41 | ASSERT(data.toMap().find("properties")->toMap().find("age")->toMap().find("minimum")->getType() == Variant::intType); 42 | ASSERT(data.toMap().find("properties")->toMap().find("age")->toMap().find("minimum")->toInt() == 0); 43 | ASSERT(data.toMap().find("required")->toList().front().toString() == "firstName"); 44 | ASSERT(data.toMap().find("required")->toList().back().toString() == "lastName"); 45 | } 46 | 47 | void testStripComments() 48 | { 49 | String input("{\n \"test\": \"/*\",\n /*\n*/\n //\n //a\n}\n"); 50 | String stripped = Json::stripComments(input); 51 | String check("{\n \"test\": \"/*\",\n \n\n \n \n}\n"); 52 | ASSERT(stripped == check); 53 | } 54 | 55 | int main(int argc, char* argv[]) 56 | { 57 | testJson(); 58 | testStripComments(); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /test/UnitTest/TestList.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void testList() 8 | { 9 | { 10 | // test list append 11 | List myList; 12 | List emptyList; 13 | myList.swap(emptyList); 14 | ASSERT(myList.isEmpty()); 15 | myList.append("string1"); 16 | myList.append("string2"); 17 | myList.append("string3"); 18 | ASSERT(myList.size() == 3); 19 | 20 | // test list copy constructor 21 | List myList2(myList); 22 | ASSERT(myList2.size() == 3); 23 | ASSERT(*myList2.begin() == "string1"); 24 | ASSERT(*(++List::Iterator(myList2.begin())) == "string2"); 25 | ASSERT(*(++myList2.begin()) == "string2"); 26 | ASSERT(myList2.back() == "string3"); 27 | 28 | // test list copy operator 29 | List myList3; 30 | myList3 = myList; 31 | ASSERT(myList3.size() == 3); 32 | ASSERT(*myList3.begin() == "string1"); 33 | ASSERT(*(++List::Iterator(myList3.begin())) == "string2"); 34 | ASSERT(myList3.back() == "string3"); 35 | 36 | // test list find 37 | ASSERT(myList.find("string2") != myList.end()); 38 | ASSERT(myList.find("string4") == myList.end()); 39 | myList.remove("string2"); 40 | ASSERT(myList.size() == 2); 41 | ASSERT(myList.find("string2") == myList.end()); 42 | 43 | // test list iterator 44 | List::Iterator it = myList.begin(); 45 | ASSERT(*it == "string1"); 46 | ASSERT(*(++it) == "string3"); 47 | *it = "abbba"; 48 | ASSERT(*it == "abbba"); 49 | 50 | // test prepend 51 | myList.prepend("string7"); 52 | ASSERT(*myList.begin() == "string7"); 53 | 54 | // test list clear 55 | myList.clear(); 56 | ASSERT(myList.size() == 0); 57 | ASSERT(myList.isEmpty()); 58 | 59 | // test front and back 60 | myList.clear(); 61 | myList.append("1"); 62 | myList.append("2"); 63 | ASSERT(myList.front() == "1"); 64 | ASSERT(myList.back() == "2"); 65 | myList.append("3"); 66 | ASSERT(myList.front() == "1"); 67 | ASSERT(myList.back() == "3"); 68 | myList.prepend("0"); 69 | ASSERT(myList.front() == "0"); 70 | ASSERT(myList.back() == "3"); 71 | 72 | // test remove front and back 73 | myList.clear(); 74 | myList.append("1"); 75 | myList.append("2"); 76 | myList.append("3"); 77 | myList.removeFront(); 78 | ASSERT(myList.size() == 2); 79 | ASSERT(myList.front() == "2"); 80 | myList.removeBack(); 81 | ASSERT(myList.size() == 1); 82 | ASSERT(myList.front() == "2"); 83 | ASSERT(myList.back() == "2"); 84 | } 85 | 86 | // int sort 87 | { 88 | List myList; 89 | for(int i = 0; i < 100; ++i) 90 | myList.append(Math::random() % 90); 91 | myList.sort(); 92 | int current = 0; 93 | for(List::Iterator i = myList.begin(), end = myList.end(); i != end; ++i) 94 | { 95 | ASSERT(*i >= current); 96 | current = *i; 97 | } 98 | } 99 | 100 | // string sort 101 | { 102 | List myList; 103 | String str; 104 | for(int i = 0; i < 100; ++i) 105 | { 106 | str.printf("abc%d", (int)(Math::random() % 90)); 107 | myList.append(str); 108 | } 109 | myList.sort(); 110 | String current("abc0"); 111 | for(List::Iterator i = myList.begin(), end = myList.end(); i != end; ++i) 112 | { 113 | ASSERT(*i >= current); 114 | current = *i; 115 | } 116 | } 117 | 118 | // insert 119 | { 120 | List list; 121 | List::Iterator it = list.insert(list.begin(), 1); 122 | ASSERT(it == list.begin()); 123 | ASSERT(*it == 1); 124 | ASSERT(list.size() == 1); 125 | } 126 | { 127 | List list; 128 | list.append(1); 129 | List::Iterator it = list.insert(list.begin(), 2); 130 | ASSERT(it == list.begin()); 131 | ASSERT(*it == 2); 132 | ASSERT(*(++it) == 1); 133 | } 134 | { 135 | List list; 136 | list.append(1); 137 | List::Iterator it = list.insert(list.end(), 2); 138 | ASSERT(it != list.begin()); 139 | ASSERT(*it == 2); 140 | ASSERT(*(--it) == 1); 141 | } 142 | 143 | // insert list 144 | { 145 | List list; 146 | list.append(1); 147 | list.append(2); 148 | List otherList; 149 | otherList.append(10); 150 | otherList.append(11); 151 | otherList.append(12); 152 | List::Iterator i = list.begin(); 153 | ++i; 154 | ASSERT(*i == 2); 155 | i = list.insert(i, otherList); 156 | ASSERT(*i == 10); 157 | ASSERT(list.size() == 5); 158 | i = list.begin(); 159 | ASSERT(*i == 1); 160 | ASSERT(*(++i) == 10); 161 | ASSERT(*(++i) == 11); 162 | ASSERT(*(++i) == 12); 163 | ASSERT(*(++i) == 2); 164 | ASSERT(++i == list.end()); 165 | List emptyList; 166 | i = list.begin(); 167 | ++i; 168 | ASSERT(list.insert(i, emptyList) == i); 169 | ASSERT(list.size() == 5); 170 | } 171 | 172 | // prepend list 173 | { 174 | List list; 175 | list.append(1); 176 | list.append(2); 177 | List otherList; 178 | otherList.append(10); 179 | otherList.append(11); 180 | otherList.append(12); 181 | list.prepend(otherList); 182 | ASSERT(list.size() == 5); 183 | List::Iterator i = list.begin(); 184 | ASSERT(*i == 10); 185 | ASSERT(*(++i) == 11); 186 | ASSERT(*(++i) == 12); 187 | ASSERT(*(++i) == 1); 188 | ASSERT(*(++i) == 2); 189 | ASSERT(++i == list.end()); 190 | List emptyList; 191 | list.prepend(emptyList); 192 | ASSERT(list.size() == 5); 193 | } 194 | { 195 | List list; 196 | List otherList; 197 | otherList.append(10); 198 | otherList.append(11); 199 | otherList.append(12); 200 | list.prepend(otherList); 201 | ASSERT(list.size() == 3); 202 | List::Iterator i = list.begin(); 203 | ASSERT(*i == 10); 204 | ASSERT(*(++i) == 11); 205 | ASSERT(*(++i) == 12); 206 | ASSERT(++i == list.end()); 207 | } 208 | 209 | // append list 210 | { 211 | List list; 212 | list.append(1); 213 | list.append(2); 214 | List otherList; 215 | otherList.append(10); 216 | otherList.append(11); 217 | otherList.append(12); 218 | list.append(otherList); 219 | ASSERT(list.size() == 5); 220 | List::Iterator i = list.begin(); 221 | ASSERT(*i == 1); 222 | ASSERT(*(++i) == 2); 223 | ASSERT(*(++i) == 10); 224 | ASSERT(*(++i) == 11); 225 | ASSERT(*(++i) == 12); 226 | ASSERT(++i == list.end()); 227 | List emptyList; 228 | list.prepend(emptyList); 229 | ASSERT(list.size() == 5); 230 | } 231 | { 232 | List list; 233 | List otherList; 234 | otherList.append(10); 235 | otherList.append(11); 236 | otherList.append(12); 237 | list.append(otherList); 238 | ASSERT(list.size() == 3); 239 | List::Iterator i = list.begin(); 240 | ASSERT(*i == 10); 241 | ASSERT(*(++i) == 11); 242 | ASSERT(*(++i) == 12); 243 | ASSERT(++i == list.end()); 244 | } 245 | } 246 | 247 | int main(int argc, char* argv[]) 248 | { 249 | testList(); 250 | return 0; 251 | } 252 | -------------------------------------------------------------------------------- /test/UnitTest/TestLog.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testLogf() 6 | { 7 | char buf[512 + 1]; 8 | Memory::fill(buf, 'a', 512); 9 | buf[512] = '\0'; 10 | Log::logf(Log::info, "%s%s", "bbb", buf); 11 | } 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | testLogf(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/UnitTest/TestMap.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void testMap() 8 | { 9 | // test insert 10 | { 11 | Map map; 12 | ASSERT(map.isEmpty()); 13 | ASSERT(map.size() == 0); 14 | ASSERT(map.begin() == map.end()); 15 | map.insert("000", 0); 16 | ASSERT(map.begin() != map.end()); 17 | Map::Iterator begin = map.begin(); 18 | ASSERT(++begin == map.end()); 19 | for(int i = 1; i < 90; ++i) 20 | { 21 | String item; 22 | item.printf("%03d", i); 23 | map.insert(item, i); 24 | } 25 | for(int i = 90; i < 100; ++i) 26 | { 27 | String item; 28 | item.printf("%03d", i); 29 | map.insert(map.end(), item, i); 30 | } 31 | ASSERT(!map.isEmpty()); 32 | ASSERT(map.size() == 100); 33 | int i = 0; 34 | for(Map::Iterator j = map.begin(), end = map.end(); j != end; ++j, ++i) 35 | { 36 | String item; 37 | item.printf("%03d", i); 38 | ASSERT(j.key() == item); 39 | ASSERT(*j == i); 40 | } 41 | for(int i = 0; i < 100; i += 10) 42 | { 43 | String item; 44 | item.printf("%03d", i); 45 | map.insert(item, i); 46 | } 47 | for(int i = 4; i < 20; i += 10) 48 | { 49 | String item2; 50 | item2.printf("%03d", 99 - i); 51 | Map::Iterator testInsertPos = map.find(item2); 52 | String item; 53 | item.printf("%03d", i); 54 | map.insert(testInsertPos, item, i); 55 | } 56 | for(int i = 3; i < 100; i += 10) 57 | { 58 | String item2; 59 | item2.printf("%03d", i); 60 | Map::Iterator testInsertPos = map.find(item2); 61 | String item; 62 | item.printf("%03d", i); 63 | map.insert(testInsertPos, item, i); 64 | } 65 | for(int i = 6; i < 100; i += 10) 66 | { 67 | String item2; 68 | item2.printf("%03d", i - 5); 69 | Map::Iterator testInsertPos = map.find(item2); 70 | String item; 71 | item.printf("%03d", i); 72 | map.insert(testInsertPos, item, i); 73 | } 74 | String lastKey = map.begin().key(); 75 | int lastValue = *map.begin(); 76 | for(Map::Iterator k = ++Map::Iterator(map.begin()), end = map.end(); k != end; ++k) 77 | { 78 | ASSERT(k.key() > lastKey); 79 | ASSERT(*k > lastValue); 80 | lastKey = k.key(); 81 | lastValue = *k; 82 | } 83 | map.remove("042"); 84 | } 85 | 86 | // test random insert and remove 87 | { 88 | Map map; 89 | for(int i = 0; i < 10000; ++i) 90 | { 91 | Map::Iterator testInsertPos = map.find(Math::random() % 100); 92 | map.insert(testInsertPos, i % 100, 123); 93 | } 94 | int lastKey = map.begin().key(); 95 | for(Map::Iterator k = ++Map::Iterator(map.begin()), end = map.end(); k != end; ++k) 96 | { 97 | ASSERT(k.key() > lastKey); 98 | lastKey = k.key(); 99 | } 100 | int item; 101 | for(int i = 0; i < 5000; ++i) 102 | { 103 | Map::Iterator testRmPos = map.find(Math::random() % 100); 104 | if (testRmPos != map.end()) 105 | map.remove(testRmPos); 106 | item = Math::random() % 100; 107 | map.insert(item, 123); 108 | } 109 | lastKey = map.begin().key(); 110 | usize count = 1; 111 | for(Map::Iterator k = ++Map::Iterator(map.begin()), end = map.end(); k != end; ++k) 112 | { 113 | ASSERT(k.key() > lastKey); 114 | lastKey = k.key(); 115 | ++count; 116 | } 117 | ASSERT(count == map.size()); 118 | for(Map::Iterator i = map.begin(), end = map.end(); i != end; ++i) 119 | { 120 | ASSERT(map.find(i.key()) != map.end()); 121 | } 122 | } 123 | 124 | // test clear 125 | { 126 | Map map; 127 | map.insert(1, false); 128 | ASSERT(map.size() == 1); 129 | map.clear(); 130 | ASSERT(map.size() == 0); 131 | map.insert(1, false); 132 | ASSERT(map.size() == 1); 133 | ASSERT(++map.begin() == map.end()); 134 | } 135 | 136 | // inserting another map 137 | { 138 | Map map; 139 | map.insert(1, false); 140 | Map map2; 141 | map.insert(-1, false); 142 | map.insert(2, false); 143 | map.insert(3, false); 144 | map.insert(map2); 145 | ASSERT(map.size() == 4); 146 | } 147 | } 148 | 149 | int main(int argc, char* argv[]) 150 | { 151 | testMap(); 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /test/UnitTest/TestMonitor.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void testWait() 8 | { 9 | // test wait with timeout - running into a timeout 10 | { 11 | Monitor monitor; 12 | { 13 | Monitor::Guard guard(monitor); 14 | ASSERT(!guard.wait(20)); 15 | } 16 | } 17 | 18 | // test wait with timeout - not running into a timeout 19 | struct SetMonitorProcData 20 | { 21 | static uint threadProc(void* param) 22 | { 23 | SetMonitorProcData* data = (SetMonitorProcData*)param; 24 | data->setSignal.wait(); 25 | data->monitor->set(); 26 | return 0; 27 | } 28 | Signal setSignal; 29 | Monitor* monitor; 30 | }; 31 | 32 | { 33 | Thread thread; 34 | SetMonitorProcData data; 35 | Monitor monitor; 36 | data.monitor = &monitor; 37 | thread.start(SetMonitorProcData::threadProc, &data); 38 | 39 | { 40 | Monitor::Guard guard(monitor); 41 | data.setSignal.set(); 42 | ASSERT(guard.wait(2000)); 43 | } 44 | } 45 | 46 | // test wait without timeout 47 | { 48 | Thread thread; 49 | SetMonitorProcData data; 50 | Monitor monitor; 51 | data.monitor = &monitor; 52 | thread.start(SetMonitorProcData::threadProc, &data); 53 | 54 | { 55 | Monitor::Guard guard(monitor); 56 | data.setSignal.set(); 57 | ASSERT(guard.wait()); 58 | } 59 | } 60 | } 61 | 62 | int main(int argc, char* argv[]) 63 | { 64 | testWait(); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /test/UnitTest/TestMultiMap.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testMultiMap() 6 | { 7 | // test insert 8 | { 9 | MultiMap map; 10 | map.insert(1, false); 11 | map.insert(2, false); 12 | map.insert(2, false); 13 | map.insert(3, false); 14 | ASSERT(map.count(1) == 1); 15 | ASSERT(map.count(2) == 2); 16 | ASSERT(map.count(3) == 1); 17 | ASSERT(map.count(4) == 0); 18 | } 19 | 20 | // test clear 21 | { 22 | MultiMap map; 23 | map.insert(1, false); 24 | ASSERT(map.size() == 1); 25 | map.clear(); 26 | ASSERT(map.size() == 0); 27 | map.insert(1, false); 28 | ASSERT(map.size() == 1); 29 | ASSERT(++map.begin() == map.end()); 30 | } 31 | } 32 | 33 | int main(int argc, char* argv[]) 34 | { 35 | testMultiMap(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /test/UnitTest/TestMutex.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testMutex() 6 | { 7 | // test recursion 8 | { 9 | Mutex mutex; 10 | Mutex::Guard guard1(mutex); 11 | Mutex::Guard guard2(mutex); 12 | } 13 | } 14 | 15 | int main(int argc, char* argv[]) 16 | { 17 | testMutex(); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/UnitTest/TestPoolList.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | struct TestObject 6 | { 7 | int _a; 8 | 9 | TestObject() {} 10 | 11 | TestObject(int a) : _a(a) {} 12 | 13 | private: 14 | TestObject(const TestObject&); 15 | TestObject& operator=(const TestObject&); 16 | }; 17 | 18 | void testAppendAndRemove() 19 | { 20 | PoolList pool; 21 | TestObject& obj = pool.append(); 22 | ASSERT(pool.size() == 1); 23 | pool.remove(obj); 24 | ASSERT(pool.size() == 0); 25 | } 26 | 27 | void testClear() 28 | { 29 | PoolList pool; 30 | pool.append(); 31 | pool.append(); 32 | pool.append(); 33 | ASSERT(pool.size() == 3); 34 | pool.clear(); 35 | ASSERT(pool.size() == 0); 36 | } 37 | 38 | void testSwap() 39 | { 40 | PoolList pool; 41 | pool.append(); 42 | pool.append(); 43 | PoolList pool2; 44 | pool.swap(pool2); 45 | ASSERT(pool.size() == 0); 46 | ASSERT(pool2.size() == 2); 47 | } 48 | 49 | void testConstructorArgs() 50 | { 51 | PoolList pool; 52 | pool.append(32); 53 | ASSERT(pool.begin()->_a == 32); 54 | } 55 | 56 | void testNoDefaultConstructor() 57 | { 58 | struct TestObject2 59 | { 60 | int _a; 61 | 62 | TestObject2(int a) : _a(a) {} 63 | 64 | private: 65 | TestObject2() {} 66 | TestObject2(const TestObject2&) {} 67 | TestObject2& operator=(const TestObject2&) {return *this;} 68 | }; 69 | 70 | PoolList pool; 71 | pool.append(32); 72 | ASSERT(pool.begin()->_a == 32); 73 | } 74 | 75 | int main(int argc, char* argv[]) 76 | { 77 | testAppendAndRemove(); 78 | testClear(); 79 | testSwap(); 80 | testConstructorArgs(); 81 | testNoDefaultConstructor(); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /test/UnitTest/TestPoolMap.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | struct TestObject 7 | { 8 | int a; 9 | 10 | TestObject() {} 11 | 12 | private: 13 | TestObject(const TestObject&); 14 | TestObject& operator=(const TestObject&); 15 | }; 16 | 17 | void testPoolMap() 18 | { 19 | // test append and remove 20 | PoolMap pool; 21 | TestObject& obj = pool.append("object1"); 22 | ASSERT(pool.size() == 1); 23 | pool.remove(obj); 24 | ASSERT(pool.size() == 0); 25 | 26 | // test clear 27 | pool.clear(); 28 | pool.append("object1"); 29 | pool.append("object2"); 30 | pool.append("object3"); 31 | ASSERT(pool.size() == 3); 32 | pool.clear(); 33 | ASSERT(pool.size() == 0); 34 | 35 | // test swap 36 | pool.clear(); 37 | pool.append("object1"); 38 | pool.append("object2"); 39 | PoolMap pool2; 40 | pool.swap(pool2); 41 | ASSERT(pool.size() == 0); 42 | ASSERT(pool2.size() == 2); 43 | } 44 | 45 | int main(int argc, char* argv[]) 46 | { 47 | testPoolMap(); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /test/UnitTest/TestProcess.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void testProcess() 8 | { 9 | // test start() and join() 10 | { 11 | Process process; 12 | #ifdef _WIN32 13 | uint32 id = process.start("cmd /C \"choice /T 1 /D N >NUL\""); 14 | #else 15 | uint32 id = process.start("sleep 1"); 16 | #endif 17 | ASSERT(id != 0); 18 | ASSERT(process.isRunning()); 19 | uint32 exitCode = 0xfffa2; 20 | ASSERT(process.join(exitCode)); 21 | ASSERT(!process.isRunning()); 22 | #ifdef _WIN32 23 | ASSERT(exitCode == 2 || exitCode == 255); 24 | #else 25 | ASSERT(exitCode == 0); 26 | #endif 27 | } 28 | 29 | // test open(), read() and join() 30 | { 31 | Process process; 32 | #ifdef _WIN32 33 | ASSERT(process.open("cmd /C echo 123", Process::stdoutStream)); 34 | #else 35 | ASSERT(process.open("ls", Process::stdoutStream)); 36 | #endif 37 | ASSERT(process.isRunning()); 38 | char buffer[123]; 39 | ASSERT(process.read(buffer, sizeof(buffer)) > 0); 40 | uint32 exitCode = 0xfffa2; 41 | ASSERT(process.join(exitCode)); 42 | ASSERT(!process.isRunning()); 43 | ASSERT(exitCode == 0); 44 | } 45 | 46 | // test wait and interrupt 47 | { 48 | Process::interrupt(); 49 | Process* processes[1]; 50 | int64 start = Time::ticks(); 51 | ASSERT(Process::wait(processes, 0) == 0); 52 | int64 waitDuration = Time::ticks() - start; 53 | ASSERT(waitDuration < 10); 54 | } 55 | { 56 | struct InterrupterThread 57 | { 58 | static uint32 proc(void*) 59 | { 60 | Thread::sleep(50); 61 | Process::interrupt(); 62 | return 0; 63 | } 64 | }; 65 | Thread thread; 66 | thread.start(InterrupterThread::proc, 0); 67 | Process* processes[1]; 68 | int64 start = Time::ticks(); 69 | ASSERT(Process::wait(processes, 0) == 0); 70 | int64 waitDuration = Time::ticks() - start; 71 | ASSERT(waitDuration > 20); 72 | } 73 | } 74 | 75 | void testWait() 76 | { 77 | Process process; 78 | Process process2; 79 | #ifdef _WIN32 80 | ASSERT(process.open("cmd /C echo 123") != 0); 81 | ASSERT(process2.start("cmd /C \"choice /T 1 /D N >NUL\"") != 0); 82 | #else 83 | ASSERT(process.open("ls") != 0); 84 | ASSERT(process2.start("sleep 1") != 0); 85 | #endif 86 | Process* processes[] = {&process2, &process}; 87 | ASSERT(Process::wait(processes, 2) == &process); 88 | uint32 exitCode; 89 | ASSERT(process.join(exitCode)); 90 | ASSERT(exitCode == 0); 91 | ASSERT(Process::wait(processes, 1) == &process2); 92 | ASSERT(process2.join(exitCode)); 93 | #ifdef _WIN32 94 | ASSERT(exitCode == 2); 95 | #else 96 | ASSERT(exitCode == 0); 97 | #endif 98 | } 99 | 100 | void testStartEnv() 101 | { 102 | Process process; 103 | Map env; 104 | env.insert("ENV_TEST", "42"); 105 | #ifdef _WIN32 106 | process.start("cmd /c \"exit %ENV_TEST%\"", env); 107 | #else 108 | process.start("sh -c \"exit $ENV_TEST\"", env); 109 | #endif 110 | uint32 exitCode = 0; 111 | process.join(exitCode); 112 | ASSERT(exitCode == 42); 113 | } 114 | 115 | void testOpenEnv() 116 | { 117 | Process process; 118 | Map env; 119 | env.insert("ENV_TEST", "42"); 120 | #ifdef _WIN32 121 | process.start("cmd /c \"exit %ENV_TEST%\"", env); 122 | #else 123 | process.start("sh -c \"exit $ENV_TEST\"", env); 124 | #endif 125 | uint32 exitCode = 0; 126 | process.join(exitCode); 127 | ASSERT(exitCode == 42); 128 | } 129 | 130 | void testGetEnvironmentVariables() 131 | { 132 | Map envs = Process::getEnvironmentVariables(); 133 | Map::Iterator testVar; 134 | #ifdef _WIN32 135 | testVar = envs.find("Path"); 136 | #else 137 | testVar = envs.find("HOME"); 138 | #endif 139 | ASSERT(testVar != envs.end()); 140 | ASSERT(!String::find(*testVar, '=')); 141 | } 142 | 143 | int main(int argc, char* argv[]) 144 | { 145 | testProcess(); 146 | testWait(); 147 | testStartEnv(); 148 | testOpenEnv(); 149 | testGetEnvironmentVariables(); 150 | return 0; 151 | } 152 | -------------------------------------------------------------------------------- /test/UnitTest/TestRefCount.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testRefCount() 6 | { 7 | static int count = 0; 8 | 9 | class TestObject : public RefCount::Object 10 | { 11 | public: 12 | TestObject() {++count;} 13 | ~TestObject() {--count;} 14 | }; 15 | 16 | // test construction and destruction 17 | { 18 | RefCount::Ptr ptr = new TestObject; 19 | ASSERT(count == 1); 20 | } 21 | ASSERT(count == 0); 22 | 23 | // test copy constructor 24 | { 25 | RefCount::Ptr ptr3; 26 | RefCount::Ptr ptr = new TestObject; 27 | ASSERT(ptr != ptr3); 28 | RefCount::Ptr ptr2(ptr); 29 | ASSERT(ptr == ptr2); 30 | ptr3 = ptr2; 31 | ASSERT(ptr == ptr3); 32 | ASSERT(count == 1); 33 | } 34 | ASSERT(count == 0); 35 | 36 | } 37 | 38 | int main(int argc, char* argv[]) 39 | { 40 | testRefCount(); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/UnitTest/TestSemaphore.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testSempahore() 7 | { 8 | Semaphore sem(3); 9 | sem.signal(); 10 | ASSERT(sem.wait()); 11 | ASSERT(sem.wait()); 12 | ASSERT(sem.wait()); 13 | ASSERT(sem.wait()); 14 | ASSERT(!sem.tryWait()); 15 | int64 start = Time::ticks(); 16 | ASSERT(!sem.wait(300)); 17 | int64 waitTime = Time::ticks() - start; 18 | ASSERT(waitTime > 200); 19 | } 20 | 21 | int main(int argc, char* argv[]) 22 | { 23 | testSempahore(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/UnitTest/TestSha256.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testSha256() 6 | { 7 | byte check1[Sha256::digestSize] = { 8 | 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 9 | }; 10 | byte checksum[Sha256::digestSize]; 11 | Sha256::hash((const byte*)"", 0, checksum); 12 | ASSERT(Memory::compare(checksum, check1, sizeof(check1)) == 0); 13 | byte check2[Sha256::digestSize] = { 14 | 0x5c, 0x93, 0x0f, 0xbe, 0x6a, 0x4d, 0x8d, 0x87, 0xd8, 0x98, 0x5b, 0x2d, 0x28, 0xad, 0x6b, 0x30, 0xa9, 0xba, 0x93, 0xfb, 0x05, 0x7e, 0x14, 0x9c, 0x96, 0xca, 0x82, 0x6d, 0xe7, 0x7a, 0x50, 0xa8 15 | }; 16 | Sha256::hash((const byte*)"But First, We Need to Talk About Parallel Universes", 51, checksum); 17 | ASSERT(Memory::compare(checksum, check2, sizeof(check2)) == 0); 18 | } 19 | 20 | int main(int argc, char* argv[]) 21 | { 22 | testSha256(); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/UnitTest/TestSignal.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testSignal() 7 | { 8 | // test wait with timeout - running into a timeout 9 | { 10 | Signal signal; 11 | ASSERT(!signal.wait(20)); 12 | } 13 | 14 | // test wait with timeout - not running into a timeout 15 | struct SetSignalProcData 16 | { 17 | static uint threadProc(void* param) 18 | { 19 | SetSignalProcData* data = (SetSignalProcData*)param; 20 | data->setSignal.wait(); 21 | data->testSignal->set(); 22 | return 0; 23 | } 24 | Signal setSignal; 25 | Signal* testSignal; 26 | }; 27 | 28 | { 29 | Thread thread; 30 | SetSignalProcData data; 31 | Signal signal; 32 | data.testSignal = &signal; 33 | thread.start(SetSignalProcData::threadProc, &data); 34 | data.setSignal.set(); 35 | ASSERT(signal.wait(2000)); 36 | } 37 | 38 | // test wait without timeout 39 | { 40 | Thread thread; 41 | SetSignalProcData data; 42 | Signal signal; 43 | data.testSignal = &signal; 44 | thread.start(SetSignalProcData::threadProc, &data); 45 | data.setSignal.set(); 46 | ASSERT(signal.wait()); 47 | } 48 | } 49 | 50 | int main(int argc, char* argv[]) 51 | { 52 | testSignal(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /test/UnitTest/TestSocket.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testSocket() 6 | { 7 | // test listening twice on a udp port 8 | { 9 | byte testData[123] = {1, 2, 3}; 10 | byte rcvData[123]; 11 | Socket listener1; 12 | Socket listener2; 13 | Socket sender; 14 | ASSERT(listener1.open(Socket::udpProtocol)); 15 | ASSERT(listener2.open(Socket::udpProtocol)); 16 | ASSERT(sender.open(Socket::udpProtocol)); 17 | ASSERT(listener1.setReuseAddress()); 18 | ASSERT(listener2.setReuseAddress()); 19 | ASSERT(listener1.bind(Socket::anyAddress, 6212)); 20 | ASSERT(listener2.bind(Socket::anyAddress, 6212)); 21 | ASSERT(sender.bind(Socket::anyAddress, 0)); 22 | ASSERT(sender.setBroadcast()); 23 | ASSERT(sender.sendTo(testData, sizeof(testData), Socket::broadcastAddress, 6212) == sizeof(testData)); 24 | uint32 ip; 25 | uint16 port; 26 | ASSERT(listener1.recvFrom(rcvData, sizeof(rcvData), ip, port) == sizeof(rcvData)); 27 | ASSERT(Memory::compare(rcvData, testData, sizeof(rcvData)) == 0); 28 | ASSERT(listener2.recvFrom(rcvData, sizeof(rcvData), ip, port) == sizeof(rcvData)); 29 | ASSERT(Memory::compare(rcvData, testData, sizeof(rcvData)) == 0); 30 | } 31 | 32 | // test listening twice on a udp port with multicast 33 | { 34 | byte testData[123] = {1, 2, 3}; 35 | byte rcvData[123]; 36 | Socket listener1; 37 | Socket listener2; 38 | Socket sender; 39 | uint32 multicastAddr = Socket::inetAddr("226.1.2.3"); 40 | ASSERT(listener1.open(Socket::udpProtocol)); 41 | ASSERT(listener2.open(Socket::udpProtocol)); 42 | ASSERT(sender.open(Socket::udpProtocol)); 43 | ASSERT(listener1.setReuseAddress()); 44 | ASSERT(listener2.setReuseAddress()); 45 | ASSERT(listener1.bind(Socket::anyAddress, 6212)); 46 | ASSERT(listener2.bind(Socket::anyAddress, 6212)); 47 | ASSERT(listener1.joinMulticastGroup(multicastAddr)); 48 | ASSERT(listener2.joinMulticastGroup(multicastAddr)); 49 | ASSERT(sender.bind(Socket::anyAddress, 0)); 50 | ASSERT(sender.sendTo(testData, sizeof(testData), multicastAddr, 6212) == sizeof(testData)); 51 | uint32 ip; 52 | uint16 port; 53 | ASSERT(listener1.recvFrom(rcvData, sizeof(rcvData), ip, port) == sizeof(rcvData)); 54 | ASSERT(Memory::compare(rcvData, testData, sizeof(rcvData)) == 0); 55 | ASSERT(listener2.recvFrom(rcvData, sizeof(rcvData), ip, port) == sizeof(rcvData)); 56 | ASSERT(Memory::compare(rcvData, testData, sizeof(rcvData)) == 0); 57 | } 58 | 59 | // test poll with udp socket 60 | { 61 | byte testData[123] = {1, 2, 3}; 62 | byte rcvData[123]; 63 | Socket listener1; 64 | Socket sender; 65 | uint32 multicastAddr = Socket::inetAddr("226.1.2.3"); 66 | ASSERT(listener1.open(Socket::udpProtocol)); 67 | ASSERT(sender.open(Socket::udpProtocol)); 68 | ASSERT(listener1.setReuseAddress()); 69 | ASSERT(listener1.bind(Socket::anyAddress, 6212)); 70 | ASSERT(listener1.joinMulticastGroup(multicastAddr)); 71 | ASSERT(sender.bind(Socket::anyAddress, 0)); 72 | ASSERT(sender.sendTo(testData, sizeof(testData), multicastAddr, 6212) == sizeof(testData)); 73 | uint32 ip; 74 | uint16 port; 75 | Socket::Poll poll; 76 | poll.set(listener1, Socket::Poll::readFlag); 77 | Socket::Poll::Event event; 78 | ASSERT(poll.poll(event, 1000)); 79 | ASSERT(event.flags == Socket::Poll::readFlag); 80 | ASSERT(event.socket == &listener1); 81 | ASSERT(listener1.recvFrom(rcvData, sizeof(rcvData), ip, port) == sizeof(rcvData)); 82 | ASSERT(Memory::compare(rcvData, testData, sizeof(rcvData)) == 0); 83 | } 84 | 85 | // test poll with udp socket 2 86 | { 87 | byte testData[123] = {1, 2, 3}; 88 | byte rcvData[123]; 89 | Socket listener1; 90 | Socket sender; 91 | uint32 multicastAddr = Socket::inetAddr("226.1.2.3"); 92 | ASSERT(listener1.open(Socket::udpProtocol)); 93 | ASSERT(sender.open(Socket::udpProtocol)); 94 | ASSERT(listener1.setReuseAddress()); 95 | ASSERT(listener1.bind(Socket::anyAddress, 6212)); 96 | ASSERT(listener1.joinMulticastGroup(multicastAddr)); 97 | ASSERT(sender.bind(Socket::anyAddress, 0)); 98 | uint32 ip; 99 | uint16 port; 100 | Socket::Poll poll; 101 | poll.set(listener1, Socket::Poll::readFlag); 102 | Socket::Poll::Event event; 103 | ASSERT(sender.sendTo(testData, sizeof(testData), multicastAddr, 6212) == sizeof(testData)); 104 | ASSERT(poll.poll(event, 1000)); 105 | ASSERT(event.flags == Socket::Poll::readFlag); 106 | ASSERT(event.socket == &listener1); 107 | ASSERT(listener1.recvFrom(rcvData, sizeof(rcvData), ip, port) == sizeof(rcvData)); 108 | ASSERT(Memory::compare(rcvData, testData, sizeof(rcvData)) == 0); 109 | } 110 | 111 | // test inetNtoA 112 | { 113 | ASSERT(Socket::inetNtoA(Socket::loopbackAddress) == "127.0.0.1"); 114 | } 115 | 116 | // test getHostByName 117 | { 118 | uint32 addr = 0; 119 | ASSERT(Socket::getHostByName(Socket::getHostName(), addr)); 120 | ASSERT(addr != 0); 121 | } 122 | } 123 | 124 | void testInetAddr() 125 | { 126 | ASSERT(Socket::inetAddr(Socket::getHostName()) == Socket::broadcastAddress); 127 | } 128 | 129 | int main(int argc, char* argv[]) 130 | { 131 | testSocket(); 132 | testInetAddr(); 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /test/UnitTest/TestString.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | void testString() 9 | { 10 | // test constructors 11 | String empty; 12 | ASSERT(empty.isEmpty()); 13 | String hello("hello"); 14 | ASSERT(!hello.isEmpty()); 15 | String copyOfHello(hello); 16 | ASSERT(!copyOfHello.isEmpty()); 17 | String copyOfCopyOfHello(copyOfHello); 18 | ASSERT(!copyOfCopyOfHello.isEmpty()); 19 | 20 | // test assignment operator 21 | { 22 | String x(copyOfCopyOfHello); 23 | x = copyOfHello; 24 | x = String("omg"); 25 | String y("omg"); 26 | y = y; 27 | } 28 | 29 | // test comparison 30 | ASSERT(String("123").compare("123") == 0); 31 | ASSERT(String("123").compare("xxx") != 0); 32 | ASSERT(String("1234").compare("123", 3) == 0); 33 | ASSERT(String("1234").compare("xxx", 3) != 0); 34 | ASSERT(String("123").compare("1234", 3) == 0); 35 | ASSERT(String("xxx").compare("1234", 3) != 0); 36 | 37 | // test ignore case comparison 38 | ASSERT(String("abc").compareIgnoreCase("ABC") == 0); 39 | ASSERT(String("abc").compareIgnoreCase("xxx") != 0); 40 | ASSERT(String("abcd").compareIgnoreCase("ABC", 3) == 0); 41 | ASSERT(String("abcd").compareIgnoreCase("xxx", 3) != 0); 42 | ASSERT(String("abc").compareIgnoreCase("ABCD", 3) == 0); 43 | ASSERT(String("xxx").compareIgnoreCase("ABCD", 3) != 0); 44 | 45 | // test self assign 46 | String blupp; 47 | blupp.printf("%d", 123); 48 | blupp = blupp; 49 | ASSERT(blupp == "123"); 50 | 51 | // test compare operators 52 | ASSERT(hello == copyOfCopyOfHello); 53 | ASSERT(copyOfHello == copyOfCopyOfHello); 54 | ASSERT(hello == copyOfCopyOfHello); 55 | ASSERT(hello != empty); 56 | ASSERT(copyOfHello != empty); 57 | ASSERT(copyOfCopyOfHello != empty); 58 | ASSERT(!(hello == empty)); 59 | ASSERT(!(copyOfHello == empty)); 60 | ASSERT(!(copyOfCopyOfHello == empty)); 61 | 62 | // test clear 63 | copyOfHello.clear(); 64 | ASSERT(copyOfHello.isEmpty()); 65 | 66 | // test toUpperCase, toLowerCase, isSpace 67 | for (int i = 0; i < 0x100; ++i) 68 | { 69 | ASSERT(String::toUpperCase((char)i) == (char)toupper((uchar&)i)); 70 | ASSERT(String::toLowerCase((char)i) == (char)tolower((uchar&)i)); 71 | ASSERT(String::isSpace((char)i) == !!isspace((uchar&)i)); 72 | } 73 | 74 | // test static length 75 | ASSERT(String::length("") == 0); 76 | ASSERT(String::length("123") == 3); 77 | 78 | // test find methods 79 | String test("this is the find test test string"); 80 | ASSERT(test.find('z') == 0); 81 | ASSERT(test.find("zz") == 0); 82 | ASSERT(String::compare(test.find('i'), "is is the find test test string") == 0); 83 | ASSERT(String::compare(test.findLast('i'), "ing") == 0); 84 | ASSERT(String::compare(test.find("is"), "is is the find test test string") == 0); 85 | ASSERT(String::compare(test.findLast("is"), "is the find test test string") == 0); 86 | ASSERT(String::compare(test.findOneOf("ex"), "e find test test string") == 0); 87 | ASSERT(String::compare(test.findOneOf("xe"), "e find test test string") == 0); 88 | ASSERT(String::compare(test.findLastOf("ex"), "est string") == 0); 89 | ASSERT(String::compare(test.findLastOf("xe"), "est string") == 0); 90 | 91 | // test prepend, append 92 | String b(" b "); 93 | String a("aa"); 94 | String c("cc"); 95 | ASSERT(a + b + c == "aa b cc"); 96 | ASSERT(String().append(a).append(b).append(c) == "aa b cc"); 97 | ASSERT(String().append(b).prepend(a).append(c) == "aa b cc"); 98 | 99 | // test if lazy copying 100 | struct LazyCopyTest 101 | { 102 | static String test1() 103 | { 104 | return String("test"); 105 | } 106 | }; 107 | String aa = LazyCopyTest::test1(); // so, this is equal to "String aa("test")"? 108 | const char* caa = aa; 109 | ASSERT(caa != (char*)aa); 110 | 111 | // test external buffer attaching 112 | char buf[100]; 113 | for(char* i = buf; i < buf + 8; ++i) 114 | *i = 'a'; 115 | String bufWrapper; 116 | bufWrapper.attach(buf, 4); 117 | ASSERT(bufWrapper == String(buf, 4)); 118 | ASSERT(bufWrapper == String("aaaa")); 119 | 120 | // test detach 121 | { 122 | char buf[100]; 123 | for(usize i = 0; i < 8; ++i) 124 | buf[i] = 'a'; 125 | String bufWrapper; 126 | buf[8] = '\0'; 127 | bufWrapper.attach(buf, 8); 128 | bufWrapper.detach(); 129 | buf[2] = 'b'; 130 | ASSERT(bufWrapper == "aaaaaaaa"); 131 | } 132 | 133 | // test trim 134 | ASSERT(String().trim() == String()); 135 | ASSERT(String("\t \n\t \n").trim() == String()); 136 | ASSERT(String("\t \nx\t \n").trim() == "x"); 137 | ASSERT(String("x\t \n").trim() == "x"); 138 | ASSERT(String("\t \nx").trim() == "x"); 139 | ASSERT(String("x").trim() == "x"); 140 | 141 | // test toBool 142 | ASSERT(!String().toBool()); 143 | ASSERT(!String("").toBool()); 144 | ASSERT(!String("0").toBool()); 145 | ASSERT(!String("false").toBool()); 146 | ASSERT(!String("False").toBool()); 147 | ASSERT(!String("falSe").toBool()); 148 | ASSERT(!String("0.0").toBool()); 149 | ASSERT(!String(".0").toBool()); 150 | ASSERT(!String("0.").toBool()); 151 | ASSERT(!String(".00").toBool()); 152 | ASSERT(!String("00.").toBool()); 153 | ASSERT(!String("00.00").toBool()); 154 | ASSERT(!String("0.00").toBool()); 155 | ASSERT(!String("00.0").toBool()); 156 | ASSERT(String(".").toBool()); 157 | ASSERT(String("dasdas").toBool()); 158 | ASSERT(String("true").toBool()); 159 | 160 | // test join 161 | { 162 | String str; 163 | ASSERT(str.join(List(), '.') == String()); 164 | } 165 | } 166 | 167 | void testPrintf() 168 | { 169 | String hello("hello"); 170 | String empty; 171 | empty.printf("%s %s", (const char*)hello, "world"); 172 | ASSERT(empty == "hello world"); 173 | ASSERT(empty != "hello worl2"); 174 | ASSERT(empty != "hello worl2a"); 175 | char buf[512 + 1]; 176 | Memory::fill(buf, 'b', 3); 177 | Memory::fill(buf + 3, 'a', 512 - 3); 178 | buf[512] = '\0'; 179 | empty.printf("%s%s", "bbb", buf + 3); 180 | ASSERT(empty == buf); 181 | } 182 | 183 | void testBase64() 184 | { 185 | ASSERT(String::fromBase64("bGlnaHQgd29yay4=") == "light work."); 186 | ASSERT(String::fromBase64("bGlnaHQgd29yaw==") == "light work"); 187 | ASSERT(String::fromBase64("bGlnaHQgd29y") == "light wor"); 188 | ASSERT(String::fromBase64("bGlnaHQgd28=") == "light wo"); 189 | ASSERT(String::fromBase64("bGlnaHQgdw==") == "light w"); 190 | } 191 | 192 | int main(int argc, char* argv[]) 193 | { 194 | testString(); 195 | testPrintf(); 196 | testBase64(); 197 | return 0; 198 | } 199 | -------------------------------------------------------------------------------- /test/UnitTest/TestThread.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testThread() 7 | { 8 | // test start and join 9 | { 10 | struct ThreadData 11 | { 12 | static uint proc(void* args) 13 | { 14 | ThreadData& threadData = *(ThreadData*)args; 15 | 16 | ASSERT(threadData.intParam == 123); 17 | for (int i = 0; i < 10000; ++i) 18 | { 19 | Atomic::increment(threadData.counter); 20 | Thread::yield(); 21 | } 22 | return 42; 23 | } 24 | uint intParam; 25 | volatile uint counter; 26 | } threadData; 27 | threadData.intParam = 123; 28 | threadData.counter = 0; 29 | 30 | Thread thread; 31 | Thread thread2; 32 | Thread thread3; 33 | ASSERT(thread.start(ThreadData::proc, &threadData)); 34 | ASSERT(thread2.start(ThreadData::proc, &threadData)); 35 | ASSERT(thread3.start(ThreadData::proc, &threadData)); 36 | ASSERT(thread.join() == 42); 37 | ASSERT(thread.start(ThreadData::proc, &threadData)); 38 | ASSERT(thread.join() == 42); 39 | ASSERT(thread2.join() == 42); 40 | ASSERT(thread3.join() == 42); 41 | ASSERT(threadData.counter == 4 * 10000); 42 | } 43 | 44 | // test member function start 45 | { 46 | struct ThreadData 47 | { 48 | public: 49 | uint proc() 50 | { 51 | return 42; 52 | } 53 | uint counter; 54 | } threadData; 55 | Thread thread; 56 | threadData.counter = 0; 57 | ASSERT(thread.start(threadData, &ThreadData::proc)); 58 | ASSERT(thread.join() == 42); 59 | } 60 | } 61 | 62 | int main(int argc, char* argv[]) 63 | { 64 | testThread(); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /test/UnitTest/TestTime.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void testTime() 7 | { 8 | String test = Time::toString(123 * 1000, "%Y-%m-%d %H:%M:%S", true); 9 | ASSERT(test == "1970-01-01 00:02:03"); 10 | 11 | { 12 | Time time(123LL * 1000, true); 13 | ASSERT(time.toString("%Y-%m-%d %H:%M:%S") == test); 14 | ASSERT(time.year == 1970); 15 | ASSERT(time.month == 1); 16 | ASSERT(time.day == 1); 17 | ASSERT(time.hour == 0); 18 | ASSERT(time.min == 2); 19 | ASSERT(time.sec == 3); 20 | } 21 | 22 | int64 now = Time::time(); 23 | Time time(now); 24 | ASSERT(time.toTimestamp() == now); 25 | Time time2(time); 26 | time2.toLocal(); 27 | ASSERT(time == time2); 28 | ASSERT(time2.toTimestamp() == now); 29 | 30 | Time timeUtc(time); 31 | timeUtc.toUtc(); 32 | ASSERT(timeUtc != time); 33 | ASSERT(timeUtc.toTimestamp() == now); 34 | Time timeUtc2(timeUtc); 35 | timeUtc2.toUtc(); 36 | ASSERT(timeUtc != time); 37 | ASSERT(timeUtc2 == timeUtc); 38 | ASSERT(timeUtc2.toTimestamp() == now); 39 | } 40 | 41 | int main(int argc, char* argv[]) 42 | { 43 | testTime(); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/UnitTest/TestUnicode.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testUnicode() 6 | { 7 | String str; 8 | ASSERT(!Unicode::append(0x110000ULL, str)); 9 | for(uint32 i = 0; i < 0x110000ULL; i += 100) 10 | { 11 | #ifdef _UNICODE 12 | if(i >= 0xD800 && i <= 0xDFFF) 13 | continue; 14 | #endif 15 | str.clear(); 16 | ASSERT(Unicode::append(i, str)); 17 | ASSERT(Unicode::isValid(str)); 18 | ASSERT(Unicode::fromString(str) == i); 19 | } 20 | } 21 | 22 | int main(int argc, char* argv[]) 23 | { 24 | testUnicode(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/UnitTest/TestVariant.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testVariant() 6 | { 7 | // test default constructor 8 | { 9 | Variant var; 10 | ASSERT(var.isNull()); 11 | ASSERT(var.toBool() == false); 12 | } 13 | 14 | // test self assign 15 | { 16 | Variant var(String("hallo")); 17 | ASSERT(var.toString() == "hallo"); 18 | var = var; 19 | ASSERT(var.toString() == "hallo"); 20 | 21 | Variant var2(123); 22 | ASSERT(var2.toInt() == 123); 23 | var2 = var2; 24 | ASSERT(var2.toInt() == 123); 25 | } 26 | 27 | // test boolean constructor 28 | { 29 | Variant var(true); 30 | ASSERT(var.toBool() == true); 31 | } 32 | 33 | // test map constructor 34 | { 35 | HashMap map; 36 | map.append("dasd", Variant(String("yes"))); 37 | Variant var(map); 38 | ASSERT(((const Variant&)var).toMap().find("dasd")->toString() == "yes"); 39 | ASSERT(var.toMap().find("dasd")->toString() == "yes"); 40 | } 41 | 42 | // test copy construction of null variant 43 | { 44 | Variant null; 45 | ASSERT(null.isNull()); 46 | Variant copy(null); 47 | ASSERT(copy.isNull()); 48 | } 49 | 50 | // test list detaching 51 | { 52 | Variant var1; 53 | var1.toList().append(123); 54 | Variant var2(var1); 55 | List& var2list = var2.toList(); 56 | ASSERT(var2list.size() == 1); 57 | var2list.clear(); 58 | ASSERT(((const Variant&)var1).toList().size() == 1); 59 | } 60 | } 61 | 62 | int main(int argc, char* argv[]) 63 | { 64 | testVariant(); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /test/UnitTest/TestXml.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void testXml() 6 | { 7 | Xml::Parser parser; 8 | Xml::Element element; 9 | String input("test&test#&#ToveJaniReminderDon't forget me this weekend!"); 10 | String expectedOutput("test&test#&#ToveJaniReminderDon't forget me this weekend!"); 11 | ASSERT(parser.parse(input, element)); 12 | ASSERT(element.type == "note"); 13 | ASSERT(!element.content.isEmpty()); 14 | ASSERT(element.content.front().toString() == "test&test#&#"); 15 | String output = element.toString(); 16 | ASSERT(output == expectedOutput); 17 | } 18 | 19 | void testXmlSyntaxError() 20 | { 21 | Xml::Parser parser; 22 | Xml::Element element; 23 | String input("