diff --git a/cbp/ModMMDB.cbp b/cbp/ModMMDB.cbp new file mode 100644 index 00000000..f8a57614 --- /dev/null +++ b/cbp/ModMMDB.cbp @@ -0,0 +1,407 @@ + + + + + + diff --git a/cbp/Module.cbp b/cbp/Module.cbp index 745f74ec..c3865803 100644 --- a/cbp/Module.cbp +++ b/cbp/Module.cbp @@ -362,6 +362,9 @@ + + + @@ -372,6 +375,7 @@ + @@ -387,7 +391,6 @@ - @@ -438,14 +441,14 @@ + + - - diff --git a/cbp/Sandbox.cbp b/cbp/Sandbox.cbp index 0e76327d..7567ee8d 100644 --- a/cbp/Sandbox.cbp +++ b/cbp/Sandbox.cbp @@ -149,6 +149,7 @@ + @@ -160,6 +161,7 @@ + diff --git a/cbp/default.workspace b/cbp/default.workspace index 09de101a..0d207ea8 100644 --- a/cbp/default.workspace +++ b/cbp/default.workspace @@ -8,6 +8,7 @@ + diff --git a/config/mingw32/maxminddb_config.h b/config/mingw32/maxminddb_config.h new file mode 100644 index 00000000..61bd5f3e --- /dev/null +++ b/config/mingw32/maxminddb_config.h @@ -0,0 +1,193 @@ +/* include/maxminddb_config.h. Generated from maxminddb_config.h.in by configure. */ +#ifndef MAXMINDDB_CONFIG_H +#define MAXMINDDB_CONFIG_H + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if the system has the type `boolean'. */ +/* #undef HAVE_BOOLEAN */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MATH_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have a working `mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Has an open_memstream() function */ +#define HAVE_OPEN_MEMSTREAM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Missing the unsigned __int128 type */ +#define MMDB_UINT128_IS_BYTE_ARRAY 1 + +/* int128 types are available with __attribute__((mode(TI))) */ +/* #undef MMDB_UINT128_USING_MODE */ + +/* Name of package */ +#define PACKAGE "libmaxminddb" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "support@maxmind.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libmaxminddb" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libmaxminddb 1.1.4" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libmaxminddb" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.4" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.1.4" + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#define restrict __restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ + +#ifndef MMDB_UINT128_USING_MODE +/* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */ +#define MMDB_UINT128_USING_MODE 0 +#endif + +#ifndef MMDB_UINT128_IS_BYTE_ARRAY +/* Define as 1 if we don't have an unsigned __int128 type */ +#define MMDB_UINT128_IS_BYTE_ARRAY 0 +#endif + +#endif /* MAXMINDDB_CONFIG_H */ diff --git a/external/Common/aes256.cpp b/external/Common/aes256.cpp new file mode 100644 index 00000000..e6d6582e --- /dev/null +++ b/external/Common/aes256.cpp @@ -0,0 +1,407 @@ +/* +* Byte-oriented AES-256 implementation. +* All lookup tables replaced with 'on the fly' calculations. +* +* Copyright (c) 2007-2011 Ilya O. Levin, http://www.literatecode.com +* Other contributors: Hal Finney +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#include "aes256.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FD(x) (((x) >> 1) ^ (((x) & 1) ? 0x8d : 0)) + +#define BACK_TO_TABLES + +static uint8_t rj_xtime(uint8_t); +static void aes_subBytes(uint8_t *); +static void aes_subBytes_inv(uint8_t *); +static void aes_addRoundKey(uint8_t *, uint8_t *); +static void aes_addRoundKey_cpy(uint8_t *, uint8_t *, uint8_t *); +static void aes_shiftRows(uint8_t *); +static void aes_shiftRows_inv(uint8_t *); +static void aes_mixColumns(uint8_t *); +static void aes_mixColumns_inv(uint8_t *); +static void aes_expandEncKey(uint8_t *, uint8_t *); +static void aes_expandDecKey(uint8_t *, uint8_t *); +#ifndef BACK_TO_TABLES +static uint8_t gf_alog(uint8_t); +static uint8_t gf_log(uint8_t); +static uint8_t gf_mulinv(uint8_t); +static uint8_t rj_sbox(uint8_t); +static uint8_t rj_sbox_inv(uint8_t); +#endif + +#ifdef BACK_TO_TABLES + +static const uint8_t sbox[256] = +{ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; +static const uint8_t sboxinv[256] = +{ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +#define rj_sbox(x) sbox[(x)] +#define rj_sbox_inv(x) sboxinv[(x)] + +#else /* tableless subroutines */ + +/* -------------------------------------------------------------------------- */ +static uint8_t gf_alog(uint8_t x) // calculate anti-logarithm gen 3 +{ + uint8_t y = 1, i; + + for (i = 0; i < x; i++) y ^= rj_xtime(y); + + return y; +} /* gf_alog */ + +/* -------------------------------------------------------------------------- */ +static uint8_t gf_log(uint8_t x) // calculate logarithm gen 3 +{ + uint8_t y, i = 0; + + if (x) + for (i = 1, y = 1; i > 0; i++ ) + { + y ^= rj_xtime(y); + if (y == x) break; + } + + return i; +} /* gf_log */ + + +/* -------------------------------------------------------------------------- */ +static uint8_t gf_mulinv(uint8_t x) // calculate multiplicative inverse +{ + return (x) ? gf_alog(255 - gf_log(x)) : 0; +} /* gf_mulinv */ + +/* -------------------------------------------------------------------------- */ +static uint8_t rj_sbox(uint8_t x) +{ + uint8_t y, sb; + + sb = y = gf_mulinv(x); + y = (uint8_t)(y << 1) | (y >> 7), sb ^= y; + y = (uint8_t)(y << 1) | (y >> 7), sb ^= y; + y = (uint8_t)(y << 1) | (y >> 7), sb ^= y; + y = (uint8_t)(y << 1) | (y >> 7), sb ^= y; + + return (sb ^ 0x63); +} /* rj_sbox */ + +/* -------------------------------------------------------------------------- */ +static uint8_t rj_sbox_inv(uint8_t x) +{ + uint8_t y, sb; + + y = x ^ 0x63; + sb = y = (uint8_t)(y << 1) | (y >> 7); + y = (uint8_t)(y << 2) | (y >> 6); + sb ^= y; + y = (uint8_t)(y << 3) | (y >> 5); + sb ^= y; + + return gf_mulinv(sb); +} /* rj_sbox_inv */ + +#endif + +/* -------------------------------------------------------------------------- */ +static uint8_t rj_xtime(uint8_t x) +{ + uint8_t y = (uint8_t)(x << 1); + return (x & 0x80) ? (y ^ 0x1b) : y; +} /* rj_xtime */ + +/* -------------------------------------------------------------------------- */ +static void aes_subBytes(uint8_t *buf) +{ + register uint8_t i = 16; + + while (i--) buf[i] = rj_sbox(buf[i]); +} /* aes_subBytes */ + +/* -------------------------------------------------------------------------- */ +static void aes_subBytes_inv(uint8_t *buf) +{ + register uint8_t i = 16; + + while (i--) buf[i] = rj_sbox_inv(buf[i]); +} /* aes_subBytes_inv */ + +/* -------------------------------------------------------------------------- */ +static void aes_addRoundKey(uint8_t *buf, uint8_t *key) +{ + register uint8_t i = 16; + + while (i--) buf[i] ^= key[i]; +} /* aes_addRoundKey */ + +/* -------------------------------------------------------------------------- */ +static void aes_addRoundKey_cpy(uint8_t *buf, uint8_t *key, uint8_t *cpk) +{ + register uint8_t i = 16; + + while (i--) buf[i] ^= (cpk[i] = key[i]), cpk[16 + i] = key[16 + i]; +} /* aes_addRoundKey_cpy */ + + +/* -------------------------------------------------------------------------- */ +static void aes_shiftRows(uint8_t *buf) +{ + register uint8_t i, j; /* to make it potentially parallelable :) */ + + i = buf[1], buf[1] = buf[5], buf[5] = buf[9], buf[9] = buf[13], buf[13] = i; + i = buf[10], buf[10] = buf[2], buf[2] = i; + j = buf[3], buf[3] = buf[15], buf[15] = buf[11], buf[11] = buf[7], buf[7] = j; + j = buf[14], buf[14] = buf[6], buf[6] = j; + +} /* aes_shiftRows */ + +/* -------------------------------------------------------------------------- */ +static void aes_shiftRows_inv(uint8_t *buf) +{ + register uint8_t i, j; /* same as above :) */ + + i = buf[1], buf[1] = buf[13], buf[13] = buf[9], buf[9] = buf[5], buf[5] = i; + i = buf[2], buf[2] = buf[10], buf[10] = i; + j = buf[3], buf[3] = buf[7], buf[7] = buf[11], buf[11] = buf[15], buf[15] = j; + j = buf[6], buf[6] = buf[14], buf[14] = j; + +} /* aes_shiftRows_inv */ + +/* -------------------------------------------------------------------------- */ +static void aes_mixColumns(uint8_t *buf) +{ + register uint8_t i, a, b, c, d, e; + + for (i = 0; i < 16; i += 4) + { + a = buf[i]; + b = buf[i + 1]; + c = buf[i + 2]; + d = buf[i + 3]; + e = a ^ b ^ c ^ d; + buf[i] ^= e ^ rj_xtime(a ^ b); + buf[i + 1] ^= e ^ rj_xtime(b ^ c); + buf[i + 2] ^= e ^ rj_xtime(c ^ d); + buf[i + 3] ^= e ^ rj_xtime(d ^ a); + } +} /* aes_mixColumns */ + +/* -------------------------------------------------------------------------- */ +void aes_mixColumns_inv(uint8_t *buf) +{ + register uint8_t i, a, b, c, d, e, x, y, z; + + for (i = 0; i < 16; i += 4) + { + a = buf[i]; + b = buf[i + 1]; + c = buf[i + 2]; + d = buf[i + 3]; + e = a ^ b ^ c ^ d; + z = rj_xtime(e); + x = e ^ rj_xtime(rj_xtime(z ^ a ^ c)); + y = e ^ rj_xtime(rj_xtime(z ^ b ^ d)); + buf[i] ^= x ^ rj_xtime(a ^ b); + buf[i + 1] ^= y ^ rj_xtime(b ^ c); + buf[i + 2] ^= x ^ rj_xtime(c ^ d); + buf[i + 3] ^= y ^ rj_xtime(d ^ a); + } +} /* aes_mixColumns_inv */ + +/* -------------------------------------------------------------------------- */ +static void aes_expandEncKey(uint8_t *k, uint8_t *rc) +{ + register uint8_t i; + + k[0] ^= rj_sbox(k[29]) ^ (*rc); + k[1] ^= rj_sbox(k[30]); + k[2] ^= rj_sbox(k[31]); + k[3] ^= rj_sbox(k[28]); + *rc = rj_xtime( *rc); + + for(i = 4; i < 16; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3], + k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1]; + k[16] ^= rj_sbox(k[12]); + k[17] ^= rj_sbox(k[13]); + k[18] ^= rj_sbox(k[14]); + k[19] ^= rj_sbox(k[15]); + + for(i = 20; i < 32; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3], + k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1]; + +} /* aes_expandEncKey */ + +/* -------------------------------------------------------------------------- */ +void aes_expandDecKey(uint8_t *k, uint8_t *rc) +{ + uint8_t i; + + for(i = 28; i > 16; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3], + k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1]; + + k[16] ^= rj_sbox(k[12]); + k[17] ^= rj_sbox(k[13]); + k[18] ^= rj_sbox(k[14]); + k[19] ^= rj_sbox(k[15]); + + for(i = 12; i > 0; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3], + k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1]; + + *rc = FD(*rc); + k[0] ^= rj_sbox(k[29]) ^ (*rc); + k[1] ^= rj_sbox(k[30]); + k[2] ^= rj_sbox(k[31]); + k[3] ^= rj_sbox(k[28]); +} /* aes_expandDecKey */ + + +/* -------------------------------------------------------------------------- */ +void aes256_init(aes256_context *ctx, uint8_t *k) +{ + uint8_t rcon = 1; + register uint8_t i; + + for (i = 0; i < sizeof(ctx->key); i++) ctx->enckey[i] = ctx->deckey[i] = k[i]; + for (i = 8; --i;) aes_expandEncKey(ctx->deckey, &rcon); +} /* aes256_init */ + +/* -------------------------------------------------------------------------- */ +void aes256_done(aes256_context *ctx) +{ + register uint8_t i; + + for (i = 0; i < sizeof(ctx->key); i++) + ctx->key[i] = ctx->enckey[i] = ctx->deckey[i] = 0; +} /* aes256_done */ + +/* -------------------------------------------------------------------------- */ +void aes256_encrypt_ecb(aes256_context *ctx, uint8_t *buf) +{ + uint8_t i, rcon; + + aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key); + for(i = 1, rcon = 1; i < 14; ++i) + { + aes_subBytes(buf); + aes_shiftRows(buf); + aes_mixColumns(buf); + if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]); + else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key); + } + aes_subBytes(buf); + aes_shiftRows(buf); + aes_expandEncKey(ctx->key, &rcon); + aes_addRoundKey(buf, ctx->key); +} /* aes256_encrypt */ + +/* -------------------------------------------------------------------------- */ +void aes256_decrypt_ecb(aes256_context *ctx, uint8_t *buf) +{ + uint8_t i, rcon; + + aes_addRoundKey_cpy(buf, ctx->deckey, ctx->key); + aes_shiftRows_inv(buf); + aes_subBytes_inv(buf); + + for (i = 14, rcon = 0x80; --i;) + { + if( ( i & 1 ) ) + { + aes_expandDecKey(ctx->key, &rcon); + aes_addRoundKey(buf, &ctx->key[16]); + } + else aes_addRoundKey(buf, ctx->key); + aes_mixColumns_inv(buf); + aes_shiftRows_inv(buf); + aes_subBytes_inv(buf); + } + aes_addRoundKey( buf, ctx->key); +} /* aes256_decrypt */ + +#ifdef __cplusplus +} +#endif diff --git a/external/MaxmindDB/LICENSE b/external/MaxmindDB/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/external/MaxmindDB/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/external/MaxmindDB/maxminddb-compat-util.h b/external/MaxmindDB/maxminddb-compat-util.h new file mode 100644 index 00000000..e3f0320f --- /dev/null +++ b/external/MaxmindDB/maxminddb-compat-util.h @@ -0,0 +1,167 @@ +#include +#include + +/* *INDENT-OFF* */ + +/* The memmem, strdup, and strndup functions were all copied from the + * FreeBSD source, along with the relevant copyright notice. + * + * It'd be nicer to simply use the functions available on the system if they + * exist, but there doesn't seem to be a good way to detect them without also + * defining things like _GNU_SOURCE, which we want to avoid, because then we + * end up _accidentally_ using GNU features without noticing, which then + * breaks on systems like OSX. + * + * C is fun! */ + +/* Applies to memmem implementation */ +/*- + * Copyright (c) 2005 Pascal Gloor + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +static void * +mmdb_memmem(const void *l, size_t l_len, const void *s, size_t s_len) +{ + register char *cur, *last; + const char *cl = (const char *)l; + const char *cs = (const char *)s; + + /* we need something to compare */ + if (l_len == 0 || s_len == 0) + return NULL; + + /* "s" must be smaller or equal to "l" */ + if (l_len < s_len) + return NULL; + + /* special case where s_len == 1 */ + if (s_len == 1) + return memchr(l, (int)*cs, l_len); + + /* the last position where its possible to find "s" in "l" */ + last = (char *)cl + l_len - s_len; + + for (cur = (char *)cl; cur <= last; cur++) + if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) + return cur; + + return NULL; +} + +/* Applies to strnlen implementation */ +/*- + * Copyright (c) 2009 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +static size_t +mmdb_strnlen(const char *s, size_t maxlen) +{ + size_t len; + + for (len = 0; len < maxlen; len++, s++) { + if (!*s) + break; + } + return (len); +} + +/* Applies to strdup and strndup implementation */ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +static char * +mmdb_strdup(const char *str) +{ + size_t len; + char *copy; + + len = strlen(str) + 1; + if ((copy = malloc(len)) == NULL) + return (NULL); + memcpy(copy, str, len); + return (copy); +} + +static char * +mmdb_strndup(const char *str, size_t n) +{ + size_t len; + char *copy; + + len = mmdb_strnlen(str, n); + if ((copy = malloc(len + 1)) == NULL) + return (NULL); + memcpy(copy, str, len); + copy[len] = '\0'; + return (copy); +} +/* *INDENT-ON* */ diff --git a/external/MaxmindDB/maxminddb.c b/external/MaxmindDB/maxminddb.c new file mode 100644 index 00000000..4b98c88e --- /dev/null +++ b/external/MaxmindDB/maxminddb.c @@ -0,0 +1,2045 @@ +#if HAVE_CONFIG_H +#include +#endif +#include "maxminddb.h" +#include "maxminddb-compat-util.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + +#define MMDB_DATA_SECTION_SEPARATOR (16) +#define MAXIMUM_DATA_STRUCTURE_DEPTH (512) + +#ifdef MMDB_DEBUG +#define LOCAL +#define NO_PROTO +#define DEBUG_FUNC +#define DEBUG_MSG(msg) fprintf(stderr, msg "\n") +#define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__) +#define DEBUG_BINARY(fmt, byte) \ + do { \ + char *binary = byte_to_binary(byte); \ + if (NULL == binary) { \ + fprintf(stderr, "Malloc failed in DEBUG_BINARY\n"); \ + abort(); \ + } \ + fprintf(stderr, fmt "\n", binary); \ + free(binary); \ + } while (0) +#define DEBUG_NL fprintf(stderr, "\n") +#else +#define LOCAL static +#define NO_PROTO static +#define DEBUG_MSG(...) +#define DEBUG_MSGF(...) +#define DEBUG_BINARY(...) +#define DEBUG_NL +#endif + +#ifdef MMDB_DEBUG +DEBUG_FUNC char *byte_to_binary(uint8_t byte) +{ + char *bits = malloc(sizeof(char) * 9); + if (NULL == bits) { + return bits; + } + + for (uint8_t i = 0; i < 8; i++) { + bits[i] = byte & (128 >> i) ? '1' : '0'; + } + bits[8] = '\0'; + + return bits; +} + +DEBUG_FUNC char *type_num_to_name(uint8_t num) +{ + switch (num) { + case 0: + return "extended"; + case 1: + return "pointer"; + case 2: + return "utf8_string"; + case 3: + return "double"; + case 4: + return "bytes"; + case 5: + return "uint16"; + case 6: + return "uint32"; + case 7: + return "map"; + case 8: + return "int32"; + case 9: + return "uint64"; + case 10: + return "uint128"; + case 11: + return "array"; + case 12: + return "container"; + case 13: + return "end_marker"; + case 14: + return "boolean"; + case 15: + return "float"; + default: + return "unknown type"; + } +} +#endif + +/* None of the values we check on the lhs are bigger than uint32_t, so on + * platforms where SIZE_MAX is a 64-bit integer, this would be a no-op, and it + * makes the compiler complain if we do the check anyway. */ +#if SIZE_MAX == UINT32_MAX +#define MAYBE_CHECK_SIZE_OVERFLOW(lhs, rhs, error) \ + if ((lhs) > (rhs)) { \ + return error; \ + } +#else +#define MAYBE_CHECK_SIZE_OVERFLOW(...) +#endif + +typedef struct record_info_s { + uint16_t record_length; + uint32_t (*left_record_getter)(const uint8_t *); + uint32_t (*right_record_getter)(const uint8_t *); + uint8_t right_record_offset; +} record_info_s; + +#define METADATA_MARKER "\xab\xcd\xefMaxMind.com" +/* This is 128kb */ +#define METADATA_BLOCK_MAX_SIZE 131072 + +/* *INDENT-OFF* */ +/* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ +LOCAL int map_file(MMDB_s *const mmdb); +LOCAL const uint8_t *find_metadata(const uint8_t *file_content, + ssize_t file_size, uint32_t *metadata_size); +LOCAL int read_metadata(MMDB_s *mmdb); +LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb); +LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key, + uint16_t *value); +LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key, + uint32_t *value); +LOCAL int value_for_key_as_uint64(MMDB_entry_s *start, char *key, + uint64_t *value); +LOCAL int value_for_key_as_string(MMDB_entry_s *start, char *key, + char const **value); +LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, + MMDB_entry_s *metadata_start); +LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, + MMDB_entry_s *metadata_start); +LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses); +LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, + sa_family_t address_family, + MMDB_lookup_result_s *result); +LOCAL record_info_s record_info_for_database(MMDB_s *mmdb); +LOCAL int find_ipv4_start_node(MMDB_s *mmdb); +LOCAL int populate_result(MMDB_s *mmdb, uint32_t node_count, uint32_t value, + uint16_t netmask, MMDB_lookup_result_s *result); +LOCAL uint32_t get_left_28_bit_record(const uint8_t *record); +LOCAL uint32_t get_right_28_bit_record(const uint8_t *record); +LOCAL int path_length(va_list va_path); +LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, + MMDB_entry_data_s *entry_data); +LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, + MMDB_entry_data_s *entry_data); +LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data); +LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, + MMDB_entry_data_s *entry_data); +LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, + MMDB_entry_data_s *entry_data); +LOCAL int get_ext_type(int raw_ext_type); +LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, + int ptr_size); +LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, + MMDB_entry_data_list_s *const entry_data_list, + int depth); +LOCAL float get_ieee754_float(const uint8_t *restrict p); +LOCAL double get_ieee754_double(const uint8_t *restrict p); +LOCAL uint32_t get_uint32(const uint8_t *p); +LOCAL uint32_t get_uint24(const uint8_t *p); +LOCAL uint32_t get_uint16(const uint8_t *p); +LOCAL uint64_t get_uintX(const uint8_t *p, int length); +LOCAL int32_t get_sintX(const uint8_t *p, int length); +LOCAL MMDB_entry_data_list_s *new_entry_data_list(void); +LOCAL void free_mmdb_struct(MMDB_s *const mmdb); +LOCAL void free_languages_metadata(MMDB_s *mmdb); +LOCAL void free_descriptions_metadata(MMDB_s *mmdb); +LOCAL MMDB_entry_data_list_s *dump_entry_data_list( + FILE *stream, MMDB_entry_data_list_s *entry_data_list, int indent, + int *status); +LOCAL void print_indentation(FILE *stream, int i); +LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size); +/* --prototypes end - don't remove this comment-- */ +/* *INDENT-ON* */ + +#define CHECKED_DECODE_ONE(mmdb, offset, entry_data) \ + do { \ + int status = decode_one(mmdb, offset, entry_data); \ + if (MMDB_SUCCESS != status) { \ + return status; \ + } \ + } while (0) + +#define CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, entry_data) \ + do { \ + int status = decode_one_follow(mmdb, offset, entry_data); \ + if (MMDB_SUCCESS != status) { \ + return status; \ + } \ + } while (0) + +#define FREE_AND_SET_NULL(p) { free((void *)(p)); (p) = NULL; } + +int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) +{ + int status = MMDB_SUCCESS; + + mmdb->file_content = NULL; + mmdb->data_section = NULL; + mmdb->metadata.database_type = NULL; + mmdb->metadata.languages.count = 0; + mmdb->metadata.description.count = 0; + + mmdb->filename = mmdb_strdup(filename); + if (NULL == mmdb->filename) { + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; + } + + if ((flags & MMDB_MODE_MASK) == 0) { + flags |= MMDB_MODE_MMAP; + } + mmdb->flags = flags; + + if (MMDB_SUCCESS != (status = map_file(mmdb)) ) { + goto cleanup; + } + +#ifdef _WIN32 + WSADATA wsa; + WSAStartup(MAKEWORD(2, 2), &wsa); +#endif + + uint32_t metadata_size = 0; + const uint8_t *metadata = find_metadata(mmdb->file_content, mmdb->file_size, + &metadata_size); + if (NULL == metadata) { + status = MMDB_INVALID_METADATA_ERROR; + goto cleanup; + } + + mmdb->metadata_section = metadata; + mmdb->metadata_section_size = metadata_size; + + status = read_metadata(mmdb); + if (MMDB_SUCCESS != status) { + goto cleanup; + } + + if (mmdb->metadata.binary_format_major_version != 2) { + status = MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; + goto cleanup; + } + + uint32_t search_tree_size = mmdb->metadata.node_count * + mmdb->full_record_byte_size; + + mmdb->data_section = mmdb->file_content + search_tree_size; + if (search_tree_size > (uint32_t)mmdb->file_size) { + status = MMDB_INVALID_METADATA_ERROR; + goto cleanup; + } + mmdb->data_section_size = mmdb->file_size - search_tree_size; + mmdb->metadata_section = metadata; + mmdb->ipv4_start_node.node_value = 0; + mmdb->ipv4_start_node.netmask = 0; + + cleanup: + if (MMDB_SUCCESS != status) { + int saved_errno = errno; + free_mmdb_struct(mmdb); + errno = saved_errno; + } + return status; +} + +#ifdef _WIN32 + +LOCAL int map_file(MMDB_s *const mmdb) +{ + ssize_t size; + int status = MMDB_SUCCESS; + HANDLE mmh = NULL; + HANDLE fd = CreateFileA(mmdb->filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd == INVALID_HANDLE_VALUE) { + status = MMDB_FILE_OPEN_ERROR; + goto cleanup; + } + size = GetFileSize(fd, NULL); + if (size == INVALID_FILE_SIZE) { + status = MMDB_FILE_OPEN_ERROR; + goto cleanup; + } + mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL); + /* Microsoft documentation for CreateFileMapping indicates this returns + NULL not INVALID_HANDLE_VALUE on error */ + if (NULL == mmh) { + status = MMDB_IO_ERROR; + goto cleanup; + } + uint8_t *file_content = + (uint8_t *)MapViewOfFile(mmh, FILE_MAP_READ, 0, 0, 0); + if (file_content == NULL) { + status = MMDB_IO_ERROR; + goto cleanup; + } + + mmdb->file_size = size; + mmdb->file_content = file_content; + + cleanup:; + int saved_errno = errno; + if (INVALID_HANDLE_VALUE != fd) { + CloseHandle(fd); + } + if (NULL != mmh) { + CloseHandle(mmh); + } + errno = saved_errno; + + return status; +} + +#else + +LOCAL int map_file(MMDB_s *const mmdb) +{ + ssize_t size; + int status = MMDB_SUCCESS; + + int fd = open(mmdb->filename, O_RDONLY); + struct stat s; + if (fd < 0 || fstat(fd, &s)) { + status = MMDB_FILE_OPEN_ERROR; + goto cleanup; + } + + size = s.st_size; + if (size < 0 || size != s.st_size) { + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; + } + + uint8_t *file_content = + (uint8_t *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (MAP_FAILED == file_content) { + if (ENOMEM == errno) { + status = MMDB_OUT_OF_MEMORY_ERROR; + } else { + status = MMDB_IO_ERROR; + } + goto cleanup; + } + + mmdb->file_size = size; + mmdb->file_content = file_content; + + cleanup:; + int saved_errno = errno; + if (fd >= 0) { + close(fd); + } + errno = saved_errno; + + return status; +} + +#endif + +LOCAL const uint8_t *find_metadata(const uint8_t *file_content, + ssize_t file_size, uint32_t *metadata_size) +{ + const ssize_t marker_len = sizeof(METADATA_MARKER) - 1; + ssize_t max_size = file_size > + METADATA_BLOCK_MAX_SIZE ? METADATA_BLOCK_MAX_SIZE : + file_size; + + uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size)); + uint8_t *start = search_area; + uint8_t *tmp; + do { + tmp = mmdb_memmem(search_area, max_size, + METADATA_MARKER, marker_len); + + if (NULL != tmp) { + max_size -= tmp - search_area; + search_area = tmp; + + /* Continue searching just after the marker we just read, in case + * there are multiple markers in the same file. This would be odd + * but is certainly not impossible. */ + max_size -= marker_len; + search_area += marker_len; + } + } while (NULL != tmp); + + if (search_area == start) { + return NULL; + } + + *metadata_size = max_size; + + return search_area; +} + +LOCAL int read_metadata(MMDB_s *mmdb) +{ + /* We need to create a fake MMDB_s struct in order to decode values from + the metadata. The metadata is basically just like the data section, so we + want to use the same functions we use for the data section to get metadata + values. */ + MMDB_s metadata_db = make_fake_metadata_db(mmdb); + + MMDB_entry_s metadata_start = { + .mmdb = &metadata_db, + .offset = 0 + }; + + int status = + value_for_key_as_uint32(&metadata_start, "node_count", + &mmdb->metadata.node_count); + if (MMDB_SUCCESS != status) { + return status; + } + if (!mmdb->metadata.node_count) { + DEBUG_MSG("could not find node_count value in metadata"); + return MMDB_INVALID_METADATA_ERROR; + } + + status = value_for_key_as_uint16(&metadata_start, "record_size", + &mmdb->metadata.record_size); + if (MMDB_SUCCESS != status) { + return status; + } + if (!mmdb->metadata.record_size) { + DEBUG_MSG("could not find record_size value in metadata"); + return MMDB_INVALID_METADATA_ERROR; + } + + if (mmdb->metadata.record_size != 24 && mmdb->metadata.record_size != 28 + && mmdb->metadata.record_size != 32) { + DEBUG_MSGF("bad record size in metadata: %i", + mmdb->metadata.record_size); + return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; + } + + status = value_for_key_as_uint16(&metadata_start, "ip_version", + &mmdb->metadata.ip_version); + if (MMDB_SUCCESS != status) { + return status; + } + if (!mmdb->metadata.ip_version) { + DEBUG_MSG("could not find ip_version value in metadata"); + return MMDB_INVALID_METADATA_ERROR; + } + if (!(mmdb->metadata.ip_version == 4 || mmdb->metadata.ip_version == 6)) { + DEBUG_MSGF("ip_version value in metadata is not 4 or 6 - it was %i", + mmdb->metadata.ip_version); + return MMDB_INVALID_METADATA_ERROR; + } + + status = value_for_key_as_string(&metadata_start, "database_type", + &mmdb->metadata.database_type); + if (MMDB_SUCCESS != status) { + DEBUG_MSG("error finding database_type value in metadata"); + return status; + } + + status = + populate_languages_metadata(mmdb, &metadata_db, &metadata_start); + if (MMDB_SUCCESS != status) { + DEBUG_MSG("could not populate languages from metadata"); + return status; + } + + status = value_for_key_as_uint16( + &metadata_start, "binary_format_major_version", + &mmdb->metadata.binary_format_major_version); + if (MMDB_SUCCESS != status) { + return status; + } + if (!mmdb->metadata.binary_format_major_version) { + DEBUG_MSG( + "could not find binary_format_major_version value in metadata"); + return MMDB_INVALID_METADATA_ERROR; + } + + status = value_for_key_as_uint16( + &metadata_start, "binary_format_minor_version", + &mmdb->metadata.binary_format_minor_version); + if (MMDB_SUCCESS != status) { + return status; + } + + status = value_for_key_as_uint64(&metadata_start, "build_epoch", + &mmdb->metadata.build_epoch); + if (MMDB_SUCCESS != status) { + return status; + } + if (!mmdb->metadata.build_epoch) { + DEBUG_MSG("could not find build_epoch value in metadata"); + return MMDB_INVALID_METADATA_ERROR; + } + + status = populate_description_metadata(mmdb, &metadata_db, &metadata_start); + if (MMDB_SUCCESS != status) { + DEBUG_MSG("could not populate description from metadata"); + return status; + } + + mmdb->full_record_byte_size = mmdb->metadata.record_size * 2 / 8U; + + mmdb->depth = mmdb->metadata.ip_version == 4 ? 32 : 128; + + return MMDB_SUCCESS; +} + +LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb) +{ + MMDB_s fake_metadata_db = { + .data_section = mmdb->metadata_section, + .data_section_size = mmdb->metadata_section_size + }; + + return fake_metadata_db; +} + +LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key, + uint16_t *value) +{ + MMDB_entry_data_s entry_data; + const char *path[] = { key, NULL }; + int status = MMDB_aget_value(start, &entry_data, path); + if (MMDB_SUCCESS != status) { + return status; + } + if (MMDB_DATA_TYPE_UINT16 != entry_data.type) { + DEBUG_MSGF("expect uint16 for %s but received %s", key, + type_num_to_name( + entry_data.type)); + return MMDB_INVALID_METADATA_ERROR; + } + *value = entry_data.uint16; + return MMDB_SUCCESS; +} + +LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key, + uint32_t *value) +{ + MMDB_entry_data_s entry_data; + const char *path[] = { key, NULL }; + int status = MMDB_aget_value(start, &entry_data, path); + if (MMDB_SUCCESS != status) { + return status; + } + if (MMDB_DATA_TYPE_UINT32 != entry_data.type) { + DEBUG_MSGF("expect uint32 for %s but received %s", key, + type_num_to_name( + entry_data.type)); + return MMDB_INVALID_METADATA_ERROR; + } + *value = entry_data.uint32; + return MMDB_SUCCESS; +} + +LOCAL int value_for_key_as_uint64(MMDB_entry_s *start, char *key, + uint64_t *value) +{ + MMDB_entry_data_s entry_data; + const char *path[] = { key, NULL }; + int status = MMDB_aget_value(start, &entry_data, path); + if (MMDB_SUCCESS != status) { + return status; + } + if (MMDB_DATA_TYPE_UINT64 != entry_data.type) { + DEBUG_MSGF("expect uint64 for %s but received %s", key, + type_num_to_name( + entry_data.type)); + return MMDB_INVALID_METADATA_ERROR; + } + *value = entry_data.uint64; + return MMDB_SUCCESS; +} + +LOCAL int value_for_key_as_string(MMDB_entry_s *start, char *key, + char const **value) +{ + MMDB_entry_data_s entry_data; + const char *path[] = { key, NULL }; + int status = MMDB_aget_value(start, &entry_data, path); + if (MMDB_SUCCESS != status) { + return status; + } + if (MMDB_DATA_TYPE_UTF8_STRING != entry_data.type) { + DEBUG_MSGF("expect string for %s but received %s", key, + type_num_to_name( + entry_data.type)); + return MMDB_INVALID_METADATA_ERROR; + } + *value = mmdb_strndup((char *)entry_data.utf8_string, entry_data.data_size); + if (NULL == *value) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + return MMDB_SUCCESS; +} + +LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, + MMDB_entry_s *metadata_start) +{ + MMDB_entry_data_s entry_data; + + const char *path[] = { "languages", NULL }; + int status = MMDB_aget_value(metadata_start, &entry_data, path); + if (MMDB_SUCCESS != status) { + return status; + } + if (MMDB_DATA_TYPE_ARRAY != entry_data.type) { + return MMDB_INVALID_METADATA_ERROR; + } + + MMDB_entry_s array_start = { + .mmdb = metadata_db, + .offset = entry_data.offset + }; + + MMDB_entry_data_list_s *member; + status = MMDB_get_entry_data_list(&array_start, &member); + if (MMDB_SUCCESS != status) { + return status; + } + + MMDB_entry_data_list_s *first_member = member; + + uint32_t array_size = member->entry_data.data_size; + MAYBE_CHECK_SIZE_OVERFLOW(array_size, SIZE_MAX / sizeof(char *), + MMDB_INVALID_METADATA_ERROR); + + mmdb->metadata.languages.count = 0; + mmdb->metadata.languages.names = malloc(array_size * sizeof(char *)); + if (NULL == mmdb->metadata.languages.names) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + + for (uint32_t i = 0; i < array_size; i++) { + member = member->next; + if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { + return MMDB_INVALID_METADATA_ERROR; + } + + mmdb->metadata.languages.names[i] = + mmdb_strndup((char *)member->entry_data.utf8_string, + member->entry_data.data_size); + + if (NULL == mmdb->metadata.languages.names[i]) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + // We assign this as we go so that if we fail a malloc and need to + // free it, the count is right. + mmdb->metadata.languages.count = i + 1; + } + + MMDB_free_entry_data_list(first_member); + + return MMDB_SUCCESS; +} + +LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, + MMDB_entry_s *metadata_start) +{ + MMDB_entry_data_s entry_data; + + const char *path[] = { "description", NULL }; + int status = MMDB_aget_value(metadata_start, &entry_data, path); + if (MMDB_SUCCESS != status) { + return status; + } + + if (MMDB_DATA_TYPE_MAP != entry_data.type) { + return MMDB_INVALID_METADATA_ERROR; + } + + MMDB_entry_s map_start = { + .mmdb = metadata_db, + .offset = entry_data.offset + }; + + MMDB_entry_data_list_s *member; + status = MMDB_get_entry_data_list(&map_start, &member); + if (MMDB_SUCCESS != status) { + return status; + } + + MMDB_entry_data_list_s *first_member = member; + + uint32_t map_size = member->entry_data.data_size; + mmdb->metadata.description.count = 0; + if (0 == map_size) { + mmdb->metadata.description.descriptions = NULL; + goto cleanup; + } + MAYBE_CHECK_SIZE_OVERFLOW(map_size, SIZE_MAX / sizeof(MMDB_description_s *), + MMDB_INVALID_METADATA_ERROR); + + mmdb->metadata.description.descriptions = + malloc(map_size * sizeof(MMDB_description_s *)); + if (NULL == mmdb->metadata.description.descriptions) { + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; + } + + for (uint32_t i = 0; i < map_size; i++) { + mmdb->metadata.description.descriptions[i] = + malloc(sizeof(MMDB_description_s)); + if (NULL == mmdb->metadata.description.descriptions[i]) { + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; + } + + mmdb->metadata.description.count = i + 1; + mmdb->metadata.description.descriptions[i]->language = NULL; + mmdb->metadata.description.descriptions[i]->description = NULL; + + member = member->next; + + if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { + status = MMDB_INVALID_METADATA_ERROR; + goto cleanup; + } + + mmdb->metadata.description.descriptions[i]->language = + mmdb_strndup((char *)member->entry_data.utf8_string, + member->entry_data.data_size); + + if (NULL == mmdb->metadata.description.descriptions[i]->language) { + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; + } + + member = member->next; + + if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { + status = MMDB_INVALID_METADATA_ERROR; + goto cleanup; + } + + mmdb->metadata.description.descriptions[i]->description = + mmdb_strndup((char *)member->entry_data.utf8_string, + member->entry_data.data_size); + + if (NULL == mmdb->metadata.description.descriptions[i]->description) { + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; + } + } + + cleanup: + MMDB_free_entry_data_list(first_member); + + return status; +} + +MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, + const char *const ipstr, + int *const gai_error, + int *const mmdb_error) +{ + MMDB_lookup_result_s result = { + .found_entry = false, + .netmask = 0, + .entry = { + .mmdb = mmdb, + .offset = 0 + } + }; + + struct addrinfo *addresses = NULL; + *gai_error = resolve_any_address(ipstr, &addresses); + + if (!*gai_error) { + result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, mmdb_error); + } + + if (NULL != addresses) { + freeaddrinfo(addresses); + } + + return result; +} + +LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses) +{ + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_NUMERICHOST, + // We set ai_socktype so that we only get one result back + .ai_socktype = SOCK_STREAM + }; + + int gai_status = getaddrinfo(ipstr, NULL, &hints, addresses); + if (gai_status) { + return gai_status; + } + + return 0; +} + +MMDB_lookup_result_s MMDB_lookup_sockaddr( + MMDB_s *const mmdb, + const struct sockaddr *const sockaddr, + int *const mmdb_error) +{ + MMDB_lookup_result_s result = { + .found_entry = false, + .netmask = 0, + .entry = { + .mmdb = mmdb, + .offset = 0 + } + }; + + uint8_t mapped_address[16], *address; + if (mmdb->metadata.ip_version == 4) { + if (sockaddr->sa_family == AF_INET6) { + *mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR; + return result; + } + address = (uint8_t *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr; + } else { + if (sockaddr->sa_family == AF_INET6) { + address = + (uint8_t *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr. + s6_addr; + } else { + address = mapped_address; + memset(address, 0, 12); + memcpy(address + 12, + &((struct sockaddr_in *)sockaddr)->sin_addr.s_addr, 4); + } + } + + *mmdb_error = + find_address_in_search_tree(mmdb, address, sockaddr->sa_family, + &result); + + return result; +} + +LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, + sa_family_t address_family, + MMDB_lookup_result_s *result) +{ + record_info_s record_info = record_info_for_database(mmdb); + if (0 == record_info.right_record_offset) { + return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; + } + + DEBUG_NL; + DEBUG_MSG("Looking for address in search tree"); + + uint32_t node_count = mmdb->metadata.node_count; + uint32_t value = 0; + uint16_t max_depth0 = mmdb->depth - 1; + uint16_t start_bit = max_depth0; + + if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) { + int mmdb_error = find_ipv4_start_node(mmdb); + if (MMDB_SUCCESS != mmdb_error) { + return mmdb_error; + } + DEBUG_MSGF("IPv4 start node is %u (netmask %u)", + mmdb->ipv4_start_node.node_value, + mmdb->ipv4_start_node.netmask); + /* We have an IPv6 database with no IPv4 data */ + if (mmdb->ipv4_start_node.node_value >= node_count) { + return populate_result(mmdb, node_count, + mmdb->ipv4_start_node.node_value, + mmdb->ipv4_start_node.netmask, + result); + } + + value = mmdb->ipv4_start_node.node_value; + start_bit -= mmdb->ipv4_start_node.netmask; + } + + const uint8_t *search_tree = mmdb->file_content; + const uint8_t *record_pointer; + for (int current_bit = start_bit; current_bit >= 0; current_bit--) { + uint8_t bit_is_true = + address[(max_depth0 - current_bit) >> 3] + & (1U << (~(max_depth0 - current_bit) & 7)) ? 1 : 0; + + DEBUG_MSGF("Looking at bit %i - bit's value is %i", current_bit, + bit_is_true); + DEBUG_MSGF(" current node = %u", value); + + record_pointer = &search_tree[value * record_info.record_length]; + if (record_pointer + record_info.record_length > mmdb->data_section) { + return MMDB_CORRUPT_SEARCH_TREE_ERROR; + } + if (bit_is_true) { + record_pointer += record_info.right_record_offset; + value = record_info.right_record_getter(record_pointer); + } else { + value = record_info.left_record_getter(record_pointer); + } + + /* Ideally we'd check to make sure that a record never points to a + * previously seen value, but that's more complicated. For now, we can + * at least check that we don't end up at the top of the tree again. */ + if (0 == value) { + DEBUG_MSGF(" %s record has a value of 0", + bit_is_true ? "right" : "left"); + return MMDB_CORRUPT_SEARCH_TREE_ERROR; + } + + if (value >= node_count) { + return populate_result(mmdb, node_count, value, current_bit, result); + } else { + DEBUG_MSGF(" proceeding to search tree node %i", value); + } + } + + DEBUG_MSG( + "Reached the end of the address bits without leaving the search tree"); + + // We should not be able to reach this return. If we do, something very bad happened. + return MMDB_CORRUPT_SEARCH_TREE_ERROR; +} + +LOCAL record_info_s record_info_for_database(MMDB_s *mmdb) +{ + record_info_s record_info = { + .record_length = mmdb->full_record_byte_size, + .right_record_offset = 0 + }; + + if (record_info.record_length == 6) { + record_info.left_record_getter = &get_uint24; + record_info.right_record_getter = &get_uint24; + record_info.right_record_offset = 3; + } else if (record_info.record_length == 7) { + record_info.left_record_getter = &get_left_28_bit_record; + record_info.right_record_getter = &get_right_28_bit_record; + record_info.right_record_offset = 3; + } else if (record_info.record_length == 8) { + record_info.left_record_getter = &get_uint32; + record_info.right_record_getter = &get_uint32; + record_info.right_record_offset = 4; + } else { + assert(false); + } + + return record_info; +} + +LOCAL int find_ipv4_start_node(MMDB_s *mmdb) +{ + /* In a pathological case of a database with a single node search tree, + * this check will be true even after we've found the IPv4 start node, but + * that doesn't seem worth trying to fix. */ + if (mmdb->ipv4_start_node.node_value != 0) { + return MMDB_SUCCESS; + } + + record_info_s record_info = record_info_for_database(mmdb); + + const uint8_t *search_tree = mmdb->file_content; + uint32_t node_value = 0; + const uint8_t *record_pointer; + uint32_t netmask; + for (netmask = 0; netmask < 96; netmask++) { + record_pointer = &search_tree[node_value * record_info.record_length]; + if (record_pointer + record_info.record_length > mmdb->data_section) { + return MMDB_CORRUPT_SEARCH_TREE_ERROR; + } + node_value = record_info.left_record_getter(record_pointer); + /* This can happen if there's no IPv4 data _or_ if there is a subnet + * with data that contains the entire IPv4 range (like ::/64) */ + if (node_value >= mmdb->metadata.node_count) { + break; + } + } + + mmdb->ipv4_start_node.node_value = node_value; + mmdb->ipv4_start_node.netmask = netmask; + + return MMDB_SUCCESS; +} + +LOCAL int populate_result(MMDB_s *mmdb, uint32_t node_count, uint32_t value, + uint16_t netmask, MMDB_lookup_result_s *result) +{ + uint32_t offset = value - node_count; + DEBUG_MSGF(" data section offset is %i (record value = %i)", offset, value); + + if (offset > mmdb->data_section_size) { + return MMDB_CORRUPT_SEARCH_TREE_ERROR; + } + + result->netmask = mmdb->depth - netmask; + result->entry.offset = offset; + result->found_entry = result->entry.offset > 0 ? true : false; + return MMDB_SUCCESS; +} + +LOCAL uint32_t get_left_28_bit_record(const uint8_t *record) +{ + return record[0] * 65536 + record[1] * 256 + record[2] + + ((record[3] & 0xf0) << 20); +} + +LOCAL uint32_t get_right_28_bit_record(const uint8_t *record) +{ + uint32_t value = get_uint32(record); + return value & 0xfffffff; +} + +int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number, + MMDB_search_node_s *const node) +{ + record_info_s record_info = record_info_for_database(mmdb); + if (0 == record_info.right_record_offset) { + return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; + } + + if (node_number > mmdb->metadata.node_count) { + return MMDB_INVALID_NODE_NUMBER_ERROR; + } + + const uint8_t *search_tree = mmdb->file_content; + const uint8_t *record_pointer = + &search_tree[node_number * record_info.record_length]; + node->left_record = record_info.left_record_getter(record_pointer); + record_pointer += record_info.right_record_offset; + node->right_record = record_info.right_record_getter(record_pointer); + + return MMDB_SUCCESS; +} + +int MMDB_get_value(MMDB_entry_s *const start, + MMDB_entry_data_s *const entry_data, + ...) +{ + va_list path; + va_start(path, entry_data); + int status = MMDB_vget_value(start, entry_data, path); + va_end(path); + return status; +} + +int MMDB_vget_value(MMDB_entry_s *const start, + MMDB_entry_data_s *const entry_data, + va_list va_path) +{ + int length = path_length(va_path); + const char *path_elem; + int i = 0; + + MAYBE_CHECK_SIZE_OVERFLOW(length, SIZE_MAX / sizeof(const char *) - 1, + MMDB_INVALID_METADATA_ERROR); + + const char **path = malloc((length + 1) * sizeof(const char *)); + if (NULL == path) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + + while (NULL != (path_elem = va_arg(va_path, char *))) { + path[i] = path_elem; + i++; + } + path[i] = NULL; + + int status = MMDB_aget_value(start, entry_data, path); + + free((char **)path); + + return status; +} + +LOCAL int path_length(va_list va_path) +{ + int i = 0; + const char *ignore; + va_list path_copy; + va_copy(path_copy, va_path); + + while (NULL != (ignore = va_arg(path_copy, char *))) { + i++; + } + + va_end(path_copy); + + return i; +} + +int MMDB_aget_value(MMDB_entry_s *const start, + MMDB_entry_data_s *const entry_data, + const char *const *const path) +{ + MMDB_s *mmdb = start->mmdb; + uint32_t offset = start->offset; + + memset(entry_data, 0, sizeof(MMDB_entry_data_s)); + DEBUG_NL; + DEBUG_MSG("looking up value by path"); + + CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, entry_data); + + DEBUG_NL; + DEBUG_MSGF("top level element is a %s", type_num_to_name(entry_data->type)); + + /* Can this happen? It'd probably represent a pathological case under + * normal use, but there's nothing preventing someone from passing an + * invalid MMDB_entry_s struct to this function */ + if (!entry_data->has_data) { + return MMDB_INVALID_LOOKUP_PATH_ERROR; + } + + const char *path_elem; + int i = 0; + while (NULL != (path_elem = path[i++])) { + DEBUG_NL; + DEBUG_MSGF("path elem = %s", path_elem); + + /* XXX - it'd be good to find a quicker way to skip through these + entries that doesn't involve decoding them + completely. Basically we need to just use the size from the + control byte to advance our pointer rather than calling + decode_one(). */ + if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { + int status = lookup_path_in_array(path_elem, mmdb, entry_data); + if (MMDB_SUCCESS != status) { + memset(entry_data, 0, sizeof(MMDB_entry_data_s)); + return status; + } + } else if (entry_data->type == MMDB_DATA_TYPE_MAP) { + int status = lookup_path_in_map(path_elem, mmdb, entry_data); + if (MMDB_SUCCESS != status) { + memset(entry_data, 0, sizeof(MMDB_entry_data_s)); + return status; + } + } else { + /* Once we make the code traverse maps & arrays without calling + * decode_one() we can get rid of this. */ + memset(entry_data, 0, sizeof(MMDB_entry_data_s)); + return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; + } + } + + return MMDB_SUCCESS; +} + +LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, + MMDB_entry_data_s *entry_data) +{ + uint32_t size = entry_data->data_size; + char *first_invalid; + + int saved_errno = errno; + errno = 0; + int array_index = strtol(path_elem, &first_invalid, 10); + if (array_index < 0 || ERANGE == errno) { + errno = saved_errno; + return MMDB_INVALID_LOOKUP_PATH_ERROR; + } + errno = saved_errno; + + if (*first_invalid || (uint32_t)array_index >= size) { + return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; + } + + for (int i = 0; i < array_index; i++) { + /* We don't want to follow a pointer here. If the next element is a + * pointer we simply skip it and keep going */ + CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); + int status = skip_map_or_array(mmdb, entry_data); + if (MMDB_SUCCESS != status) { + return status; + } + } + + MMDB_entry_data_s value; + CHECKED_DECODE_ONE_FOLLOW(mmdb, entry_data->offset_to_next, &value); + memcpy(entry_data, &value, sizeof(MMDB_entry_data_s)); + + return MMDB_SUCCESS; +} + +LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, + MMDB_entry_data_s *entry_data) +{ + uint32_t size = entry_data->data_size; + uint32_t offset = entry_data->offset_to_next; + size_t path_elem_len = strlen(path_elem); + + while (size-- > 0) { + MMDB_entry_data_s key, value; + CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, &key); + + uint32_t offset_to_value = key.offset_to_next; + + if (MMDB_DATA_TYPE_UTF8_STRING != key.type) { + return MMDB_INVALID_DATA_ERROR; + } + + if (key.data_size == path_elem_len && + !memcmp(path_elem, key.utf8_string, path_elem_len)) { + + DEBUG_MSG("found key matching path elem"); + + CHECKED_DECODE_ONE_FOLLOW(mmdb, offset_to_value, &value); + memcpy(entry_data, &value, sizeof(MMDB_entry_data_s)); + return MMDB_SUCCESS; + } else { + /* We don't want to follow a pointer here. If the next element is + * a pointer we simply skip it and keep going */ + CHECKED_DECODE_ONE(mmdb, offset_to_value, &value); + int status = skip_map_or_array(mmdb, &value); + if (MMDB_SUCCESS != status) { + return status; + } + offset = value.offset_to_next; + } + } + + memset(entry_data, 0, sizeof(MMDB_entry_data_s)); + return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; +} + +LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data) +{ + if (entry_data->type == MMDB_DATA_TYPE_MAP) { + uint32_t size = entry_data->data_size; + while (size-- > 0) { + CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // key + CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // value + int status = skip_map_or_array(mmdb, entry_data); + if (MMDB_SUCCESS != status) { + return status; + } + } + } else if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { + uint32_t size = entry_data->data_size; + while (size-- > 0) { + CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // value + int status = skip_map_or_array(mmdb, entry_data); + if (MMDB_SUCCESS != status) { + return status; + } + } + } + + return MMDB_SUCCESS; +} + +LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, + MMDB_entry_data_s *entry_data) +{ + CHECKED_DECODE_ONE(mmdb, offset, entry_data); + if (entry_data->type == MMDB_DATA_TYPE_POINTER) { + uint32_t next = entry_data->offset_to_next; + CHECKED_DECODE_ONE(mmdb, entry_data->pointer, entry_data); + /* Pointers to pointers are illegal under the spec */ + if (entry_data->type == MMDB_DATA_TYPE_POINTER) { + DEBUG_MSG("pointer points to another pointer"); + return MMDB_INVALID_DATA_ERROR; + } + + /* The pointer could point to any part of the data section but the + * next entry for this particular offset may be the one after the + * pointer, not the one after whatever the pointer points to. This + * depends on whether the pointer points to something that is a simple + * value or a compound value. For a compound value, the next one is + * the one after the pointer result, not the one after the pointer. */ + if (entry_data->type != MMDB_DATA_TYPE_MAP + && entry_data->type != MMDB_DATA_TYPE_ARRAY) { + + entry_data->offset_to_next = next; + } + } + + return MMDB_SUCCESS; +} + +#if !MMDB_UINT128_IS_BYTE_ARRAY +NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length) +{ + mmdb_uint128_t value = 0; + while (length-- > 0) { + value <<= 8; + value += *p++; + } + return value; +} +#endif + +LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, + MMDB_entry_data_s *entry_data) +{ + const uint8_t *mem = mmdb->data_section; + + if (offset + 1 > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + + entry_data->offset = offset; + entry_data->has_data = true; + + DEBUG_NL; + DEBUG_MSGF("Offset: %i", offset); + + uint8_t ctrl = mem[offset++]; + DEBUG_BINARY("Control byte: %s", ctrl); + + int type = (ctrl >> 5) & 7; + DEBUG_MSGF("Type: %i (%s)", type, type_num_to_name(type)); + + if (type == MMDB_DATA_TYPE_EXTENDED) { + if (offset + 1 > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + type = get_ext_type(mem[offset++]); + DEBUG_MSGF("Extended type: %i (%s)", type, type_num_to_name(type)); + } + + entry_data->type = type; + + if (type == MMDB_DATA_TYPE_POINTER) { + int psize = (ctrl >> 3) & 3; + DEBUG_MSGF("Pointer size: %i", psize); + + if (offset + psize + 1 > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + entry_data->pointer = get_ptr_from(ctrl, &mem[offset], psize); + DEBUG_MSGF("Pointer to: %i", entry_data->pointer); + + entry_data->data_size = psize + 1; + entry_data->offset_to_next = offset + psize + 1; + return MMDB_SUCCESS; + } + + uint32_t size = ctrl & 31; + switch (size) { + case 29: + if (offset + 1 > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + size = 29 + mem[offset++]; + break; + case 30: + if (offset + 2 > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + size = 285 + get_uint16(&mem[offset]); + offset += 2; + break; + case 31: + if (offset + 3 > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + size = 65821 + get_uint24(&mem[offset]); + offset += 3; + default: + break; + } + + DEBUG_MSGF("Size: %i", size); + + if (type == MMDB_DATA_TYPE_MAP || type == MMDB_DATA_TYPE_ARRAY) { + entry_data->data_size = size; + entry_data->offset_to_next = offset; + return MMDB_SUCCESS; + } + + if (type == MMDB_DATA_TYPE_BOOLEAN) { + entry_data->boolean = size ? true : false; + entry_data->data_size = 0; + entry_data->offset_to_next = offset; + DEBUG_MSGF("boolean value: %s", entry_data->boolean ? "true" : "false"); + return MMDB_SUCCESS; + } + + // check that the data doesn't extend past the end of the memory + // buffer + if (offset + size > mmdb->data_section_size) { + return MMDB_INVALID_DATA_ERROR; + } + + if (type == MMDB_DATA_TYPE_UINT16) { + if (size > 2) { + return MMDB_INVALID_DATA_ERROR; + } + entry_data->uint16 = (uint16_t)get_uintX(&mem[offset], size); + DEBUG_MSGF("uint16 value: %u", entry_data->uint16); + } else if (type == MMDB_DATA_TYPE_UINT32) { + if (size > 4) { + return MMDB_INVALID_DATA_ERROR; + } + entry_data->uint32 = (uint32_t)get_uintX(&mem[offset], size); + DEBUG_MSGF("uint32 value: %u", entry_data->uint32); + } else if (type == MMDB_DATA_TYPE_INT32) { + if (size > 4) { + return MMDB_INVALID_DATA_ERROR; + } + entry_data->int32 = get_sintX(&mem[offset], size); + DEBUG_MSGF("int32 value: %i", entry_data->int32); + } else if (type == MMDB_DATA_TYPE_UINT64) { + if (size > 8) { + return MMDB_INVALID_DATA_ERROR; + } + entry_data->uint64 = get_uintX(&mem[offset], size); + DEBUG_MSGF("uint64 value: %" PRIu64, entry_data->uint64); + } else if (type == MMDB_DATA_TYPE_UINT128) { + if (size > 16) { + return MMDB_INVALID_DATA_ERROR; + } +#if MMDB_UINT128_IS_BYTE_ARRAY + memset(entry_data->uint128, 0, 16); + if (size > 0) { + memcpy(entry_data->uint128 + 16 - size, &mem[offset], size); + } +#else + entry_data->uint128 = get_uint128(&mem[offset], size); +#endif + } else if (type == MMDB_DATA_TYPE_FLOAT) { + if (size != 4) { + return MMDB_INVALID_DATA_ERROR; + } + size = 4; + entry_data->float_value = get_ieee754_float(&mem[offset]); + DEBUG_MSGF("float value: %f", entry_data->float_value); + } else if (type == MMDB_DATA_TYPE_DOUBLE) { + if (size != 8) { + return MMDB_INVALID_DATA_ERROR; + } + size = 8; + entry_data->double_value = get_ieee754_double(&mem[offset]); + DEBUG_MSGF("double value: %f", entry_data->double_value); + } else if (type == MMDB_DATA_TYPE_UTF8_STRING) { + entry_data->utf8_string = size == 0 ? "" : (char *)&mem[offset]; + entry_data->data_size = size; +#ifdef MMDB_DEBUG + char *string = mmdb_strndup(entry_data->utf8_string, + size > 50 ? 50 : size); + if (NULL == string) { + abort(); + } + DEBUG_MSGF("string value: %s", string); + free(string); +#endif + } else if (type == MMDB_DATA_TYPE_BYTES) { + entry_data->bytes = &mem[offset]; + entry_data->data_size = size; + } + + entry_data->offset_to_next = offset + size; + + return MMDB_SUCCESS; +} + +LOCAL int get_ext_type(int raw_ext_type) +{ + return 7 + raw_ext_type; +} + +LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, + int ptr_size) +{ + uint32_t new_offset; + switch (ptr_size) { + case 0: + new_offset = (ctrl & 7) * 256 + ptr[0]; + break; + case 1: + new_offset = 2048 + (ctrl & 7) * 65536 + ptr[0] * 256 + ptr[1]; + break; + case 2: + new_offset = 2048 + 524288 + (ctrl & 7) * 16777216 + get_uint24(ptr); + break; + case 3: + default: + new_offset = get_uint32(ptr); + break; + } + return MMDB_DATA_SECTION_SEPARATOR + new_offset; +} + +int MMDB_get_metadata_as_entry_data_list( + MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list) +{ + MMDB_s metadata_db = make_fake_metadata_db(mmdb); + + MMDB_entry_s metadata_start = { + .mmdb = &metadata_db, + .offset = 0 + }; + + return MMDB_get_entry_data_list(&metadata_start, entry_data_list); +} + +int MMDB_get_entry_data_list( + MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list) +{ + *entry_data_list = new_entry_data_list(); + if (NULL == *entry_data_list) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + return get_entry_data_list(start->mmdb, start->offset, *entry_data_list, 0); +} + +LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, + MMDB_entry_data_list_s *const entry_data_list, + int depth) +{ + if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) { + DEBUG_MSG("reached the maximum data structure depth"); + return MMDB_INVALID_DATA_ERROR; + } + depth++; + CHECKED_DECODE_ONE(mmdb, offset, &entry_data_list->entry_data); + + switch (entry_data_list->entry_data.type) { + case MMDB_DATA_TYPE_POINTER: + { + uint32_t next_offset = entry_data_list->entry_data.offset_to_next; + uint32_t last_offset; + CHECKED_DECODE_ONE(mmdb, last_offset = + entry_data_list->entry_data.pointer, + &entry_data_list->entry_data); + + /* Pointers to pointers are illegal under the spec */ + if (entry_data_list->entry_data.type == MMDB_DATA_TYPE_POINTER) { + DEBUG_MSG("pointer points to another pointer"); + return MMDB_INVALID_DATA_ERROR; + } + + if (entry_data_list->entry_data.type == MMDB_DATA_TYPE_ARRAY + || entry_data_list->entry_data.type == MMDB_DATA_TYPE_MAP) { + + int status = + get_entry_data_list(mmdb, last_offset, entry_data_list, + depth); + if (MMDB_SUCCESS != status) { + return status; + } + } + entry_data_list->entry_data.offset_to_next = next_offset; + } + break; + case MMDB_DATA_TYPE_ARRAY: + { + uint32_t array_size = entry_data_list->entry_data.data_size; + uint32_t array_offset = entry_data_list->entry_data.offset_to_next; + MMDB_entry_data_list_s *previous = entry_data_list; + while (array_size-- > 0) { + MMDB_entry_data_list_s *entry_data_list_to = previous->next = + new_entry_data_list(); + if (NULL == entry_data_list_to) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + + int status = + get_entry_data_list(mmdb, array_offset, entry_data_list_to, + depth); + if (MMDB_SUCCESS != status) { + return status; + } + + array_offset = entry_data_list_to->entry_data.offset_to_next; + while (previous->next) { + previous = previous->next; + } + } + entry_data_list->entry_data.offset_to_next = array_offset; + + } + break; + case MMDB_DATA_TYPE_MAP: + { + uint32_t size = entry_data_list->entry_data.data_size; + + offset = entry_data_list->entry_data.offset_to_next; + MMDB_entry_data_list_s *previous = entry_data_list; + while (size-- > 0) { + MMDB_entry_data_list_s *entry_data_list_to = previous->next = + new_entry_data_list(); + if (NULL == entry_data_list_to) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + + int status = + get_entry_data_list(mmdb, offset, entry_data_list_to, + depth); + if (MMDB_SUCCESS != status) { + return status; + } + + while (previous->next) { + previous = previous->next; + } + + offset = entry_data_list_to->entry_data.offset_to_next; + entry_data_list_to = previous->next = + new_entry_data_list(); + + if (NULL == entry_data_list_to) { + return MMDB_OUT_OF_MEMORY_ERROR; + } + + status = get_entry_data_list(mmdb, offset, entry_data_list_to, + depth); + if (MMDB_SUCCESS != status) { + return status; + } + + while (previous->next) { + previous = previous->next; + } + offset = entry_data_list_to->entry_data.offset_to_next; + } + entry_data_list->entry_data.offset_to_next = offset; + } + break; + default: + break; + } + + return MMDB_SUCCESS; +} + +LOCAL float get_ieee754_float(const uint8_t *restrict p) +{ + volatile float f; + uint8_t *q = (void *)&f; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + q[3] = p[0]; + q[2] = p[1]; + q[1] = p[2]; + q[0] = p[3]; +#else + memcpy(q, p, 4); +#endif + return f; +} + +LOCAL double get_ieee754_double(const uint8_t *restrict p) +{ + volatile double d; + uint8_t *q = (void *)&d; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + q[7] = p[0]; + q[6] = p[1]; + q[5] = p[2]; + q[4] = p[3]; + q[3] = p[4]; + q[2] = p[5]; + q[1] = p[6]; + q[0] = p[7]; +#else + memcpy(q, p, 8); +#endif + + return d; +} + +LOCAL uint32_t get_uint32(const uint8_t *p) +{ + return p[0] * 16777216U + p[1] * 65536 + p[2] * 256 + p[3]; +} + +LOCAL uint32_t get_uint24(const uint8_t *p) +{ + return p[0] * 65536U + p[1] * 256 + p[2]; +} + +LOCAL uint32_t get_uint16(const uint8_t *p) +{ + return p[0] * 256U + p[1]; +} + +LOCAL uint64_t get_uintX(const uint8_t *p, int length) +{ + uint64_t value = 0; + while (length-- > 0) { + value <<= 8; + value += *p++; + } + return value; +} + +LOCAL int32_t get_sintX(const uint8_t *p, int length) +{ + return (int32_t)get_uintX(p, length); +} + +LOCAL MMDB_entry_data_list_s *new_entry_data_list(void) +{ + /* We need calloc here in order to ensure that the ->next pointer in the + * struct doesn't point to some random address. */ + return calloc(1, sizeof(MMDB_entry_data_list_s)); +} + +void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list) +{ + if (entry_data_list == NULL) { + return; + } + if (entry_data_list->next) { + MMDB_free_entry_data_list(entry_data_list->next); + } + free(entry_data_list); +} + +void MMDB_close(MMDB_s *const mmdb) +{ + free_mmdb_struct(mmdb); +} + +LOCAL void free_mmdb_struct(MMDB_s *const mmdb) +{ + if (!mmdb) { + return; + } + + if (NULL != mmdb->filename) { + FREE_AND_SET_NULL(mmdb->filename); + } + if (NULL != mmdb->file_content) { +#ifdef _WIN32 + UnmapViewOfFile(mmdb->file_content); + /* Winsock is only initialized if open was successful so we only have + * to cleanup then. */ + WSACleanup(); +#else + munmap((void *)mmdb->file_content, mmdb->file_size); +#endif + } + + if (NULL != mmdb->metadata.database_type) { + FREE_AND_SET_NULL(mmdb->metadata.database_type); + } + + free_languages_metadata(mmdb); + free_descriptions_metadata(mmdb); +} + +LOCAL void free_languages_metadata(MMDB_s *mmdb) +{ + if (!mmdb->metadata.languages.count) { + return; + } + + for (size_t i = 0; i < mmdb->metadata.languages.count; i++) { + FREE_AND_SET_NULL(mmdb->metadata.languages.names[i]); + } + FREE_AND_SET_NULL(mmdb->metadata.languages.names); +} + +LOCAL void free_descriptions_metadata(MMDB_s *mmdb) +{ + if (!mmdb->metadata.description.count) { + return; + } + + for (size_t i = 0; i < mmdb->metadata.description.count; i++) { + if (NULL != mmdb->metadata.description.descriptions[i]) { + if (NULL != + mmdb->metadata.description.descriptions[i]->language) { + FREE_AND_SET_NULL( + mmdb->metadata.description.descriptions[i]->language); + } + + if (NULL != + mmdb->metadata.description.descriptions[i]->description) { + FREE_AND_SET_NULL( + mmdb->metadata.description.descriptions[i]->description); + } + FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]); + } + } + + FREE_AND_SET_NULL(mmdb->metadata.description.descriptions); +} + +const char *MMDB_lib_version(void) +{ + return PACKAGE_VERSION; +} + +int MMDB_dump_entry_data_list(FILE *const stream, + MMDB_entry_data_list_s *const entry_data_list, + int indent) +{ + int status; + dump_entry_data_list(stream, entry_data_list, indent, &status); + return status; +} + +LOCAL MMDB_entry_data_list_s *dump_entry_data_list( + FILE *stream, MMDB_entry_data_list_s *entry_data_list, int indent, + int *status) +{ + switch (entry_data_list->entry_data.type) { + case MMDB_DATA_TYPE_MAP: + { + uint32_t size = entry_data_list->entry_data.data_size; + + print_indentation(stream, indent); + fprintf(stream, "{\n"); + indent += 2; + + for (entry_data_list = entry_data_list->next; + size && entry_data_list; size--) { + + if (MMDB_DATA_TYPE_UTF8_STRING != + entry_data_list->entry_data.type) { + *status = MMDB_INVALID_DATA_ERROR; + return NULL; + } + char *key = + mmdb_strndup( + (char *)entry_data_list->entry_data.utf8_string, + entry_data_list->entry_data.data_size); + if (NULL == key) { + *status = MMDB_OUT_OF_MEMORY_ERROR; + return NULL; + } + + print_indentation(stream, indent); + fprintf(stream, "\"%s\": \n", key); + free(key); + + entry_data_list = entry_data_list->next; + entry_data_list = + dump_entry_data_list(stream, entry_data_list, indent + 2, + status); + + if (MMDB_SUCCESS != *status) { + return NULL; + } + } + + indent -= 2; + print_indentation(stream, indent); + fprintf(stream, "}\n"); + } + break; + case MMDB_DATA_TYPE_ARRAY: + { + uint32_t size = entry_data_list->entry_data.data_size; + + print_indentation(stream, indent); + fprintf(stream, "[\n"); + indent += 2; + + for (entry_data_list = entry_data_list->next; + size && entry_data_list; size--) { + entry_data_list = + dump_entry_data_list(stream, entry_data_list, indent, + status); + if (MMDB_SUCCESS != *status) { + return NULL; + } + } + + indent -= 2; + print_indentation(stream, indent); + fprintf(stream, "]\n"); + } + break; + case MMDB_DATA_TYPE_UTF8_STRING: + { + char *string = + mmdb_strndup((char *)entry_data_list->entry_data.utf8_string, + entry_data_list->entry_data.data_size); + if (NULL == string) { + *status = MMDB_OUT_OF_MEMORY_ERROR; + return NULL; + } + print_indentation(stream, indent); + fprintf(stream, "\"%s\" \n", string); + free(string); + entry_data_list = entry_data_list->next; + } + break; + case MMDB_DATA_TYPE_BYTES: + { + char *hex_string = + bytes_to_hex((uint8_t *)entry_data_list->entry_data.bytes, + entry_data_list->entry_data.data_size); + if (NULL == hex_string) { + *status = MMDB_OUT_OF_MEMORY_ERROR; + return NULL; + } + + print_indentation(stream, indent); + fprintf(stream, "%s \n", hex_string); + free(hex_string); + + entry_data_list = entry_data_list->next; + } + break; + case MMDB_DATA_TYPE_DOUBLE: + print_indentation(stream, indent); + fprintf(stream, "%f \n", + entry_data_list->entry_data.double_value); + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_FLOAT: + print_indentation(stream, indent); + fprintf(stream, "%f \n", + entry_data_list->entry_data.float_value); + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_UINT16: + print_indentation(stream, indent); + fprintf(stream, "%u \n", entry_data_list->entry_data.uint16); + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_UINT32: + print_indentation(stream, indent); + fprintf(stream, "%u \n", entry_data_list->entry_data.uint32); + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_BOOLEAN: + print_indentation(stream, indent); + fprintf(stream, "%s \n", + entry_data_list->entry_data.boolean ? "true" : "false"); + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_UINT64: + print_indentation(stream, indent); + fprintf(stream, "%" PRIu64 " \n", + entry_data_list->entry_data.uint64); + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_UINT128: + print_indentation(stream, indent); +#if MMDB_UINT128_IS_BYTE_ARRAY + char *hex_string = + bytes_to_hex((uint8_t *)entry_data_list->entry_data.uint128, 16); + if (NULL == hex_string) { + *status = MMDB_OUT_OF_MEMORY_ERROR; + return NULL; + } + fprintf(stream, "0x%s \n", hex_string); + free(hex_string); +#else + uint64_t high = entry_data_list->entry_data.uint128 >> 64; + uint64_t low = (uint64_t)entry_data_list->entry_data.uint128; + fprintf(stream, "0x%016" PRIX64 "%016" PRIX64 " \n", high, + low); +#endif + entry_data_list = entry_data_list->next; + break; + case MMDB_DATA_TYPE_INT32: + print_indentation(stream, indent); + fprintf(stream, "%d \n", entry_data_list->entry_data.int32); + entry_data_list = entry_data_list->next; + break; + default: + *status = MMDB_INVALID_DATA_ERROR; + return NULL; + } + + *status = MMDB_SUCCESS; + return entry_data_list; +} + +LOCAL void print_indentation(FILE *stream, int i) +{ + char buffer[1024]; + int size = i >= 1024 ? 1023 : i; + memset(buffer, 32, size); + buffer[size] = '\0'; + fputs(buffer, stream); +} + +LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size) +{ + char *hex_string; + MAYBE_CHECK_SIZE_OVERFLOW(size, SIZE_MAX / 2 - 1, NULL); + + hex_string = malloc((size * 2) + 1); + if (NULL == hex_string) { + return NULL; + } + + for (uint32_t i = 0; i < size; i++) { + sprintf(hex_string + (2 * i), "%02X", bytes[i]); + } + + return hex_string; +} + +const char *MMDB_strerror(int error_code) +{ + switch (error_code) { + case MMDB_SUCCESS: + return "Success (not an error)"; + case MMDB_FILE_OPEN_ERROR: + return "Error opening the specified MaxMind DB file"; + case MMDB_CORRUPT_SEARCH_TREE_ERROR: + return "The MaxMind DB file's search tree is corrupt"; + case MMDB_INVALID_METADATA_ERROR: + return "The MaxMind DB file contains invalid metadata"; + case MMDB_IO_ERROR: + return "An attempt to read data from the MaxMind DB file failed"; + case MMDB_OUT_OF_MEMORY_ERROR: + return "A memory allocation call failed"; + case MMDB_UNKNOWN_DATABASE_FORMAT_ERROR: + return + "The MaxMind DB file is in a format this library can't handle (unknown record size or binary format version)"; + case MMDB_INVALID_DATA_ERROR: + return + "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"; + case MMDB_INVALID_LOOKUP_PATH_ERROR: + return + "The lookup path contained an invalid value (like a negative integer for an array index)"; + case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR: + return + "The lookup path does not match the data (key that doesn't exist, array index bigger than the array, expected array or map where none exists)"; + case MMDB_INVALID_NODE_NUMBER_ERROR: + return + "The MMDB_read_node function was called with a node number that does not exist in the search tree"; + case MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR: + return + "You attempted to look up an IPv6 address in an IPv4-only database"; + default: + return "Unknown error code"; + } +} diff --git a/external/RandomLib/LICENSE.txt b/external/RandomLib/LICENSE.txt deleted file mode 100644 index 78f3414c..00000000 --- a/external/RandomLib/LICENSE.txt +++ /dev/null @@ -1,23 +0,0 @@ -This license applies to RandomLib, versions 1.2 and later. - -Copyright (c) 2006-2013, Charles Karney - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/external/RandomLib/Random.cpp b/external/RandomLib/Random.cpp deleted file mode 100644 index 1b752095..00000000 --- a/external/RandomLib/Random.cpp +++ /dev/null @@ -1,1405 +0,0 @@ -/** - * \file Random.cpp - * \brief Implementation code for %RandomLib - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - * - * \brief Code for MixerMT0, MixerMT1, MixerSFMT. - * - * MixerMT0 is adapted from MT19937 (init_by_array) and MT19937_64 - * (init_by_array64) by Makoto Matsumoto and Takuji Nishimura. See - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c and - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c - * - * MixerMT1 contains modifications to MixerMT0 by Charles Karney to - * correct defects in MixerMT0. This is described in W. E. Brown, - * M. Fischler, J. Kowalkowski, M. Paterno, Random Number Generation in C++0X: - * A Comprehensive Proposal, version 3, Sept 2006, Sec. 26.4.7.1, - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf - * This has been replaced in the C++11 standard by MixerSFMT. - * - * MixerSFMT is adapted from SFMT19937's init_by_array Mutsuo Saito given in - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz and - * is part of the C++11 standard; see P. Becker, Working Draft, Standard for - * Programming Language C++, Oct. 2007, Sec. 26.4.7.1, - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf - * - * The adaption to the C++ is copyright (c) Charles Karney (2006-2011) - * and licensed under the MIT/X11 License. For more - * information, see http://randomlib.sourceforge.net/ - * - * \brief Code for MT19937 and SFMT19937. - * - * MT19937 is adapted from MT19937 and MT19937_64 by Makoto Matsumoto and - * Takuji Nishimura. See - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c and - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c - * - * The code for stepping MT19937 backwards is adapted (and simplified) from - * revrand() by Katsumi Hagita. See - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/REVmt19937b.f - * - * SFMT19937 is adapted from SFMT19937 Mutsuo Saito given in - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/M062821.pdf and - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz - * - * The code for stepping SFMT19937 backwards is by Charles Karney. - * - * The adaption to the C++ is copyright (c) Charles Karney (2006-2011) - * and licensed under the MIT/X11 License. For more - * information, see http://randomlib.sourceforge.net/ - **********************************************************************/ - -#define RANDOMLIB_RANDOM_CPP 1 - -/** - * Let the header file know that the library is being built. - **********************************************************************/ -#define RANDOMLIB_BUILDING_LIBRARY 1 - -#include - -#if defined(_MSC_VER) || defined(__MINGW32__) -#define RANDOMLIB_WINDOWS 1 -#else -#define RANDOMLIB_WINDOWS 0 -#endif - -#include // For SeedWord reading /dev/urandom -#include // For SeedWord calling time() -#include // For formatting in Write32/Read32 -#include // For formatting in Write32/Read32 -#if !RANDOMLIB_WINDOWS -#include // For SeedWord calling gettimeofday -#include // For SeedWord calling getpid(), gethostid() -#else -#include // For SeedWord calling high prec timer -#include -#include // For SeedWord calling getpid() -#define getpid _getpid -#define gmtime_r(t,g) gmtime_s(g,t) -#endif - -#if RANDOMLIB_WINDOWS || defined(__CYGWIN__) -#define strtoull strtoul -#endif - -#if defined(_MSC_VER) -// Squelch warnings about constant conditional expressions -# pragma warning (disable: 4127) -#endif - -namespace RandomLib { - - // RandomType implementation - - template<> - void Random_u32::Write32(std::ostream& os, bool bin, int& cnt, - Random_u32::type x) { - if (bin) { - unsigned char buf[4]; - // Use network order -- most significant byte first - buf[3] = (unsigned char)(x); - buf[2] = (unsigned char)(x >>= 8); - buf[1] = (unsigned char)(x >>= 8); - buf[0] = (unsigned char)(x >>= 8); - os.write(reinterpret_cast(buf), 4); - } else { - const int longsperline = 72/9; - // Use hexadecimal to minimize storage together with stringstream to - // isolate the effect of changing the base. - std::ostringstream str; - // No spacing before or after - if (cnt > 0) - // Newline every longsperline longs - str << (cnt % longsperline ? ' ' : '\n'); - str << std::hex << x; - os << str.str(); - ++cnt; - } - } - - template<> - void Random_u32::Read32(std::istream& is, bool bin, Random_u32::type& x) { - if (bin) { - unsigned char buf[4]; - is.read(reinterpret_cast(buf), 4); - // Use network order -- most significant byte first - x = Random_u32::type(buf[0]) << 24 | Random_u32::type(buf[1]) << 16 | - Random_u32::type(buf[2]) << 8 | Random_u32::type(buf[3]); - } else { - std::string s; - is >> std::ws >> s; - // Use hexadecimal to minimize storage together with stringstream to - // isolate the effect of changing the base. - std::istringstream str(s); - str >> std::hex >> x; - } - x &= Random_u32::mask; - } - - template<> - void Random_u64::Write32(std::ostream& os, bool bin, int& cnt, - Random_u64::type x) { - Random_u32::Write32(os, bin, cnt, Random_u32::cast(x >> 32)); - Random_u32::Write32(os, bin, cnt, Random_u32::cast(x )); - } - - template<> - void Random_u64::Read32(std::istream& is, bool bin, Random_u64::type& x) { - Random_u32::type t; - Random_u32::Read32(is, bin, t); - x = Random_u64::type(t) << 32; - Random_u32::Read32(is, bin, t); - x |= Random_u64::type(t); - } - - // RandomSeed implementation - - RandomSeed::seed_type RandomSeed::SeedWord() { - // Check that the assumptions made about the capabilities of the number - // system are valid. - STATIC_ASSERT(std::numeric_limits::radix == 2 && - !std::numeric_limits::is_signed && - std::numeric_limits::digits >= 32, - "seed_type is a bad type"); - u32::type t = 0; - // Linux has /dev/urandom to initialize the seed randomly. (Use - // /dev/urandom instead of /dev/random because it does not block.) - { - std::ifstream f("/dev/urandom", std::ios::binary | std::ios::in); - if (f.good()) { - // Read 32 bits from /dev/urandom - f.read(reinterpret_cast(&t), sizeof(t)); - } - } - std::vector v = SeedVector(); - for (size_t i = v.size(); i--;) - u32::CheckSum(u32::type(v[i]), t); - return seed_t::cast(t); - } - - std::vector RandomSeed::SeedVector() { - std::vector v; - { - // fine-grained timer -#if !RANDOMLIB_WINDOWS - timeval tv; - if (gettimeofday(&tv, 0) == 0) - v.push_back(seed_t::cast(tv.tv_usec)); -#else - LARGE_INTEGER taux; - if (QueryPerformanceCounter((LARGE_INTEGER *)&taux)) { - v.push_back(seed_t::cast(taux.LowPart)); - v.push_back(seed_t::cast(taux.HighPart)); - } -#endif - } - // seconds - const time_t tim = std::time(0); - v.push_back(seed_t::cast(seed_type(tim))); - // PID - v.push_back(seed_t::cast(getpid())); -#if !RANDOMLIB_WINDOWS - // host ID - v.push_back(seed_t::cast(gethostid())); -#endif - { - // year -#if !defined(__MINGW32__) - tm gt; - gmtime_r(&tim, >); - v.push_back((seed_type(1900) + seed_t::cast(gt.tm_year))); -#else - tm* gt = gmtime(&tim); - v.push_back((seed_type(1900) + seed_t::cast(gt->tm_year))); -#endif - } - // Candidates for additional elements: - // ip address(es) of computer, thread index. - std::transform(v.begin(), v.end(), v.begin(), seed_t::cast); - return v; - } - - std::vector - RandomSeed::StringToVector(const std::string& s) { - std::vector v(0); - const char* c = s.c_str(); - char* q; - std::string::size_type p = 0; - while (true) { - p = s.find_first_of("0123456789", p); - if (p == std::string::npos) - break; - v.push_back(seed_t::cast(std::strtoull(c + p, &q, 0))); - p = q - c; - } - return v; - } - - // RandomEngine implementation - - template - void RandomEngine::Init() throw() { - // On exit we have _ptr == N. - - STATIC_ASSERT(std::numeric_limits::radix == 2 && - !std::numeric_limits::is_signed && - std::numeric_limits::digits >= - int(mixer_t::width), - "mixer_type is a bad type"); - - STATIC_ASSERT(std::numeric_limits::radix == 2 && - !std::numeric_limits::is_signed && - std::numeric_limits::digits >= width, - "engine_type is a bad type"); - - STATIC_ASSERT(mixer_t::width == 32 || mixer_t::width == 64, - "Mixer width must be 32 or 64"); - - STATIC_ASSERT(width == 32 || width == 64, - "Algorithm width must be 32 or 64"); - - // If the bit-widths are the same then the data sizes must be the same. - STATIC_ASSERT(!(mixer_t::width == width) || - sizeof(_stateu) == sizeof(_state), - "Same bit-widths but different storage"); - - // Repacking assumes that narrower data type is at least as wasteful than - // the broader one. - STATIC_ASSERT(!(mixer_t::width < width) || - sizeof(_stateu) >= sizeof(_state), - "Narrow data type uses less storage"); - - STATIC_ASSERT(!(mixer_t::width > width) || - sizeof(_stateu) <= sizeof(_state), - "Narrow data type uses less storage"); - - // Require that _statev and _state are aligned since no repacking is done - // when calling Transition - STATIC_ASSERT(sizeof(_statev) == sizeof(_state), - "Storage mismatch with internal engine data type"); - - // Convert the seed into state - Mixer::SeedToState(_seed, _stateu, NU); - - // Pack into _state - if (mixer_t::width < width) { - for (size_t i = 0; i < N; ++i) - // Assume 2:1 LSB packing - _state[i] = result_type(_stateu[2*i]) | - result_type(_stateu[2*i + 1]) << - (mixer_t::width < width ? mixer_t::width : 0); - } else if (mixer_t::width > width) { - for (size_t i = N; i--;) - // Assume 1:2 LSB packing - _state[i] = result_t::cast(_stateu[i>>1] >> width * (i&1u)); - } // Otherwise the union takes care of it - - Algorithm::NormalizeState(_state); - - _rounds = -1; - _ptr = N; - } - - template Random_u32::type - RandomEngine::Check(u64::type v, u32::type e, - u32::type m) const { - if (v != version) - throw RandomErr(Name() + ": Unknown version"); - if (e != Algorithm::version) - throw RandomErr(Name() + ": Algorithm mismatch"); - if (m != Mixer::version) - throw RandomErr(Name() + ": Mixer mismatch"); - u32::type check = 0; - u64::CheckSum(v, check); - u32::CheckSum(e, check); - u32::CheckSum(m, check); - u32::CheckSum(u32::type(_seed.size()), check); - for (std::vector::const_iterator n = _seed.begin(); - n != _seed.end(); ++n) { - if (*n != seed_t::cast(*n)) - throw RandomErr(Name() + ": Illegal seed value"); - u32::CheckSum(u32::type(*n), check); - } - u32::CheckSum(_ptr, check); - if (_stride == 0 || _stride > UNINIT/2) - throw RandomErr(Name() + ": Invalid stride"); - u32::CheckSum(_stride, check); - if (_ptr != UNINIT) { - if (_ptr >= N + _stride) - throw RandomErr(Name() + ": Invalid pointer"); - u64::CheckSum(_rounds, check); - Algorithm::CheckState(_state, check); - } - return check; - } - - template - RandomEngine::RandomEngine(std::istream& is, bool bin) { - u64::type versionr; - u32::type versione, versionm, t; - u64::Read32(is, bin, versionr); - u32::Read32(is, bin, versione); - u32::Read32(is, bin, versionm); - u32::Read32(is, bin, t); - _seed.resize(size_t(t)); - for (std::vector::iterator n = _seed.begin(); - n != _seed.end(); ++n) { - u32::Read32(is, bin, t); - *n = seed_type(t); - } - u32::Read32(is, bin, t); - // Don't need to worry about sign extension because _ptr is unsigned. - _ptr = unsigned(t); - u32::Read32(is, bin, t); - _stride = unsigned(t); - if (_ptr != UNINIT) { - u64::type p; - u64::Read32(is, bin, p); - _rounds = (long long)(p); - // Sign extension in case long long is bigger than 64 bits. - _rounds <<= 63 - std::numeric_limits::digits; - _rounds >>= 63 - std::numeric_limits::digits; - for (unsigned i = 0; i < N; ++i) - result_t::Read32(is, bin, _state[i]); - } - u32::Read32(is, bin, t); - if (t != Check(versionr, versione, versionm)) - throw RandomErr(Name() + ": Checksum failure"); - } - - template - void RandomEngine::Save(std::ostream& os, - bool bin) const { - u32::type check = Check(version, Algorithm::version, Mixer::version); - int c = 0; - u64::Write32(os, bin, c, version); - u32::Write32(os, bin, c, Algorithm::version); - u32::Write32(os, bin, c, Mixer::version); - u32::Write32(os, bin, c, u32::type(_seed.size())); - for (std::vector::const_iterator n = _seed.begin(); - n != _seed.end(); ++n) - u32::Write32(os, bin, c, u32::type(*n)); - u32::Write32(os, bin, c, _ptr); - u32::Write32(os, bin, c, _stride); - if (_ptr != UNINIT) { - u64::Write32(os, bin, c, u64::type(_rounds)); - for (unsigned i = 0; i < N; ++i) - result_t::Write32(os, bin, c, _state[i]); - } - u32::Write32(os, bin, c, check); - } - - template - void RandomEngine::StepCount(long long n) throw() { - // On exit we have 0 <= _ptr <= N. - if (_ptr == UNINIT) - Init(); - const long long ncount = n + Count(); // new Count() - long long nrounds = ncount / N; - int nptr = int(ncount - nrounds * N); - // We pick _ptr = N or _ptr = 0 depending on which choice involves the - // least work. We thus avoid doing one (potentially unneeded) call to - // Transition. - if (nptr < 0) { - --nrounds; - nptr += N; - } else if (nptr == 0 && nrounds > _rounds) { - nptr = N; - --nrounds; - } - if (nrounds != _rounds) - Algorithm::Transition(nrounds - _rounds, _statev); - _rounds = nrounds; - _ptr = nptr; - } - - template - void RandomEngine::SelfTest() { - RandomEngine g(std::vector(0)); - g.SetCount(10000-1); - result_type x = g(); - if (SelfTestResult(0) && x != SelfTestResult(1)) - throw RandomErr(Name() + ": Incorrect result with seed " + - g.SeedString()); - seed_type s[] = {0x1234U, 0x5678U, 0x9abcU, 0xdef0U}; - // seed_type s[] = {1, 2, 3, 4}; - g.Reseed(s, s+4); - g.StepCount(-20000); - std::string save; - { - std::ostringstream stream; - stream << g << "\n"; - save = stream.str(); - } - g.Reset(); - { - std::istringstream stream(save); - stream >> g; - } - g.SetCount(10000); - { - std::ostringstream stream; - g.Save(stream, true); - save = stream.str(); - } - { - std::istringstream stream(save); - RandomEngine h(std::vector(0)); - h.Load(stream, true); - h.SetCount(1000000-1); - x = h(); - if (SelfTestResult(0) && x != SelfTestResult(2)) - throw RandomErr(Name() + ": Incorrect result with seed " + - h.SeedString()); - g.SetCount(1000000); - if (h != g) - throw RandomErr(Name() + ": Comparison failure"); - } - } - - template<> Random_u32::type - RandomEngine, MixerMT0 >:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 4123659995UL : 3016432305UL; - } - - template<> Random_u64::type - RandomEngine, MixerMT0 >:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 9981545732273789042ULL : 1384037754719008581ULL; - } - - template<> Random_u32::type - RandomEngine, MixerMT1 >:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 4123659995UL : 2924523180UL; - } - - template<> Random_u64::type - RandomEngine, MixerMT1 >:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 9981545732273789042ULL : 5481486777409645478ULL; - } - - template<> Random_u32::type - RandomEngine, MixerSFMT>:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 666528879UL : 2183745132UL; - } - - template<> Random_u64::type - RandomEngine, MixerSFMT>:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 12176471137395770412ULL : 66914054428611861ULL; - } - - template<> Random_u32::type - RandomEngine, MixerSFMT>:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 2695024307UL : 782200760UL; - } - - template<> Random_u64::type - RandomEngine, MixerSFMT>:: - SelfTestResult(unsigned i) throw() { - return i == 0 ? 1 : - i == 1 ? 1464461649847485149ULL : 5050640804923595109ULL; - } - - // RandomMixer implementation - - template void MixerMT0:: - SeedToState(const std::vector& seed, - mixer_type state[], unsigned n) throw() { - // Adapted from - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c - const unsigned s = unsigned(seed.size()); - const unsigned w = mixer_t::width; - - mixer_type r = s ? a1 + mixer_type(0) : a0 + mixer_type(0); - state[0] = r; - for (unsigned k = 1; k < n; ++k) { - r = b * (r ^ r >> (w - 2)) + k; - r &= mask; - state[k] = r; - } - if (s > 0) { - const unsigned m = mixer_t::width / 32, - s2 = (s + m - 1)/m; - unsigned i1 = 1; - r = state[0]; - for (unsigned k = (n > s2 ? n : s2), j = 0; - k; --k, i1 = i1 == n - 1 ? 1 : i1 + 1, // i1 = i1 + 1 mod n - 1 - j = j == s2 - 1 ? 0 : j + 1 ) { // j = j+1 mod s2 - r = state[i1] ^ c * (r ^ r >> (w - 2)); - r += j + mixer_type(seed[m * j]) + - (m == 1 || 2 * j + 1 == s ? mixer_type(0) : - mixer_type(seed[m * j + 1]) << (w - 32)); - r &= mask; - state[i1] = r; - } - for (unsigned k = n - 1; k; --k, - i1 = i1 == n - 1 ? 1 : i1 + 1) { // i1 = i1 + 1 mod n - 1 - r = state[i1] ^ d * (r ^ r >> (w - 2)); - r -= i1; - r &= mask; - state[i1] = r; - } - state[0] = typename mixer_t::type(1) << (w - 1); - } - } - - template void MixerMT1:: - SeedToState(const std::vector& seed, - mixer_type state[], unsigned n) throw() { - // This is the algorithm given in the seed_seq class described in - // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf It is - // a modification of - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c - const unsigned s = unsigned(seed.size()); - const unsigned w = mixer_t::width; - - mixer_type r = (a + s) & mask; - state[0] = r; - for (unsigned k = 1; k < n; ++k) { - r = b * (r ^ r >> (w - 2)) + k; - r &= mask; - state[k] = r; - } - if (s > 0) { - const unsigned m = mixer_t::width / 32, - s2 = (s + m - 1)/m; - unsigned i1 = 0; - for (unsigned k = (n > s2 ? n : s2), j = 0; - k; --k, i1 = i1 == n - 1 ? 0 : i1 + 1, // i1 = i1 + 1 mod n - j = j == s2 - 1 ? 0 : j + 1 ) { // j = j+1 mod s2 - r = state[i1] ^ c * (r ^ r >> (w - 2)); - r += j + mixer_type(seed[m * j]) + - (m == 1 || 2 * j + 1 == s ? mixer_type(0) : - mixer_type(seed[m * j + 1]) << (w - 32)); - r &= mask; - state[i1] = r; - } - for (unsigned k = n; k; --k, - i1 = i1 == n - 1 ? 0 : i1 + 1) { // i1 = i1 + 1 mod n - r = state[i1] ^ d * (r ^ r >> (w - 2)); - r -= i1; - r &= mask; - state[i1] = r; - } - } - } - - void MixerSFMT::SeedToState(const std::vector& seed, - mixer_type state[], unsigned n) throw() { - // This is adapted from the routine init_by_array by Mutsuo Saito given in - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz - - if (n == 0) - return; // Nothing to do - - const unsigned s = unsigned(seed.size()), - // Add treatment of small n with lag = (n - 1)/2 for n <= 7. In - // particular, the first operation (xor or plus) in each for loop - // involves three distinct indices for n > 2. - lag = n >= 623 ? 11 : (n >= 68 ? 7 : (n >= 39 ? 5 : - (n >= 7 ? 3 : (n - 1)/2))), - // count = max( s + 1, n ) - count = s + 1 > n ? s + 1 : n; - - std::fill(state, state + n, mixer_type(a)); - const unsigned w = mixer_t::width; - - unsigned i = 0, k = (n - lag) / 2, l = k + lag; - mixer_type r = state[n - 1]; - for (unsigned j = 0; j < count; ++j, - i = i == n - 1 ? 0 : i + 1, - k = k == n - 1 ? 0 : k + 1, - l = l == n - 1 ? 0 : l + 1) { - // Here r = state[(j - 1) mod n] - // i = j mod n - // k = (j + (n - lag)/2) mod n - // l = (j + (n - lag)/2 + lag) mod n - r ^= state[i] ^ state[k]; - r &= mask; - r = b * (r ^ r >> (w - 5)); - state[k] += r; - r += i + (j > s ? 0 : (j ? mixer_type(seed[j - 1]) : s)); - state[l] += r; - state[i] = r; - } - - for (unsigned j = n; j; --j, - i = i == n - 1 ? 0 : i + 1, - k = k == n - 1 ? 0 : k + 1, - l = l == n - 1 ? 0 : l + 1) { - // Here r = state[(i - 1) mod n] - // k = (i + (n - lag)/2) mod n - // l = (i + (n - lag)/2 + lag) mod n - r += state[i] + state[k]; - r &= mask; - r = c * (r ^ r >> (w - 5)); - r &= mask; - state[k] ^= r; - r -= i; - r &= mask; - state[l] ^= r; - state[i] = r; - } - } - - // RandomAlgorithm implementation - - // Here, input is I, J = I + 1, K = I + M; output is I = I + N (mod N) - -#define MT19937_STEP(I, J, K) statev[I] = statev[K] ^ \ - (statev[J] & engine_type(1) ? magic : engine_type(0)) ^ \ - ((statev[I] & upper) | (statev[J] & lower)) >> 1 - - // The code is cleaned up a little from Hagita's Fortran version by getting - // rid of the unnecessary masking by YMASK and by using simpler logic to - // restore the correct value of _state[0]. - // - // Here input is J = I + N - 1, K = I + M - 1, and p = y[I] (only the high - // bits are used); output _state[I] and p = y[I - 1]. - -#define MT19937_REVSTEP(I, J, K) { \ - engine_type q = statev[J] ^ statev[K], s = q >> (width - 1); \ - q = (q ^ (s ? magic : engine_type(0))) << 1 | s; \ - statev[I] = (p & upper) | (q & lower); \ - p = q; \ - } - - template - void MT19937::Transition(long long count, internal_type statev[]) - throw() { - if (count > 0) - for (; count; --count) { - // This ONLY uses high bit of statev[0] - unsigned i = 0; - for (; i < N - M; ++i) MT19937_STEP(i, i + 1, i + M ); - for (; i < N - 1; ++i) MT19937_STEP(i, i + 1, i + M - N); - MT19937_STEP(N - 1, 0, M - 1); // i = N - 1 - } - else if (count < 0) - for (; count; ++count) { - // This ONLY uses high bit of statev[0] - engine_type p = statev[0]; - // Fix low bits of statev[0] and compute y[-1] - MT19937_REVSTEP(0, N - 1, M - 1); // i = N - unsigned i = N - 1; - for (; i > N - M; --i) MT19937_REVSTEP(i, i - 1, i + M - 1 - N); - for (; i ; --i) MT19937_REVSTEP(i, i - 1, i + M - 1 ); - MT19937_REVSTEP(0, N - 1, M - 1); // i = 0 - } - } - -#undef MT19937_STEP -#undef MT19937_REVSTEP - - template - void MT19937::NormalizeState(engine_type state[]) throw() { - - // Perform the MT-specific sanity check on the resulting state ensuring - // that the significant 19937 bits are not all zero. - state[0] &= upper; // Mask out unused bits - unsigned i = 0; - while (i < N && state[i] == 0) - ++i; - if (i >= N) - state[0] = engine_type(1) << (width - 1); // with prob 2^-19937 - - // This sets the low R bits of _state[0] consistent with the rest of the - // state. Needed to handle SetCount(-N); Ran32(); immediately following - // reseeding. This wasn't required in the original code because a - // Transition was always done first. - engine_type q = state[N - 1] ^ state[M - 1], s = q >> (width - 1); - q = (q ^ (s ? magic : engine_type(0))) << 1 | s; - state[0] = (state[0] & upper) | (q & lower); - } - - template - void MT19937::CheckState(const engine_type state[], - Random_u32::type& check) { - engine_type x = 0; - Random_u32::type c = check; - for (unsigned i = 0; i < N; ++i) { - engine_t::CheckSum(state[i], c); - x |= state[i]; - } - if (x == 0) - throw RandomErr("MT19937: All-zero state"); - - // There are only width*(N-1) + 1 = 19937 independent bits of state. Thus - // the low width-1 bits of _state[0] are derivable from the other bits in - // state. Verify that the redundant bits bits are consistent. - engine_type q = state[N - 1] ^ state[M - 1], s = q >> (width - 1); - q = (q ^ (s ? magic : engine_type(0))) << 1 | s; - if ((q ^ state[0]) & lower) - throw RandomErr("MT19937: Invalid state"); - - check = c; - } - -#if defined(HAVE_SSE2) && HAVE_SSE2 - - // Transition is from Saito's Master's Thesis - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/M062821.pdf - // - // This implements - // - // w_{i+N} = w_i A xor w_M B xor w_{i+N-2} C xor w_{i+N-1} D - // - // where w_i is a 128-bit word and - // - // w A = (w << 8)_128 xor w - // w B = (w >> 11)_32 & MSK - // w C = (w >> 8)_128 - // w D = (w << 18)_32 - // - // Here the _128 means shift is of whole 128-bit word. _32 means the shifts - // are independently done on each 32-bit word. - // - // In SFMT19937_STEP32 and SFMT19937_STEP64 input is I, J = I + M and output - // is I = I + N (mod N). On input, s and r give state for I + N - 2 and I + - // N - 1; on output s and r give state for I + N - 1 and I + N. The - // implementation of 128-bit operations is open-coded in a portable fashion - // (with LSB ordering). - // - // N.B. Here N and M are the lags in units of BitWidth words and so are 4 - // (for u32 implementation) or 2 (for u64 implementation) times bigger than - // defined in Saito's thesis. - - // This is adapted from SFMT-sse.c in the SFMT 1.2 distribution. - // The order of instructions has been rearranged to increase the - // speed slightly - -#define SFMT19937_STEP128(I, J) { \ - internal_type x = _mm_load_si128(statev + I), \ - y = _mm_srli_epi32(statev[J], 11), \ - z = _mm_srli_si128(s, 1); \ - s = _mm_slli_epi32(r, 18); \ - z = _mm_xor_si128(z, x); \ - x = _mm_slli_si128(x, 1); \ - z = _mm_xor_si128(z, s); \ - y = _mm_and_si128(y, m); \ - z = _mm_xor_si128(z, x); \ - s = r; \ - r = _mm_xor_si128(z, y); \ - _mm_store_si128(statev + I, r); \ - } - - // This undoes SFMT19937_STEP. Trivially, we have - // - // w_i A = w_{i+N} xor w_{i+M} B xor w_{i+N-2} C xor w_{i+N-1} D - // - // Given w_i A we can determine w_i from the observation that A^16 = - // identity, thus - // - // w_i = (w_i A) A^15 - // - // Because x A^(2^n) = x << (8*2^n) xor x, the operation y = x A^15 can be - // implemented as - // - // y' = (x << 64)_128 xor x = x A^8 - // y'' = (y' << 32)_128 xor y' = y' A^4 = x A^12 - // y''' = (y'' << 16)_128 xor y'' = y'' A^2 = x A^14 - // y = (y''' << 8)_128 xor y''' = y''' A = x A^15 - // - // Here input is I = I + N, J = I + M, K = I + N - 2, L = I + N -1, and - // output is I = I. - // - // This is about 15-35% times slower than SFMT19937_STEPNN, because (1) there - // doesn't appear to be a straightforward way of saving intermediate results - // across calls as with SFMT19937_STEPNN and (2) w A^15 is slower to compute - // than w A. - -#define SFMT19937_REVSTEP128(I, J, K, L) { \ - internal_type x = _mm_load_si128(statev + I), \ - y = _mm_srli_epi32(statev[J], 11), \ - z = _mm_slli_epi32(statev[L], 18); \ - y = _mm_and_si128(y, m); \ - x = _mm_xor_si128(x, _mm_srli_si128(statev[K], 1)); \ - x = _mm_xor_si128(x, z); \ - x = _mm_xor_si128(x, y); \ - x = _mm_xor_si128(_mm_slli_si128(x, 8), x); \ - x = _mm_xor_si128(_mm_slli_si128(x, 4), x); \ - x = _mm_xor_si128(_mm_slli_si128(x, 2), x); \ - x = _mm_xor_si128(_mm_slli_si128(x, 1), x); \ - _mm_store_si128(statev + I, x); \ - } - - template - void SFMT19937::Transition(long long count, - internal_type statev[]) - throw() { - const internal_type m = _mm_set_epi32(magic3, magic2, magic1, magic0); - if (count > 0) { - internal_type s = _mm_load_si128(statev + N128 - 2), - r = _mm_load_si128(statev + N128 - 1); - for (; count; --count) { - unsigned i = 0; - for (; i + M128 < N128; ++i) SFMT19937_STEP128(i, i + M128 ); - for (; i < N128 ; ++i) SFMT19937_STEP128(i, i + M128 - N128); - } - } else if (count < 0) - for (; count; ++count) { - unsigned i = N128; - for (; i + M128 > N128;) { - --i; SFMT19937_REVSTEP128(i, i + M128 - N128, i - 2, i - 1); - } - for (; i > 2;) { - --i; SFMT19937_REVSTEP128(i, i + M128, i - 2, i - 1); - } - SFMT19937_REVSTEP128(1, M128 + 1, N128 - 1, 0 ); // i = 1 - SFMT19937_REVSTEP128(0, M128 , N128 - 2, N128 - 1); // i = 0 - } - } - -#undef SFMT19937_STEP128 -#undef SFMT19937_REVSTEP128 - -#elif defined(HAVE_ALTIVEC) && HAVE_ALTIVEC - - // The Altivec versions of SFMT19937_{,REV}STEP128 are simply translated from - // the SSE2 versions. The only significant differences arise because of the - // MSB ordering of the PowerPC. This means that the 32-bit and 64-bit - // versions are no different because 32-bit and 64-bit words don't pack - // together in the same way as on an SSE2 machine (see the two definitions of - // magic). This also means that the 128-bit byte shifts on an LSB machine - // change into more complicated byte permutations. - -#define ALTIVEC_PERM(X, P) vec_perm(X, P, P) - -#define SFMT19937_STEP128(I, J) { \ - internal_type x = statev[I], \ - z = vec_xor(vec_xor(ALTIVEC_PERM(s, right1), x), \ - vec_sl(r, bitleft)); \ - s = r; \ - r = vec_xor(z, \ - vec_xor(ALTIVEC_PERM(x, left1), \ - vec_and(vec_sr(statev[J], bitright), \ - magic))); \ - statev[I] = r; \ - } - -#define SFMT19937_REVSTEP128(I, J, K, L) { \ - internal_type x = statev[I], \ - y = vec_sr(statev[J], bitright), \ - z = vec_sl(statev[L], bitleft); \ - y = vec_and(y, magic); \ - x = vec_xor(x, ALTIVEC_PERM(statev[K], right1)); \ - x = vec_xor(x, z); \ - x = vec_xor(x, y); \ - x = vec_xor(ALTIVEC_PERM(x, left8), x); \ - x = vec_xor(ALTIVEC_PERM(x, left4), x); \ - x = vec_xor(ALTIVEC_PERM(x, left2), x); \ - statev[I] = vec_xor(ALTIVEC_PERM(x, left1), x); \ - } - - template - void SFMT19937::Transition(long long count, - internal_type statev[]) - throw() { - const internal_type magic = width == 32 ? - (vector unsigned)(magic0, magic1, magic2, magic3) : - (vector unsigned)(magic1, magic0, magic3, magic2), - bitleft = (vector unsigned)(18, 18, 18, 18), - bitright = (vector unsigned)(11, 11, 11, 11); - // Shift left and right by 1 byte. Note that vec_perm(X, Y, P) glues X and - // Y together into a 32-byte quantity and then the 16-byte permutation - // vector P specifies which bytes to put into the 16-byte output. We - // follow here the convention of using Y = P and using the zero entries in - // P to allow zero bytes to be introduces into the shifted output. The - // following describes how the left1 table (32-bit version) is produced: - // - // Byte layout of original with LSB ordering - // 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 - // shift left by 1 byte (z means zeros enter) - // 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00 zz - // - // Rearrange original to LSB order in 4-byte units - // 03 02 01 00 13 12 11 10 23 22 21 20 33 32 31 30 - // with sequential MSB byte indices - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // - // Rearrange shift left verion to LSB order in 4-byte units - // 02 01 00 zz 12 11 10 03 22 21 20 13 32 31 30 23 - // with corresponding MSB byte indices - // 1 2 3 z 5 6 7 0 9 10 11 4 13 14 15 8 - // - // Replace byte index at x by 16 + index of 0 = 16 + 7 = 23 to give - // 1 2 3 23 5 6 7 0 9 10 11 4 13 14 15 8 - const vector unsigned char left1 = width == 32 ? - (vector unsigned char)(1,2,3,23, 5,6,7,0, 9,10,11,4, 13,14,15,8) : - (vector unsigned char)(1,2,3,4,5,6,7,31, 9,10,11,12,13,14,15,0), - right1 = width == 32 ? - (vector unsigned char)(7,0,1,2, 11,4,5,6, 15,8,9,10, 17,12,13,14) : - (vector unsigned char)(15,0,1,2,3,4,5,6, 17,8,9,10,11,12,13,14); - if (count > 0) { - internal_type s = statev[N128 - 2], - r = statev[N128 - 1]; - for (; count; --count) { - unsigned i = 0; - for (; i + M128 < N128; ++i) SFMT19937_STEP128(i, i + M128 ); - for (; i < N128 ; ++i) SFMT19937_STEP128(i, i + M128 - N128); - } - } else if (count < 0) { - // leftN shifts left by N bytes. - const vector unsigned char left2 = width == 32 ? - (vector unsigned char)(2,3,22,22, 6,7,0,1, 10,11,4,5, 14,15,8,9) : - (vector unsigned char)(2,3,4,5,6,7,30,30, 10,11,12,13,14,15,0,1), - left4 = width == 32 ? - (vector unsigned char)(20,20,20,20, 0,1,2,3, 4,5,6,7, 8,9,10,11) : - (vector unsigned char)(4,5,6,7,28,28,28,28, 12,13,14,15,0,1,2,3), - left8 = (vector unsigned char)(24,24,24,24,24,24,24,24,0,1,2,3,4,5,6,7); - for (; count; ++count) { - unsigned i = N128; - for (; i + M128 > N128;) { - --i; SFMT19937_REVSTEP128(i, i + M128 - N128, i - 2, i - 1); - } - for (; i > 2;) { - --i; SFMT19937_REVSTEP128(i, i + M128, i - 2, i - 1); - } - SFMT19937_REVSTEP128(1, M128 + 1, N128 - 1, 0 ); // i = 1 - SFMT19937_REVSTEP128(0, M128 , N128 - 2, N128 - 1); // i = 0 - } - } - } - -#undef SFMT19937_STEP128 -#undef SFMT19937_REVSTEP128 -#undef ALTIVEC_PERM - -#else // neither HAVE_SSE2 or HAVE_ALTIVEC - -#define SFMT19937_STEP32(I, J) { \ - internal_type t = statev[I] ^ statev[I] << 8 ^ \ - (statev[J] >> 11 & magic0) ^ \ - (s0 >> 8 | s1 << 24) ^ r0 << 18; \ - s0 = r0; r0 = t & mask; \ - t = statev[I + 1] ^ \ - (statev[I + 1] << 8 | statev[I] >> 24) ^ \ - (statev[J + 1] >> 11 & magic1) ^ \ - (s1 >> 8 | s2 << 24) ^ r1 << 18; \ - s1 = r1; r1 = t & mask; \ - t = statev[I + 2] ^ \ - (statev[I + 2] << 8 | statev[I + 1] >> 24) ^ \ - (statev[J + 2] >> 11 & magic2) ^ \ - (s2 >> 8 | s3 << 24) ^ r2 << 18; \ - s2 = r2; r2 = t & mask; \ - t = statev[I + 3] ^ \ - (statev[I + 3] << 8 | statev[I + 2] >> 24) ^ \ - (statev[J + 3] >> 11 & magic3) ^ s3 >> 8 ^ r3 << 18; \ - s3 = r3; r3 = t & mask; \ - statev[I ] = r0; statev[I + 1] = r1; \ - statev[I + 2] = r2; statev[I + 3] = r3; \ - } - -#define SFMT19937_REVSTEP32(I, J, K, L) { \ - internal_type \ - t0 = (statev[I] ^ (statev[J] >> 11 & magic0) ^ \ - (statev[K] >> 8 | statev[K + 1] << 24) ^ \ - statev[L] << 18) & mask, \ - t1 = (statev[I + 1] ^ \ - (statev[J + 1] >> 11 & magic1) ^ \ - (statev[K + 1] >> 8 | statev[K + 2] << 24) ^ \ - statev[L + 1] << 18) & mask, \ - t2 = (statev[I + 2] ^ \ - (statev[J + 2] >> 11 & magic2) ^ \ - (statev[K + 2] >> 8 | statev[K + 3] << 24) ^ \ - statev[L + 2] << 18) & mask, \ - t3 = (statev[I + 3] ^ \ - (statev[J + 3] >> 11 & magic3) ^ \ - statev[K + 3] >> 8 ^ \ - statev[L + 3] << 18) & mask; \ - t3 ^= t1; t2 ^= t0; t3 ^= t2; t2 ^= t1; t1 ^= t0; \ - t3 ^= t2 >> 16 | (t3 << 16 & mask); \ - t2 ^= t1 >> 16 | (t2 << 16 & mask); \ - t1 ^= t0 >> 16 | (t1 << 16 & mask); \ - t0 ^= t0 << 16 & mask; \ - statev[I ] = t0 ^ (t0 << 8 & mask); \ - statev[I + 1] = t1 ^ (t0 >> 24 | (t1 << 8 & mask)); \ - statev[I + 2] = t2 ^ (t1 >> 24 | (t2 << 8 & mask)); \ - statev[I + 3] = t3 ^ (t2 >> 24 | (t3 << 8 & mask)); \ - } - - template<> - void SFMT19937::Transition(long long count, - internal_type statev[]) - throw() { - if (count > 0) { - // x[i+N] = g(x[i], x[i+M], x[i+N-2], x[i,N-1]) - internal_type - s0 = statev[N - 8], s1 = statev[N - 7], - s2 = statev[N - 6], s3 = statev[N - 5], - r0 = statev[N - 4], r1 = statev[N - 3], - r2 = statev[N - 2], r3 = statev[N - 1]; - for (; count; --count) { - unsigned i = 0; - for (; i + M < N; i += R) SFMT19937_STEP32(i, i + M ); - for (; i < N ; i += R) SFMT19937_STEP32(i, i + M - N); - } - } else if (count < 0) - for (; count; ++count) { - unsigned i = N; - for (; i + M > N;) { - i -= R; SFMT19937_REVSTEP32(i, i + M - N, i - 2 * R, i - R); - } - for (; i > 2 * R;) { - i -= R; SFMT19937_REVSTEP32(i, i + M , i - 2 * R, i - R); - } - SFMT19937_REVSTEP32(R, M + R, N - R, 0 ); // i = R - SFMT19937_REVSTEP32(0, M , N - 2 * R, N - R); // i = 0 - } - } - -#undef SFMT19937_STEP32 -#undef SFMT19937_REVSTEP32 - -#define SFMT19937_STEP64(I, J) { \ - internal_type t = statev[I] ^ statev[I] << 8 ^ \ - (statev[J] >> 11 & magic0) ^ \ - (s0 >> 8 | s1 << 56) ^ (r0 << 18 & mask18); \ - s0 = r0; r0 = t & mask; \ - t = statev[I + 1] ^ \ - (statev[I + 1] << 8 | statev[I] >> 56) ^ \ - (statev[J + 1] >> 11 & magic1) ^ \ - s1 >> 8 ^ (r1 << 18 & mask18); \ - s1 = r1; r1 = t & mask; \ - statev[I] = r0; statev[I + 1] = r1; \ - } - - // In combining the left and right shifts to simulate a 128-bit shift we - // usually use or. However we can equivalently use xor (e.g., t1 << 8 ^ t0 - // >> 56 instead of t1 ^ t1 << 8 | t0 >> 56) and this speeds up the code if - // used in some places. - -#define SFMT19937_REVSTEP64(I, J, K, L) { \ - internal_type \ - t0 = statev[I] ^ (statev[J] >> 11 & magic0) ^ \ - (statev[K] >> 8 | (statev[K + 1] << 56 & mask)) ^ \ - (statev[L] << 18 & mask18), \ - t1 = statev[I + 1] ^ (statev[J + 1] >> 11 & magic1) ^ \ - statev[K + 1] >> 8 ^ (statev[L + 1] << 18 & mask18); \ - t1 ^= t0; \ - t1 ^= t0 >> 32 ^ (t1 << 32 & mask); \ - t0 ^= t0 << 32 & mask; \ - t1 ^= t0 >> 48 ^ (t1 << 16 & mask); \ - t0 ^= t0 << 16 & mask; \ - statev[I ] = t0 ^ (t0 << 8 & mask); \ - statev[I + 1] = t1 ^ t0 >> 56 ^ (t1 << 8 & mask); \ - } - - template<> - void SFMT19937::Transition(long long count, - internal_type statev[]) - throw() { - // x[i+N] = g(x[i], x[i+M], x[i+N-2], x[i,N-1]) - if (count > 0) { - internal_type - s0 = statev[N - 4], s1 = statev[N - 3], - r0 = statev[N - 2], r1 = statev[N - 1]; - for (; count; --count) { - unsigned i = 0; - for (; i + M < N; i += R) SFMT19937_STEP64(i, i + M ); - for (; i < N ; i += R) SFMT19937_STEP64(i, i + M - N); - } - } else if (count < 0) - for (; count; ++count) { - unsigned i = N; - for (; i + M > N;) { - i -= R; SFMT19937_REVSTEP64(i, i + M - N, i - 2 * R, i - R); - } - for (; i > 2 * R;) { - i -= R; SFMT19937_REVSTEP64(i, i + M , i - 2 * R, i - R); - } - SFMT19937_REVSTEP64(R, M + R, N - R, 0 ); // i = R - SFMT19937_REVSTEP64(0, M , N - 2 * R, N - R); // i = 0 - } - } - -#undef SFMT19937_STEP64 -#undef SFMT19937_REVSTEP64 - -#endif // HAVE_SSE2 and HAVE_ALTIVEC - - template<> - void SFMT19937::NormalizeState(engine_type state[]) throw() { - // Carry out the Period Certification for SFMT19937 - engine_type inner = (state[0] & PARITY0) ^ (state[1] & PARITY1) ^ - (state[2] & PARITY2) ^ (state[3] & PARITY3); - for (unsigned s = 16; s; s >>= 1) - inner ^= inner >> s; - STATIC_ASSERT(PARITY_LSB < 32 && PARITY0 & 1u << PARITY_LSB, - "inconsistent PARITY_LSB or PARITY0"); - // Now inner & 1 is the parity of the number of 1 bits in w_0 & p. - if ((inner & 1u) == 0) - // Change bit of w_0 corresponding to LSB of PARITY - state[PARITY_LSB >> 5] ^= engine_type(1u) << (PARITY_LSB & 31u); - } - - template<> - void SFMT19937::NormalizeState(engine_type state[]) throw() { - // Carry out the Period Certification for SFMT19937 - engine_type inner = (state[0] & PARITY0) ^ (state[1] & PARITY1); - for (unsigned s = 32; s; s >>= 1) - inner ^= inner >> s; - STATIC_ASSERT(PARITY_LSB < 64 && PARITY0 & 1u << PARITY_LSB, - "inconsistent PARITY_LSB or PARITY0"); - // Now inner & 1 is the parity of the number of 1 bits in w_0 & p. - if ((inner & 1u) == 0) - // Change bit of w_0 corresponding to LSB of PARITY - state[PARITY_LSB >> 6] ^= engine_type(1u) << (PARITY_LSB & 63u); - } - - template - void SFMT19937::CheckState(const engine_type state[], - Random_u32::type& check) { - engine_type x = 0; - Random_u32::type c = check; - for (unsigned i = 0; i < N; ++i) { - engine_t::CheckSum(state[i], c); - x |= state[i]; - } - if (x == 0) - throw RandomErr("SFMT19937: All-zero state"); - check = c; - } - - // RandomPower2 implementation - -#if RANDOMLIB_POWERTABLE - // Powers of two. Just use floats here. As long as there's no overflow - // or underflow these are exact. In particular they can be cast to - // doubles or long doubles with no error. - const float RandomPower2::power2[maxpow - minpow + 1] = { -#if RANDOMLIB_LONGDOUBLEPREC > 64 - // It would be nice to be able to use the C99 notation of 0x1.0p-120 - // for 2^-120 here. - 1/1329227995784915872903807060280344576.f, // 2^-120 - 1/664613997892457936451903530140172288.f, // 2^-119 - 1/332306998946228968225951765070086144.f, // 2^-118 - 1/166153499473114484112975882535043072.f, // 2^-117 - 1/83076749736557242056487941267521536.f, // 2^-116 - 1/41538374868278621028243970633760768.f, // 2^-115 - 1/20769187434139310514121985316880384.f, // 2^-114 - 1/10384593717069655257060992658440192.f, // 2^-113 - 1/5192296858534827628530496329220096.f, // 2^-112 - 1/2596148429267413814265248164610048.f, // 2^-111 - 1/1298074214633706907132624082305024.f, // 2^-110 - 1/649037107316853453566312041152512.f, // 2^-109 - 1/324518553658426726783156020576256.f, // 2^-108 - 1/162259276829213363391578010288128.f, // 2^-107 - 1/81129638414606681695789005144064.f, // 2^-106 - 1/40564819207303340847894502572032.f, // 2^-105 - 1/20282409603651670423947251286016.f, // 2^-104 - 1/10141204801825835211973625643008.f, // 2^-103 - 1/5070602400912917605986812821504.f, // 2^-102 - 1/2535301200456458802993406410752.f, // 2^-101 - 1/1267650600228229401496703205376.f, // 2^-100 - 1/633825300114114700748351602688.f, // 2^-99 - 1/316912650057057350374175801344.f, // 2^-98 - 1/158456325028528675187087900672.f, // 2^-97 - 1/79228162514264337593543950336.f, // 2^-96 - 1/39614081257132168796771975168.f, // 2^-95 - 1/19807040628566084398385987584.f, // 2^-94 - 1/9903520314283042199192993792.f, // 2^-93 - 1/4951760157141521099596496896.f, // 2^-92 - 1/2475880078570760549798248448.f, // 2^-91 - 1/1237940039285380274899124224.f, // 2^-90 - 1/618970019642690137449562112.f, // 2^-89 - 1/309485009821345068724781056.f, // 2^-88 - 1/154742504910672534362390528.f, // 2^-87 - 1/77371252455336267181195264.f, // 2^-86 - 1/38685626227668133590597632.f, // 2^-85 - 1/19342813113834066795298816.f, // 2^-84 - 1/9671406556917033397649408.f, // 2^-83 - 1/4835703278458516698824704.f, // 2^-82 - 1/2417851639229258349412352.f, // 2^-81 - 1/1208925819614629174706176.f, // 2^-80 - 1/604462909807314587353088.f, // 2^-79 - 1/302231454903657293676544.f, // 2^-78 - 1/151115727451828646838272.f, // 2^-77 - 1/75557863725914323419136.f, // 2^-76 - 1/37778931862957161709568.f, // 2^-75 - 1/18889465931478580854784.f, // 2^-74 - 1/9444732965739290427392.f, // 2^-73 - 1/4722366482869645213696.f, // 2^-72 - 1/2361183241434822606848.f, // 2^-71 - 1/1180591620717411303424.f, // 2^-70 - 1/590295810358705651712.f, // 2^-69 - 1/295147905179352825856.f, // 2^-68 - 1/147573952589676412928.f, // 2^-67 - 1/73786976294838206464.f, // 2^-66 - 1/36893488147419103232.f, // 2^-65 -#endif - 1/18446744073709551616.f, // 2^-64 - 1/9223372036854775808.f, // 2^-63 - 1/4611686018427387904.f, // 2^-62 - 1/2305843009213693952.f, // 2^-61 - 1/1152921504606846976.f, // 2^-60 - 1/576460752303423488.f, // 2^-59 - 1/288230376151711744.f, // 2^-58 - 1/144115188075855872.f, // 2^-57 - 1/72057594037927936.f, // 2^-56 - 1/36028797018963968.f, // 2^-55 - 1/18014398509481984.f, // 2^-54 - 1/9007199254740992.f, // 2^-53 - 1/4503599627370496.f, // 2^-52 - 1/2251799813685248.f, // 2^-51 - 1/1125899906842624.f, // 2^-50 - 1/562949953421312.f, // 2^-49 - 1/281474976710656.f, // 2^-48 - 1/140737488355328.f, // 2^-47 - 1/70368744177664.f, // 2^-46 - 1/35184372088832.f, // 2^-45 - 1/17592186044416.f, // 2^-44 - 1/8796093022208.f, // 2^-43 - 1/4398046511104.f, // 2^-42 - 1/2199023255552.f, // 2^-41 - 1/1099511627776.f, // 2^-40 - 1/549755813888.f, // 2^-39 - 1/274877906944.f, // 2^-38 - 1/137438953472.f, // 2^-37 - 1/68719476736.f, // 2^-36 - 1/34359738368.f, // 2^-35 - 1/17179869184.f, // 2^-34 - 1/8589934592.f, // 2^-33 - 1/4294967296.f, // 2^-32 - 1/2147483648.f, // 2^-31 - 1/1073741824.f, // 2^-30 - 1/536870912.f, // 2^-29 - 1/268435456.f, // 2^-28 - 1/134217728.f, // 2^-27 - 1/67108864.f, // 2^-26 - 1/33554432.f, // 2^-25 - 1/16777216.f, // 2^-24 - 1/8388608.f, // 2^-23 - 1/4194304.f, // 2^-22 - 1/2097152.f, // 2^-21 - 1/1048576.f, // 2^-20 - 1/524288.f, // 2^-19 - 1/262144.f, // 2^-18 - 1/131072.f, // 2^-17 - 1/65536.f, // 2^-16 - 1/32768.f, // 2^-15 - 1/16384.f, // 2^-14 - 1/8192.f, // 2^-13 - 1/4096.f, // 2^-12 - 1/2048.f, // 2^-11 - 1/1024.f, // 2^-10 - 1/512.f, // 2^-9 - 1/256.f, // 2^-8 - 1/128.f, // 2^-7 - 1/64.f, // 2^-6 - 1/32.f, // 2^-5 - 1/16.f, // 2^-4 - 1/8.f, // 2^-3 - 1/4.f, // 2^-2 - 1/2.f, // 2^-1 - 1.f, // 2^0 - 2.f, // 2^1 - 4.f, // 2^2 - 8.f, // 2^3 - 16.f, // 2^4 - 32.f, // 2^5 - 64.f, // 2^6 - 128.f, // 2^7 - 256.f, // 2^8 - 512.f, // 2^9 - 1024.f, // 2^10 - 2048.f, // 2^11 - 4096.f, // 2^12 - 8192.f, // 2^13 - 16384.f, // 2^14 - 32768.f, // 2^15 - 65536.f, // 2^16 - 131072.f, // 2^17 - 262144.f, // 2^18 - 524288.f, // 2^19 - 1048576.f, // 2^20 - 2097152.f, // 2^21 - 4194304.f, // 2^22 - 8388608.f, // 2^23 - 16777216.f, // 2^24 - 33554432.f, // 2^25 - 67108864.f, // 2^26 - 134217728.f, // 2^27 - 268435456.f, // 2^28 - 536870912.f, // 2^29 - 1073741824.f, // 2^30 - 2147483648.f, // 2^31 - 4294967296.f, // 2^32 - 8589934592.f, // 2^33 - 17179869184.f, // 2^34 - 34359738368.f, // 2^35 - 68719476736.f, // 2^36 - 137438953472.f, // 2^37 - 274877906944.f, // 2^38 - 549755813888.f, // 2^39 - 1099511627776.f, // 2^40 - 2199023255552.f, // 2^41 - 4398046511104.f, // 2^42 - 8796093022208.f, // 2^43 - 17592186044416.f, // 2^44 - 35184372088832.f, // 2^45 - 70368744177664.f, // 2^46 - 140737488355328.f, // 2^47 - 281474976710656.f, // 2^48 - 562949953421312.f, // 2^49 - 1125899906842624.f, // 2^50 - 2251799813685248.f, // 2^51 - 4503599627370496.f, // 2^52 - 9007199254740992.f, // 2^53 - 18014398509481984.f, // 2^54 - 36028797018963968.f, // 2^55 - 72057594037927936.f, // 2^56 - 144115188075855872.f, // 2^57 - 288230376151711744.f, // 2^58 - 576460752303423488.f, // 2^59 - 1152921504606846976.f, // 2^60 - 2305843009213693952.f, // 2^61 - 4611686018427387904.f, // 2^62 - 9223372036854775808.f, // 2^63 - 18446744073709551616.f, // 2^64 - }; -#endif - - // RandomEngine (and implicitly RandomAlgorithm and RandomMixer) - // instantiations. The first 4 (using MixerMT[01]) are not recommended. - template class RandomEngine< MT19937, MixerMT0 >; - template class RandomEngine< MT19937, MixerMT0 >; - template class RandomEngine< MT19937, MixerMT1 >; - template class RandomEngine< MT19937, MixerMT1 >; - - template class RandomEngine< MT19937, MixerSFMT>; - template class RandomEngine< MT19937, MixerSFMT>; - template class RandomEngine, MixerSFMT>; - template class RandomEngine, MixerSFMT>; - - // RandomCanonial instantiations - - template<> RandomCanonical - RandomCanonical::Global = RandomCanonical(); - template<> RandomCanonical - RandomCanonical::Global = RandomCanonical(); - template<> RandomCanonical - RandomCanonical::Global = RandomCanonical(); - template<> RandomCanonical - RandomCanonical::Global = RandomCanonical(); - -} // namespace RandomLib diff --git a/include/RandomLib/Config.h b/include/RandomLib/Config.h deleted file mode 100644 index 94d35c2f..00000000 --- a/include/RandomLib/Config.h +++ /dev/null @@ -1,13 +0,0 @@ -#define RANDOMLIB_VERSION_STRING "Unconfigured" -#define RANDOMLIB_VERSION_MAJOR -1 -#define RANDOMLIB_VERSION_MINOR -1 -#define RANDOMLIB_VERSION_PATCH -1 - -// Define HAVE_SSE2 to be 1 if Intel/AMD CPU with SSE2 support -/* #undef HAVE_SSE2 */ - -// Define HAVE_ALTIVEC to be 1 if Power PC CPU with AltiVec support -/* #undef HAVE_ALTIVEC */ - -// Undefine HAVE_LONG_DOUBLE if this type is unknown to the compiler -#define HAVE_LONG_DOUBLE 1 diff --git a/include/RandomLib/DiscreteNormal.hpp b/include/RandomLib/DiscreteNormal.hpp deleted file mode 100644 index 6775bae4..00000000 --- a/include/RandomLib/DiscreteNormal.hpp +++ /dev/null @@ -1,432 +0,0 @@ -/** - * \file DiscreteNormal.hpp - * \brief Header for DiscreteNormal - * - * Sample exactly from the discrete normal distribution. - * - * Copyright (c) Charles Karney (2013) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_DISCRETENORMAL_HPP) -#define RANDOMLIB_DISCRETENORMAL_HPP 1 - -#include -#include - -namespace RandomLib { - /** - * \brief The discrete normal distribution. - * - * Sample integers \e i with probability proportional to - * \f[ - * \exp\biggl[-\frac12\biggl(\frac{i-\mu}{\sigma}\biggr)^2\biggr], - * \f] - * where σ and μ are given as rationals (the ratio of two integers). - * The sampling is exact (provided that the random generator is ideal). For - * example - * \code - #include - #include - #include - - int main() { - RandomLib::Random r; // Create r - r.Reseed(); // and give it a unique seed - int sigma_num = 7, sigma_den = 1, mu_num = 1, mu_den = 3; - RandomLib::DiscreteNormal d(sigma_num, sigma_den, - mu_num, mu_den); - for (int i = 0; i < 100; ++i) - std::cout << d(r) << "\n"; - } - \endcode - * prints out 100 samples with σ = 7 and μ = 1/3. - * - * The algorithm is much the same as for ExactNormal; for details see - * - C. F. F. Karney, Sampling exactly from the normal distribution, - * http://arxiv.org/abs/1303.6257 (Mar. 2013). - * . - * That algorithm samples the integer part of the result \e k, samples \e x - * in [0,1], and (unless rejected) returns s(\e k + \e x), where \e s - * = ±1. For the discrete case, we sample \e x in [0,1) such that - * \f[ - * s(k + x) = (i - \mu)/\sigma, - * \f] - * or - * \f[ - * x = s(i - \mu)/\sigma - k - * \f] - * The value of \e i which results in the smallest \e x ≥ 0 is - * \f[ - * i_0 = s\lceil k \sigma + s \mu\rceil - * \f] - * so sample - * \f[ - * i = i_0 + sj - * \f] - * where \e j is uniformly distributed in [0, ⌈σ⌉). The - * corresponding value of \e x is - * \f[ - * \begin{aligned} - * x &= \bigl(si_0 - (k\sigma + s\mu)\bigr)/\sigma + j/\sigma\\ - * &= x_0 + j/\sigma,\\ - * x_0 &= \bigl(\lceil k \sigma + s \mu\rceil - - * (k \sigma + s \mu)\bigr)/\sigma. - * \end{aligned} - * \f] - * After \e x is sampled in this way, it should be rejected if \e x ≥ 1 - * (this is counted with the next larger value of \e k) or if \e x = 0, \e k - * = 0, and \e s = −1 (to avoid double counting the origin). If \e x - * is accepted (in Step 4 of the ExactNormal algorithm), then return \e i. - * - * When σ and μ are given as rationals, all the arithmetic outlined - * above can be carried out exactly. The basic rejection techniques used by - * ExactNormal are exact. Thus the result of this discrete form of the - * algorithm is also exact. - * - * RandomLib provides two classes to sample from this distribution: - * - DiscreteNormal which is tuned for speed on a typical general purpose - * computer. This assumes that random samples can be generated relatively - * quickly. - * - DiscreteNormalAlt, which is a prototype for what might be needed on a - * small device used for cryptography which is using a hardware generator - * for obtaining truly random bits. This assumption here is that the - * random bits are relatively expensive to obtain. - * . - - * The basic algorithm is the same in the two cases. The main advantages of - * this method are: - * - exact sampling (provided that the source of random numbers is ideal), - * - no need to cut off the tails of the distribution, - * - a short program involving simple integer operations only, - * - no dependence on external libraries (except to generate random bits), - * - no large tables of constants needed, - * - minimal time to set up for a new σ and μ (roughly comparable to - * the time it takes to generate one sample), - * - only about 5–20 times slower than standard routines to sample from - * a normal distribution using plain double-precision arithmetic. - * - DiscreteNormalAlt exhibits ideal scaling for the consumption of random - * bits, namely a constant + log2σ, for large σ, - * where the constant is about 31. - * . - * The possible drawbacks of this method are: - * - σ and μ are restricted to rational numbers with sufficiently - * small numerators and denominators to avoid overflow (this is unlikely to - * be a severe restriction especially if the template parameter IntType is - * set to long long), - * - the running time is unbounded (but not in any practical sense), - * - the memory consumption is unbounded (but not in any practical sense), - * - the toll, about 30 bits, is considerably worse than that obtained using - * the Knuth-Yao algorithm, for which the toll is no more than 2 (but this - * requires a large table which is expensive to compute and requires a lot - * of memory to store). - * - * This class uses a mutable private vector. So a single DiscreteNormal - * object cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific DiscreteNormal - * object. - * - * Some timing results for IntType = int, μ = 0, and 108 - * samples (time = time per sample, including setup time, rv = mean number of - * random variables per sample) - * - σ = 10, time = 219 ns, rv = 17.52 - * - σ = 32, time = 223 ns, rv = 17.82 - * - σ = 1000, time = 225 ns, rv = 17.95 - * - σ = 160000, time = 226 ns, rv = 17.95 - * - * @tparam IntType the integer type to use (default int). - **********************************************************************/ - template class DiscreteNormal { - public: - /** - * Constructor. - * - * @param[in] sigma_num the numerator of σ. - * @param[in] sigma_den the denominator of σ (default 1). - * @param[in] mu_num the numerator of μ (default 0). - * @param[in] mu_den the denominator of μ (default 1). - * - * The constructor creates a DiscreteNormal objects for sampling with - * specific values of σ and μ. This may throw an exception if the - * parameters are such that overflow is possible. Internally σ and - * μ are expressed with a common denominator, so it may be possible to - * avoid overflow by picking the fractions of these quantities so that \e - * sigma_den and \e mu_den have many common factors. - **********************************************************************/ - DiscreteNormal(IntType sigma_num, IntType sigma_den = 1, - IntType mu_num = 0, IntType mu_den = 1); - /** - * Return a sample. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return discrete normal integer. - **********************************************************************/ - template - IntType operator()(Random& r) const; - private: - /** - * sigma = _sig / _d, mu = _imu + _mu / _d, _isig = floor(sigma) - **********************************************************************/ - IntType _sig, _mu, _d, _isig, _imu; - typedef unsigned short word; - /** - * Holds as much of intermediate uniform deviates as needed. - **********************************************************************/ - mutable std::vector _v; - mutable unsigned _m, _l; - /** - * Increment on size of _v. - **********************************************************************/ - static const unsigned alloc_incr = 16; - - // ceil(n/d) for d > 0 - static IntType iceil(IntType n, IntType d); - // abs(n) needed because Visual Studio's std::abs has problems - static IntType iabs(IntType n); - static IntType gcd(IntType u, IntType v); - - // After x = LeadingDigit(p), p/_sig = (x + p'/_sig)/b where p and p' are - // in [0, _sig) and b = 1 + max(word). - word LeadingDigit(IntType& p) const; - - /** - * Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2); - * return: - * - 1 (succeed unconditionally) with prob (\e m − 2) / \e m, - * - 0 (succeed with probability x) with prob 1 / \e m, - * - −1 (fail unconditionally) with prob 1 / \e m. - **********************************************************************/ - template static int Choose(Random& r, int m); - - // Compute v' < v. If true set v = v'. - template bool less_than(Random& r) const; - - // Compute v < (x + p/_sig)/base (updating v) - template bool less_than(Random& r, word x, IntType p) const; - - // true with prob (x + p/_sig)/base - template bool bernoulli(Random& r, word x, IntType p) const; - - /** - * Return true with probability exp(−1/2). - **********************************************************************/ - template bool ExpProbH(Random& r) const; - - /** - * Return true with probability exp(−n/2). - **********************************************************************/ - template bool ExpProb(Random& r, int n) const; - - /** - * Return \e n with probability exp(−n/2) - * (1−exp(−1/2)). - **********************************************************************/ - template int ExpProbN(Random& r) const; - - /** - * Algorithm B: true with prob exp(-x * (2*k + x) / (2*k + 2)) where - * x = (x0 + xn / _sig)/b. - **********************************************************************/ - template - bool B(Random& r, int k, word x0, IntType xn) const; - }; - - template DiscreteNormal::DiscreteNormal - (IntType sigma_num, IntType sigma_den, - IntType mu_num, IntType mu_den) - : _v(std::vector(alloc_incr)), _m(0), _l(alloc_incr) { - STATIC_ASSERT(std::numeric_limits::is_integer, - "DiscreteNormal: invalid integer type IntType"); - STATIC_ASSERT(std::numeric_limits::is_signed, - "DiscreteNormal: IntType must be a signed type"); - STATIC_ASSERT(!std::numeric_limits::is_signed, - "DiscreteNormal: word must be an unsigned type"); - STATIC_ASSERT(std::numeric_limits::digits + 1 >= - std::numeric_limits::digits, - "DiscreteNormal: IntType must be at least as wide as word"); - if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 )) - throw RandomErr("DiscreteNormal: need sigma > 0"); - _imu = mu_num / mu_den; - if (_imu == (std::numeric_limits::min)()) - throw RandomErr("DiscreteNormal: abs(mu) too large"); - mu_num -= _imu * mu_den; - IntType l; - l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l; - l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l; - _isig = iceil(sigma_num, sigma_den); - l = gcd(sigma_den, mu_den); - _sig = sigma_num * (mu_den / l); - _mu = mu_num * (sigma_den / l); - _d = sigma_den * (mu_den / l); - // The rest of the constructor tests for possible overflow - // Check for overflow in computing member variables - IntType maxint = (std::numeric_limits::max)(); - if (!( mu_den / l <= maxint / sigma_num && - mu_num <= maxint / (sigma_den / l) && - mu_den / l <= maxint / sigma_den )) - throw RandomErr("DiscreteNormal: sigma or mu overflow"); - // The probability that k = kmax is about 10^-543. - int kmax = 50; - // Check that max plausible result fits in an IntType, i.e., - // _isig * (kmax + 1) + abs(_imu) does not lead to overflow. - if (!( kmax + 1 <= maxint / _isig && - _isig * (kmax + 1) <= maxint - iabs(_imu) )) - throw RandomErr("DiscreteNormal: possible overflow a"); - // Check xn0 = _sig * k + s * _mu; - if (!( kmax <= maxint / _sig && - _sig * kmax <= maxint - iabs(_mu) )) - throw RandomErr("DiscreteNormal: possible overflow b"); - // Check for overflow in LeadingDigit - // p << bits, p = _sig - 1, bits = 8 - if (!( _sig <= (maxint >> 8) )) - throw RandomErr("DiscreteNormal: overflow in LeadingDigit"); - } - - template template - IntType DiscreteNormal::operator()(Random& r) const { - for (;;) { - int k = ExpProbN(r); - if (!ExpProb(r, k * (k - 1))) continue; - IntType - s = r.Boolean() ? -1 : 1, - xn = _sig * IntType(k) + s * _mu, - i = iceil(xn, _d) + r.template Integer(_isig); - xn = i * _d - xn; - if (xn >= _sig || (k == 0 && s < 0 && xn <= 0)) continue; - if (xn > 0) { - word x0 = LeadingDigit(xn); // Find first digit in expansion in words - int h = k + 1; while (h-- && B(r, k, x0, xn)); - if (!(h < 0)) continue; - } - return s * i + _imu; - } - } - - template - IntType DiscreteNormal::iceil(IntType n, IntType d) - { IntType k = n / d; return k + (k * d < n ? 1 : 0); } - - template IntType DiscreteNormal::iabs(IntType n) - { return n < 0 ? -n : n; } - - template - IntType DiscreteNormal::gcd(IntType u, IntType v) { - // Knuth, TAOCP, vol 2, 4.5.2, Algorithm A - u = iabs(u); v = iabs(v); - while (v > 0) { IntType r = u % v; u = v; v = r; } - return u; - } - - template typename DiscreteNormal::word - DiscreteNormal::LeadingDigit(IntType& p) const { - static const unsigned bits = 8; - static const unsigned num = std::numeric_limits::digits / bits; - STATIC_ASSERT(bits * num == std::numeric_limits::digits, - "Number of digits in word must be multiple of 8"); - word s = 0; - for (unsigned c = num; c--;) { - p <<= bits; s <<= bits; - word d = word(p / _sig); - s += d; - p -= IntType(d) * _sig; - } - return s; - } - - template template - int DiscreteNormal::Choose(Random& r, int m) { - int k = r.template Integer(m); - return k == 0 ? 0 : (k == 1 ? -1 : 1); - } - - template template - bool DiscreteNormal::less_than(Random& r) const { - for (unsigned j = 0; ; ++j) { - if (j == _m) { - // Need more bits in the old V - if (_l == _m) _v.resize(_l += alloc_incr); - _v[_m++] = r.template Integer(); - } - word w = r.template Integer(); - if (w > _v[j]) - return false; // New V is bigger, so exit - else if (w < _v[j]) { - _v[j] = w; // New V is smaller, update _v - _m = j + 1; // adjusting its size - return true; // and generate the next V - } - // Else w == _v[j] and we need to check the next word - } - } - - template template - bool DiscreteNormal::less_than(Random& r, word x, IntType p) const { - if (_m == 0) _v[_m++] = r.template Integer(); - if (_v[0] != x) return _v[0] < x; - for (unsigned j = 1; ; ++j) { - if (p == 0) return false; - if (j == _m) { - if (_l == _m) _v.resize(_l += alloc_incr); - _v[_m++] = r.template Integer(); - } - x = LeadingDigit(p); - if (_v[j] != x) return _v[j] < x; - } - } - - template template - bool DiscreteNormal::bernoulli(Random& r, word x, IntType p) const { - word w = r.template Integer(); - if (w != x) return w < x; - for (;;) { - if (p == 0) return false; - x = LeadingDigit(p); - w = r.template Integer(); - if (w != x) return w < x; - } - } - - template template - bool DiscreteNormal::ExpProbH(Random& r) const { - static const word half = word(1) << (std::numeric_limits::digits - 1); - _m = 0; - if ((_v[_m++] = r.template Integer()) & half) return true; - // Here _v < 1/2. Now loop finding decreasing V. Exit when first - // increasing one is found. - for (unsigned s = 0; ; s ^= 1) { // Parity of loop count - if (!less_than(r)) return s != 0u; - } - } - - template template - bool DiscreteNormal::ExpProb(Random& r, int n) const { - while (n-- > 0) { if (!ExpProbH(r)) return false; } - return true; - } - - template template - int DiscreteNormal::ExpProbN(Random& r) const { - int n = 0; - while (ExpProbH(r)) ++n; - return n; - } - - template template - bool DiscreteNormal::B(Random& r, int k, word x0, IntType xn) - const { - int n = 0, h = 2 * k + 2, f; - _m = 0; - for (;; ++n) { - if ( ((f = k ? 0 : Choose(r, h)) < 0) || - !(n ? less_than(r) : less_than(r, x0, xn)) || - ((f = k ? Choose(r, h) : f) < 0) || - (f == 0 && !bernoulli(r, x0, xn)) ) break; - } - return (n % 2) == 0; - } - -} // namespace RandomLib - -#endif // RANDOMLIB_DISCRETENORMAL_HPP diff --git a/include/RandomLib/DiscreteNormalAlt.hpp b/include/RandomLib/DiscreteNormalAlt.hpp deleted file mode 100644 index b92e4974..00000000 --- a/include/RandomLib/DiscreteNormalAlt.hpp +++ /dev/null @@ -1,328 +0,0 @@ -/** - * \file DiscreteNormalAlt.hpp - * \brief Header for DiscreteNormalAlt - * - * Sample exactly from the discrete normal distribution (alternate version). - * - * Copyright (c) Charles Karney (2013) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_DISCRETENORMALALT_HPP) -#define RANDOMLIB_DISCRETENORMALALT_HPP 1 - -#include -#include -#include - -namespace RandomLib { - /** - * \brief The discrete normal distribution (alternate version). - * - * Sample integers \e i with probability proportional to - * \f[ - * \exp\biggl[-\frac12\biggl(\frac{i-\mu}{\sigma}\biggr)^2\biggr], - * \f] - * where σ and μ are given as rationals (the ratio of two integers). - * The sampling is exact (provided that the random generator is ideal). The - * results of this class are UniformInteger objects which represent a - * contiguous range which is a power of 2\e bits. This can be - * narrowed down to a specific integer as follows - * \code - #include - #include - #include - #include - - int main() { - RandomLib::Random r; // Create r - r.Reseed(); // and give it a unique seed - int sigma_num = 7, sigma_den = 1, mu_num = 1, mu_den = 3; - RandomLib::DiscreteNormalAlt d(sigma_num, sigma_den, - mu_num, mu_den); - for (int i = 0; i < 100; ++i) { - RandomLib::UniformInteger u = d(r); - std::cout << u << " = "; - std::cout << u(r) << "\n"; - } - } - \endcode - * prints out 100 samples with σ = 7 and μ = 1/3; the samples are - * first given as a range and then u(r) is used to obtain a - * specific integer. In some applications, it might be possible to avoid - * sampling all the additional digits to get to a specific integer. (An - * example would be drawing a sample which satisfies an inequality.) This - * version is slower (by a factor of about 4 for \e bits = 1) than - * DiscreteNormal on a conventional computer, but may be faster when random - * bits are generated by a slow hardware device. - * - * The basic algorithm is the same as for DiscreteNormal. However randomness - * in metered out \e bits random bits at a time. The algorithm uses the - * least random bits (and is slowest!) when \e bits = 1. This rationing of - * random bits also applies to sampling \e j in the expression - * \f[ - * x = x_0 + j/\sigma. - * \f] - * Rather than sampling a definite value for \e j, which then might be - * rejected, \e j is sampled using UniformInteger. UniformInteger uses - * Lumbroso's method from sampling an integer uniformly in [0, \e m) using at - * most 2 + log2\e m bits on average (for \e bits = 1). However - * when a UniformInteger object is first constructed it samples at most 3 - * bits (on average) to obtain a range for \e j which is power of 2. This - * allows the algorithm to achieve ideal scaling in the limit of large - * σ consuming constant + log2σ bits on average. In - * addition it can deliver the resuls in the form of a UniformInteger - * consuming a constant number of bits on average (and then about - * log2σ additional bits are required to convert the - * UniformInteger into an integer sample). The consumption of random bits - * (for \e bits = 1) is summarized here \verbatim - min mean max - bits for UniformInteger result 30.4 34.3 35.7 - bits for integer result - log2(sigma) 28.8 31.2 32.5 - toll 26.8 29.1 30.4 \endverbatim - * These results are averaged over many samples. The "min" results apply - * when σ is a power of 2; the "max" results apply when σ is - * slightly more than a power of two; the "mean" results are averaged over - * σ. The toll is the excess number of bits over the entropy of the - * distribution, which is log2(2π\e e)/2 + - * log2σ (for σ large). - * - * The data for the first two lines in the table above are taken for the blue - * and red lines in the figure below where the abscissa is the fractional - * part of log2σ - * \image html - * discrete-bits.png "Random bits to sample from discrete normal distribution" - * - * This class uses a mutable RandomNumber objects. So a single - * DiscreteNormalAlt object cannot safely be used by multiple threads. In a - * multi-processing environment, each thread should use a thread-specific - * DiscreteNormalAlt object. - * - * @tparam IntType the integer type to use (default int). - **********************************************************************/ - template class DiscreteNormalAlt { - public: - /** - * Constructor. - * - * @param[in] sigma_num the numerator of σ. - * @param[in] sigma_den the denominator of σ (default 1). - * @param[in] mu_num the numerator of μ (default 0). - * @param[in] mu_den the denominator of μ (default 1). - * - * This may throw an exception is the parameters are such that overflow is - * possible. - **********************************************************************/ - DiscreteNormalAlt(IntType sigma_num, IntType sigma_den = 1, - IntType mu_num = 0, IntType mu_den = 1); - /** - * Return a sample. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return discrete normal sample in the form of a UniformInteger object. - **********************************************************************/ - template - UniformInteger operator()(Random& r) const; - private: - /** - * sigma = _sig / _d, mu = _imu + _mu / _d, _isig = ceil(sigma) - **********************************************************************/ - IntType _sig, _mu, _d, _isig, _imu; - - mutable RandomNumber _p; - mutable RandomNumber _q; - - // ceil(n/d) for d > 0 - static IntType iceil(IntType n, IntType d); - // abs(n) needed because Visual Studio's std::abs has problems - static IntType iabs(IntType n); - static IntType gcd(IntType u, IntType v); - - /** - * Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2); - * return: - * - 1 (succeed unconditionally) with prob (\e m − 2) / \e m, - * - 0 (succeed with probability x) with prob 1 / \e m, - * - −1 (fail unconditionally) with prob 1 / \e m. - **********************************************************************/ - template static int Choose(Random& r, int m); - - /** - * Return true with probability exp(−1/2). - **********************************************************************/ - template bool ExpProbH(Random& r) const; - - /** - * Return true with probability exp(−n/2). - **********************************************************************/ - template bool ExpProb(Random& r, int n) const; - - /** - * Return \e n with probability exp(−n/2) - * (1−exp(−1/2)). - **********************************************************************/ - template int ExpProbN(Random& r) const; - - /** - * Algorithm B: true with prob exp(-x * (2*k + x) / (2*k + 2)) where - * x = (xn0 + _d * j) / _sig - **********************************************************************/ - template - bool B(Random& r, int k, IntType xn0, UniformInteger& j) - const; - }; - - template - DiscreteNormalAlt::DiscreteNormalAlt - (IntType sigma_num, IntType sigma_den, IntType mu_num, IntType mu_den) { - STATIC_ASSERT(std::numeric_limits::is_integer, - "DiscreteNormalAlt: invalid integer type IntType"); - STATIC_ASSERT(std::numeric_limits::is_signed, - "DiscreteNormalAlt: IntType must be a signed type"); - if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 )) - throw RandomErr("DiscreteNormalAlt: need sigma > 0"); - _imu = mu_num / mu_den; - if (_imu == (std::numeric_limits::min)()) - throw RandomErr("DiscreteNormalAlt: abs(mu) too large"); - mu_num -= _imu * mu_den; - IntType l; - l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l; - l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l; - _isig = iceil(sigma_num, sigma_den); - l = gcd(sigma_den, mu_den); - _sig = sigma_num * (mu_den / l); - _mu = mu_num * (sigma_den / l); - _d = sigma_den * (mu_den / l); - // The rest of the constructor tests for possible overflow - // Check for overflow in computing member variables - IntType maxint = (std::numeric_limits::max)(); - if (!( mu_den / l <= maxint / sigma_num && - iabs(mu_num) <= maxint / (sigma_den / l) && - mu_den / l <= maxint / sigma_den )) - throw RandomErr("DiscreteNormalAlt: sigma or mu overflow"); - if (!UniformInteger::Check(_isig, _d)) - throw RandomErr("DiscreteNormalAlt: overflow in UniformInteger"); - // The probability that k = kmax is about 10^-543. - int kmax = 50; - // Check that max plausible result fits in an IntType, i.e., - // _isig * (kmax + 1) + abs(_imu) does not lead to overflow. - if (!( kmax + 1 <= maxint / _isig && - _isig * (kmax + 1) <= maxint - iabs(_imu) )) - throw RandomErr("DiscreteNormalAlt: possible overflow a"); - // Check xn0 = _sig * k + s * _mu; - if (!( kmax <= maxint / _sig && - _sig * kmax <= maxint - iabs(_mu) )) - throw RandomErr("DiscreteNormalAlt: possible overflow b"); - // Check for overflow in RandomNumber::LessThan(..., UniformInteger& j) - // p0 * b, p0 = arg2 = xn0 = _d - 1 - // c *= b, c = arg3 = _d - // digit(D, k) * q, digit(D, k) = b - 1, q = arg4 = _sig - if (!( _d <= maxint >> bits )) - throw std::runtime_error("DiscreteNormalAlt: overflow in RandomNumber a"); - if (!( (IntType(1) << bits) - 1 <= maxint / _sig )) - throw std::runtime_error("DiscreteNormalAlt: overflow in RandomNumber b"); - } - - template template - UniformInteger - DiscreteNormalAlt::operator()(Random& r) const { - for (;;) { - int k = ExpProbN(r); - if (!ExpProb(r, k * (k - 1))) continue; - UniformInteger j(r, _isig); - IntType - s = r.Boolean() ? -1 : 1, - xn0 = _sig * IntType(k) + s * _mu, - i0 = iceil(xn0, _d); // i = i0 + j - xn0 = i0 * _d - xn0; // xn = xn0 + _d * j - if (!j.LessThan(r, _sig - xn0, _d) || - (k == 0 && s < 0 && !j.GreaterThan(r, -xn0, _d))) continue; - int h = k + 1; while (h-- && B(r, k, xn0, j)); - if (!(h < 0)) continue; - j.Add(i0 + s * _imu); - if (s < 0) j.Negate(); - return j; - } - } - - template - IntType DiscreteNormalAlt::iceil(IntType n, IntType d) - { IntType k = n / d; return k + (k * d < n ? 1 : 0); } - - template - IntType DiscreteNormalAlt::iabs(IntType n) - { return n < 0 ? -n : n; } - - template - IntType DiscreteNormalAlt::gcd(IntType u, IntType v) { - // Knuth, TAOCP, vol 2, 4.5.2, Algorithm A - u = iabs(u); v = iabs(v); - while (v > 0) { IntType r = u % v; u = v; v = r; } - return u; - } - - template template - int DiscreteNormalAlt::Choose(Random& r, int m) { - // Limit base to 2^15 to avoid integer overflow - const int b = bits > 15 ? 15 : bits; - const unsigned mask = (1u << b) - 1; - int n1 = m - 2, n2 = m - 1; - // Evaluate u < n/m where u is a random real number in [0,1). Write u = - // (d + u') / 2^b where d is a random integer in [0,2^b) and u' is in - // [0,1). Then u < n/m becomes u' < n'/m where n' = 2^b * n - d * m and - // exit if n' <= 0 (false) or n' >= m (true). - for (;;) { - int d = (mask & RandomNumber::RandomDigit(r)) * m; - n1 = (std::max)((n1 << b) - d, 0); - if (n1 >= m) return 1; - n2 = (std::min)((n2 << b) - d, m); - if (n2 <= 0) return -1; - if (n1 == 0 && n2 == m) return 0; - } - } - - template template - bool DiscreteNormalAlt::ExpProbH(Random& r) const { - _p.Init(); - if (_p.Digit(r, 0) >> (bits - 1)) return true; - for (;;) { - _q.Init(); if (!_q.LessThan(r, _p)) return false; - _p.Init(); if (!_p.LessThan(r, _q)) return true; - } - } - - template template - bool DiscreteNormalAlt::ExpProb(Random& r, int n) const { - while (n-- > 0) { if (!ExpProbH(r)) return false; } - return true; - } - - template template - int DiscreteNormalAlt::ExpProbN(Random& r) const { - int n = 0; - while (ExpProbH(r)) ++n; - return n; - } - - template template bool - DiscreteNormalAlt::B(Random& r, int k, IntType xn0, - UniformInteger& j) - const { - int n = 0, m = 2 * k + 2, f; - for (;; ++n) { - if ( ((f = k ? 0 : Choose(r, m)) < 0) || - (_q.Init(), - !(n ? _q.LessThan(r, _p) : _q.LessThan(r, xn0, _d, _sig, j))) || - ((f = k ? Choose(r, m) : f) < 0) || - (f == 0 && (_p.Init(), !_p.LessThan(r, xn0, _d, _sig, j))) ) - break; - _p.swap(_q); // an efficient way of doing p = q - } - return (n % 2) == 0; - } - -} // namespace RandomLib - -#endif // RANDOMLIB_DISCRETENORMALALT_HPP diff --git a/include/RandomLib/ExactExponential.hpp b/include/RandomLib/ExactExponential.hpp deleted file mode 100644 index 2620f9c5..00000000 --- a/include/RandomLib/ExactExponential.hpp +++ /dev/null @@ -1,241 +0,0 @@ -/** - * \file ExactExponential.hpp - * \brief Header for ExactExponential - * - * Sample exactly from an exponential distribution. - * - * Copyright (c) Charles Karney (2006-2012) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_EXACTEXPONENTIAL_HPP) -#define RANDOMLIB_EXACTEXPONENTIAL_HPP 1 - -#include - -#if defined(_MSC_VER) -// Squelch warnings about constant conditional expressions -# pragma warning (push) -# pragma warning (disable: 4127) -#endif - -namespace RandomLib { - /** - * \brief Sample exactly from an exponential distribution. - * - * Sample \e x ≥ 0 from exp(−\e x). See: - * - J. von Neumann, Various Techniques used in Connection with Random - * Digits, J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38 - * (1951), reprinted in Collected Works, Vol. 5, 768--770 (Pergammon, - * 1963). - * - M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions - * (National Bureau of Standards, 1964), Sec. 26.8.6.c(2). - * - G. E. Forsythe, Von Neumann's Comparison Method for Random Sampling from - * Normal and Other Distributions, Math. Comp. 26, 817--826 (1972). - * - D. E. Knuth, TAOCP, Vol 2, Sec 3.4.1.C.3. - * - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number - * Generation, in "Algorithms and Complexity" (Academic Press, 1976), - * pp. 357--428. - * - P. Flajolet and N. Saheb, The Complexity of Generating an - * Exponentially Distributed Variate, J. Algorithms 7, 463--488 (1986). - * - * The following code illustrates the basic method given by von Neumann: - * \code - // Return a random number x >= 0 distributed with probability exp(-x). - double ExpDist(RandomLib::Random& r) { - for (unsigned k = 0; ; ++k) { - double x = r.Fixed(), // executed 1/(1-exp(-1)) times on average - p = x, q; - do { - q = r.Fixed(); // executed exp(x)*cosh(x) times on average - if (!(q < p)) return k + x; - p = r.Fixed(); // executed exp(x)*sinh(x) times on average - } while (p < q); - } - } - \endcode - * This returns a result consuming exp(1)/(1 − exp(-1)) = 4.30 random - * numbers on average. (Von Neumann incorrectly states that the method takes - * (1 + exp(1))/(1 − exp(-1)) = 5.88 random numbers on average.) - * Because of the finite precision of Random::Fixed(), the code snippet above - * only approximates exp(−\e x). Instead, it returns \e x with - * probability \e h(1 − \e h)x/h for \e x = \e - * ih, \e h = 2−53, and integer \e i ≥ 0. - * - * The above is precisely von Neumann's method. Abramowitz and Stegun - * consider a variant: sample uniform variants until the first is less than - * the sum of the rest. Forsythe converts the < ranking for the runs to ≤ - * which makes the analysis of the discrete case more difficult. He also - * drops the "trick" by which the integer part of the deviate is given by the - * number of rejections when finding the fractional part. - * - * Von Neumann says of his method: "The machine has in effect computed a - * logarithm by performing only discriminations on the relative magnitude of - * numbers in (0,1). It is a sad fact of life, however, that under the - * particular conditions of the Eniac it was slightly quicker to use a - * truncated power series for log(1−\e T) than to carry out all the - * discriminations." - * - * Here the code is modified to make it more efficient: - * \code - // Return a random number x >= 0 distributed with probability exp(-x). - double ExpDist(RandomLib::Random& r) { - for (unsigned k = 0; ; ++k) { - double x = r.Fixed(); // executed 1/(1-exp(-1/2)) times on average - if (x >= 0.5) continue; - double p = x, q; - do { - q = r.Fixed(); // executed exp(x)*cosh(x) times on average - if (!(q < p)) return 0.5 * k + x; - p = r.Fixed(); // executed exp(x)*sinh(x) times on average - } while (p < q); - } - } - \endcode - * In addition, the method is extended to use infinite precision uniform - * deviates implemented by RandomNumber and returning \e exact results for - * the exponential distribution. This is possible because only comparisons - * are done in the method. The template parameter \e bits specifies the - * number of bits in the base used for RandomNumber (i.e., base = - * 2bits). - * - * For example the following samples from an exponential distribution and - * prints various representations of the result. - * \code - #include - #include - - RandomLib::Random r; - const int bits = 1; - RandomLib::ExactExponential edist; - for (size_t i = 0; i < 10; ++i) { - RandomLib::RandomNumber x = edist(r); // Sample - std::pair z = x.Range(); - std::cout << x << " = " // Print in binary with ellipsis - << "(" << z.first << "," << z.second << ")"; // Print range - double v = x.Value(r); // Round exactly to nearest double - std::cout << " = " << v << "\n"; - } - \endcode - * Here's a possible result: \verbatim - 0.0111... = (0.4375,0.5) = 0.474126 - 10.000... = (2,2.125) = 2.05196 - 1.00... = (1,1.25) = 1.05766 - 0.010... = (0.25,0.375) = 0.318289 - 10.1... = (2.5,3) = 2.8732 - 0.0... = (0,0.5) = 0.30753 - 0.101... = (0.625,0.75) = 0.697654 - 0.00... = (0,0.25) = 0.0969214 - 0.0... = (0,0.5) = 0.194053 - 0.11... = (0.75,1) = 0.867946 \endverbatim - * First number is in binary with ... indicating an infinite sequence of - * random bits. Second number gives the corresponding interval. Third - * number is the result of filling in the missing bits and rounding exactly - * to the nearest representable double. - * - * This class uses some mutable RandomNumber objects. So a single - * ExactExponential object cannot safely be used by multiple threads. In a - * multi-processing environment, each thread should use a thread-specific - * ExactExponential object. In addition, these should be invoked with - * thread-specific random generator objects. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class ExactExponential { - public: - /** - * Return a random deviate with an exponential distribution, exp(−\e - * x) for \e x ≥ 0. Requires 7.232 bits per invocation for \e bits = 1. - * The average number of bits in the fraction = 1.743. The relative - * frequency of the results for the fractional part with \e bits = 1 is - * shown by the histogram - * \image html exphist.png - * The base of each rectangle gives the range represented by the - * corresponding binary number and the area is proportional to its - * frequency. A PDF version of this figure is given - * here. This allows the figure to be magnified - * to show the rectangles for all binary numbers up to 9 bits. Note that - * this histogram was generated using an earlier version of - * ExactExponential (thru version 1.3) that implements von Neumann's - * original method. The histogram generated with the current version of - * ExactExponential is the same as this figure for \e u in [0, 1/2]. The - * histogram for \e u in [1/2, 1] is obtained by shifting and scaling the - * part for \e u in [0, 1/2] to fit under the exponential curve. - * - * Another way of assessing the efficiency of the algorithm is thru the - * mean value of the balance = (number of random bits consumed) − - * (number of bits in the result). If we code the result in mixed Knuth - * and Yao's unary-binary notation (integer is given in unary, followed by - * "0" as a separator, followed by the fraction in binary), then the mean - * balance is 3.906. (Flajolet and Saheb analyzed the algorithm based on - * the original von Neumann method and showed that the balance is 5.680 in - * that case.) - * - * For \e bits large, the mean number of random digits is exp(1/2)/(1 - * − exp(−1/2)) = 4.19 (versus 4.30 digits for the original - * method). - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return the random sample. - **********************************************************************/ - template RandomNumber operator()(Random& r) const; - private: - /** - * Return true with probability exp(−\e p) for \e p in (0,1/2). - **********************************************************************/ - template bool - ExpFraction(Random& r, RandomNumber& p) const; - mutable RandomNumber _x; - mutable RandomNumber _v; - mutable RandomNumber _w; - }; - - template template RandomNumber - ExactExponential::operator()(Random& r) const { - // A simple rejection method gives the 1/2 fractional part. The number of - // rejections gives the multiples of 1/2. - // - // bits: used fract un-bin balance double - // original stats: 9.31615 2.05429 3.63628 5.67987 61.59456 - // new stats: 7.23226 1.74305 3.32500 3.90725 59.82198 - // - // The difference between un-bin and fract is exp(1)/(exp(1)-1) = 1.58198 - _x.Init(); - int k = 0; - while (!ExpFraction(r, _x)) { // Executed 1/(1 - exp(-1/2)) on average - ++k; - _x.Init(); - } - if (k & 1) _x.RawDigit(0) += 1U << (bits - 1); - _x.AddInteger(k >> 1); - return _x; - } - - template template bool - ExactExponential::ExpFraction(Random& r, RandomNumber& p) - const { - // The early bale out - if (p.Digit(r, 0) >> (bits - 1)) return false; - // Implement the von Neumann algorithm - _w.Init(); - if (!_w.LessThan(r, p)) // if (w < p) - return true; - while (true) { // Unroll loop to avoid copying RandomNumber - _v.Init(); // v = r.Fixed(); - if (!_v.LessThan(r, _w)) // if (v < w) - return false; - _w.Init(); // w = r.Fixed(); - if (!_w.LessThan(r, _v)) // if (w < v) - return true; - } - } - -} // namespace RandomLib - -#if defined(_MSC_VER) -# pragma warning (pop) -#endif - -#endif // RANDOMLIB_EXACTEXPONENTIAL_HPP diff --git a/include/RandomLib/ExactNormal.hpp b/include/RandomLib/ExactNormal.hpp deleted file mode 100644 index cd8dfc73..00000000 --- a/include/RandomLib/ExactNormal.hpp +++ /dev/null @@ -1,417 +0,0 @@ -/** - * \file ExactNormal.hpp - * \brief Header for ExactNormal - * - * Sample exactly from a normal distribution. - * - * Copyright (c) Charles Karney (2011-2012) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_EXACTNORMAL_HPP) -#define RANDOMLIB_EXACTNORMAL_HPP 1 - -#include -#include // for max/min - -#if defined(_MSC_VER) -// Squelch warnings about constant conditional expressions -# pragma warning (push) -# pragma warning (disable: 4127) -#endif - -namespace RandomLib { - /** - * \brief Sample exactly from a normal distribution. - * - * Sample \e x from exp(−x2/2) / sqrt(2π). For - * background, see: - * - J. von Neumann, Various Techniques used in Connection with Random - * Digits, J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38 - * (1951), reprinted in Collected Works, Vol. 5, 768--770 (Pergammon, - * 1963). - * - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number - * Generation, in "Algorithms and Complexity" (Academic Press, 1976), - * pp. 357--428. - * - P. Flajolet and N. Saheb, The Complexity of Generating an Exponentially - * Distributed Variate, J. Algorithms 7, 463--488 (1986). - * - * The algorithm is given in - * - C. F. F. Karney, Sampling exactly from the normal distribution, - * http://arxiv.org/abs/1303.6257 (Mar. 2013). - * . - * In brief, the algorithm is: - * -# Select an integer \e k ≥ 0 with probability - * exp(−k/2) (1−exp(−1/2)). - * -# Accept with probability - * exp(− \e k (\e k − 1) / 2); otherwise, reject and start - * over at step 1. - * -# Sample a random number \e x uniformly from [0,1). - * -# Accept with probability exp(− \e x (\e x + 2\e k) / 2); - * otherwise, reject and start over at step 1. - * -# Set \e x = \e k + \e x. - * -# With probability 1/2, negate \e x. - * -# Return \e x. - * . - * It is easy to show that this algorithm returns samples from the normal - * distribution with zero mean and unit variance. Futhermore, all these - * steps can be carried out exactly as follows: - * - Step 1: - * - \e k = 0; - * - while (ExpProb(−1/2)) increment \e k by 1. - * - Step 2: - * - \e n = \e k (\e k − 1) / 2; - * - while (\e n > 0) - * { if (!ExpProb(−1/2)) go to step 1; decrement \e n by 1; } - * - Step 4: - * - repeat \e k + 1 times: - * if (!ExpProb(− \e x (\e x + 2\e k) / (2\e k + 2))) go to step 1. - * . - * Here, ExpProb(−\e p) returns true with probability exp(−\e p). - * With \e p = 1/2 (steps 1 and 2), this is implemented with von Neumann's - * rejection technique: - * - Generate a sequence of random numbers Ui and - * find the greatest \e n such that 1/2 > U1 > - * U2 > . . . > Un. (The - * resulting value of \e n may be 0.) - * - If \e n is even, accept and return true; otherwise (\e n odd), reject - * and return false. - * . - * For \e p = \e x (\e x + 2\e k) / (2\e k + 2) (step 4), we generalize von - * Neumann's procedure as follows: - * - Generate two sequences of random numbers Ui - * and Vi and find the greatest \e n such that - * both the following conditions hold - * - \e x > U1 > U2 > . . . > - * Un; - * - Vi < (\e x + 2 \e k) / (2 \e k + 2) for - * all \e i in [1, \e n]. - * . - * (The resulting value of \e n may be 0.) - * - If \e n is even, accept (return true); otherwise (\e n odd), reject - * (return false). - * . - * Here, instead of testing Vi < (\e x + 2 \e k) - * / (2 \e k + 2), we carry out the following tests: - * - return true, with probability 2 \e k / (2 \e k + 2); - * - return false, with probability 1 / (2 \e k + 2); - * - otherwise (also with probability 1 / (2 \e k + 2)), - * return \e x > Vi. - * . - * The resulting method now entails evaluation of simple fractional - * probabilities (e.g., 1 / (2 \e k + 2)), or comparing random numbers (e.g., - * U1 > U2). These may be carried out - * exactly with a finite mean running time. - * - * With \e bits = 1, this consumes 30.1 digits on average and the result has - * 1.19 digits in the fraction. It takes about 676 ns to generate a result - * (1460 ns, including the time to round it to a double). With bits = 32, it - * takes 437 ns to generate a result (621 ns, including the time to round it - * to a double). In contrast, NormalDistribution takes about 44 ns to - * generate a double result. - * - * Another way of assessing the efficiency of the algorithm is thru the mean - * value of the balance = (number of random bits consumed) − (number of - * bits in the result). If we code the result in Knuth & Yao's unary-binary - * notation, then the mean balance is 26.6. - * - * For example the following samples from a normal exponential distribution - * and prints various representations of the result. - * \code - #include - #include - - RandomLib::Random r; - const int bits = 1; - RandomLib::ExactNormal ndist; - for (size_t i = 0; i < 10; ++i) { - RandomLib::RandomNumber x = ndist(r); // Sample - std::pair z = x.Range(); - std::cout << x << " = " // Print in binary with ellipsis - << "(" << z.first << "," << z.second << ")"; // Print range - double v = x.Value(r); // Round exactly to nearest double - std::cout << " = " << v << "\n"; - } - \endcode - * Here's a possible result: \verbatim - -1.00... = (-1.25,-1) = -1.02142 - -0.... = (-1,0) = -0.319708 - 0.... = (0,1) = 0.618735 - -0.0... = (-0.5,0) = -0.396591 - 0.0... = (0,0.5) = 0.20362 - 0.0... = (0,0.5) = 0.375662 - -1.111... = (-2,-1.875) = -1.88295 - -1.10... = (-1.75,-1.5) = -1.68088 - -0.... = (-1,0) = -0.577547 - -0.... = (-1,0) = -0.890553 - \endverbatim - * First number is in binary with ... indicating an infinite sequence of - * random bits. Second number gives the corresponding interval. Third - * number is the result of filling in the missing bits and rounding exactly - * to the nearest representable double. - * - * This class uses some mutable RandomNumber objects. So a single - * ExactNormal object cannot safely be used by multiple threads. In a - * multi-processing environment, each thread should use a thread-specific - * ExactNormal object. In addition, these should be invoked with - * thread-specific random generator objects. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class ExactNormal { - public: - /** - * Return a random deviate with a normal distribution of mean 0 and - * variance 1. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return the random sample. - **********************************************************************/ - template RandomNumber operator()(Random& r) const; - private: - /** - * Return true with probability exp(−1/2). For \e bits = 1, this - * consumes, on average, \e t = 2.846 random digits. We have \e t = \e a - * (1−exp(−1/2)) + \e b exp(−1/2), where \e a is the mean - * bit count for false result = 3.786 and \e b is the mean bit count for - * true result = 2.236. - **********************************************************************/ - template bool ExpProbH(Random& r) const; - - /** - * Return true with probability exp(−n/2). For \e bits = 1, - * this consumes, on average, \e t - * (1−exp(−n/2))/(1−exp(−1/2)) random - * digits. A true result uses \e n \e b random digits. A false result - * uses \e a + \e b [exp(−1/2)/(1−exp(−1/2)) − - * n exp(−n/2)/(1−exp(−n/2))] random - * digits. - **********************************************************************/ - template bool ExpProb(Random& r, unsigned n) const; - - /** - * Return \e n with probability exp(−n/2) - * (1−exp(−1/2)). For \e bits = 1, this consumes \e n \e a + - * \e b random digits if the result is \e n. Averaging over \e n this - * becomes (\e b − (\e b − \e a) exp(−1/2))/(1 − - * exp(−1/2)) digits. - **********************************************************************/ - template unsigned ExpProbN(Random& r) const; - - /** - * Return true with probability 1/2. This is similar to r.Boolean() but - * forces all the random results to come thru RandomNumber::RandomDigit. - **********************************************************************/ - template static bool Boolean(Random& r) { - // A more general implementation which deals with the case where the base - // might be negative is: - // - // const unsigned base = 1u << bits; - // unsigned b; - // do - // b = RandomNumber::RandomDigit(r); - // while (b == (base / 2) * 2); - // return b & 1u; - return RandomNumber::RandomDigit(r) & 1u; - } - - /** - * Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2); - * return: - * - 1 (succeed unconditionally) with prob (2\e k) / (2\e k + 2), - * - 0 (succeed with probability x) with prob 1 / (2\e k + 2), - * - −1 (fail unconditionally) with prob 1 / (2\e k + 2). - * . - * This simulates \code - double x = r.Fixed(); // Uniform in [0,1) - x *= (2 * k + 2); - return x < 2 * k ? 1 : (x < 2 * k + 1 ? 0 : -1); - \endcode - **********************************************************************/ - template static int Choose(Random& r, int k) { - // Limit base to 2^15 to avoid integer overflow - const int b = bits > 15 ? 15 : bits; - const unsigned mask = (1u << b) - 1; - const int m = 2 * k + 2; - int n1 = m - 2, n2 = m - 1; - // Evaluate u < n/m where u is a random real number in [0,1). Write u = - // (d + u') / 2^b where d is a random integer in [0,2^b) and u' is in - // [0,1). Then u < n/m becomes u' < n'/m where n' = 2^b * n - d * m and - // exit if n' <= 0 (false) or n' >= m (true). - while (true) { - int d = (mask & RandomNumber::RandomDigit(r)) * m; - n1 = (std::max)((n1 << b) - d, 0); - if (n1 >= m) return 1; - n2 = (std::min)((n2 << b) - d, m); - if (n2 <= 0) return -1; - if (n1 == 0 && n2 == m) return 0; - } - } - - mutable RandomNumber _x; - mutable RandomNumber _p; - mutable RandomNumber _q; - }; - - template template - bool ExactNormal::ExpProbH(Random& r) const { - // Bit counts - // ExpProbH: 2.846 = 3.786 * (1-exp(-1/2)) + 2.236 * exp(-1/2) - // t = a * (1-exp(-1/2)) + b * exp(-1/2) - // t = mean bit count for result = 2.846 - // a = mean bit count for false result = 3.786 - // b = mean bit count for true result = 2.236 - // - // for bits large - // t = exp(1/2) = 1.6487 - // a = exp(1/2)/(2*(1-exp(-1/2))) = 2.0951 - // b = exp(1/2)/(2*exp(-1/2)) = 1.3591 - // - // Results for Prob(exp(-1)), omitting first test - // total = 5.889, false = 5.347, true = 6.826 - // - // Results for Prob(exp(-1)) using ExpProbH(r) && ExpProbH(r), - // total = 4.572 = (1 - exp(-1)) * a + (1 + exp(-1/2)) * exp(-1/2) * b - // false = 4.630 = a + b * exp(-1/2)/(1 + exp(-1/2)), - // true = 4.472 = 2 * b - _p.Init(); - if (_p.Digit(r, 0) >> (bits - 1)) return true; - while (true) { - _q.Init(); if (!_q.LessThan(r, _p)) return false; - _p.Init(); if (!_p.LessThan(r, _q)) return true; - } - } - - template template - bool ExactNormal::ExpProb(Random& r, unsigned n) const { - // Bit counts - // ExpProb(n): t * (1-exp(-n/2))/(1-exp(-1/2)) - // ExpProb(n) = true: n * b - // ExpProb(n) = false: a + - // b * (exp(-1/2)/(1-exp(-1/2)) - n*exp(-n/2)/(1-exp(-n/2))) - while (n--) { if (!ExpProbH(r)) return false; } - return true; - } - - template template - unsigned ExactNormal::ExpProbN(Random& r) const { - // Bit counts - // ExpProbN() = n: n * a + b - unsigned n = 0; - while (ExpProbH(r)) ++n; - return n; - } - - template template RandomNumber - ExactNormal::operator()(Random& r) const { - // With bits = 1, - // - mean number of bits used = 30.10434 - // - mean number of bits in fraction = 1.18700 - // - mean number of bits in result = 3.55257 (unary-binary) - // - mean balance = 30.10434 - 3.55257 = 26.55177 - // - mean number of bits to generate a double = 83.33398 - // . - // Note - // - unary-binary notation (Knuth + Yao, 1976): write x = n + y, with n = - // integer and y in [0,1). If n >=0, then write (n+1) 1's followed by a - // 0; otherwise (n < 0), write (-n) 0's followed by a 1. Write y as a - // binary fraction. - // - (bits in result) - (bits in fraction) = 2 (for encoding overhead for - // the integer part) + 0.36557, where 0.36557 = (bits used for integer - // part) = sum(k*int(sqrt(2/pi)*exp(-x^2/2), x=k..k+1), k=0..inf) - // - (bits for double) approx (bits used) - (bits in fraction) + 1 (for - // guard bit) + 53.41664 where 53.41664 = (bits in fraction of double) = - // sum((52-l)*int(sqrt(2/pi)*exp(-x^2/2), x=2^l,2^(l+1)), l=-inf..inf) - // This is approximate because it doesn't account for the minimum - // exponent, denormalized numbers, and rounding changing the exponent. - // - while (true) { - // Executed sqrt(2/pi)/(1-exp(-1/2)) = 2.027818889827955 times on - // average. - unsigned k = ExpProbN(r); // the integer part of the result. - if (ExpProb(r, (k - 1) * k)) { - // Probability that this test succeeds is - // (1 - exp(-1/2)) * sum(exp(-k/2) * exp(-(k-1)*k/2), k=0..inf)) - // = (1 - exp(-1/2)) * G = 0.689875359564630 - // where G = sum(exp(-k^2/2, k=0..inf) = 1.75331414402145 - // For k == 0, sample from exp(-x^2/2) for x in [0,1]. This succeeds - // with probability int(exp(-x^2/2),x=0..1). - // - // For general k, substitute x' = x + k in exp(-x'^2/2), and obtain - // exp(-k^2/2) * exp(-x*(x+2*k)/2). So sample from exp(-x*(x+2*k)/2). - // This succeeds with probability int(exp(-x*(x+2*k)/2),x=0..1) = - // int(exp(-x^2/2),x=k..k+1)*exp(k^2/2) = - // - // 0.8556243918921 for k = 0 - // 0.5616593588061 for k = 1 - // 0.3963669350376 for k = 2 - // 0.2974440159655 for k = 3 - // 0.2345104783458 for k = 4 - // 0.1921445042826 for k = 5 - // - // Returns a result with prob sqrt(pi/2) / G = 0.714825772431666; - // otherwise another trip through the outer loop is taken. - _x.Init(); - unsigned s = 1; - for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times - bool first; - for (s = 1, first = true; ; s ^= 1, first = false) { - // A simpler algorithm is indicated by ALT, results in - // - mean number of bits used = 29.99968 - // - mean number of bits in fraction = 1.55580 - // - mean number of bits in result = 3.92137 (unary-binary) - // - mean balance = 29.99968 - 3.92137 = 26.07831 - // - mean number of bits to generate a double = 82.86049 - // . - // This has a smaller balance (by 0.47 bits). However the number - // of bits in the fraction is larger by 0.37 - if (first) { // ALT: if (false) { - // This implements the success prob (x + 2*k) / (2*k + 2). - int y = Choose(r, k); - if (y < 0) break; // the y test fails - _q.Init(); - if (y > 0) { // the y test succeeds just test q < x - if (!_q.LessThan(r, _x)) break; - } else { // the y test is ambiguous - // Test max(q, p) < x. List _q before _p since it ends up with - // slightly more digits generated (and these will be used - // subsequently). (_p's digits are immediately thrown away.) - _p.Init(); if (!_x.GreaterPair(r, _q, _p)) break; - } - } else { - // Split off the failure test for k == 0, i.e., factor the prob - // x/2 test into the product: 1/2 (here) times x (in assignment - // of y). - if (k == 0 && Boolean(r)) break; - // ALT: _q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break; - _q.Init(); if (!_q.LessThan(r, _p)) break; - // succeed with prob k == 0 ? x : (x + 2*k) / (2*k + 2) - int y = k == 0 ? 0 : Choose(r, k); - if (y < 0) - break; - else if (y == 0) { - _p.Init(); if (!_p.LessThan(r, _x)) break; - } - } - _p.swap(_q); // a fast way of doing p = q - } - if (s == 0) break; - } - if (s != 0) { - _x.AddInteger(k); - if (Boolean(r)) _x.Negate(); // half of the numbers are negative - return _x; - } - } - } - } - -} // namespace RandomLib - -#if defined(_MSC_VER) -# pragma warning (pop) -#endif - -#endif // RANDOMLIB_EXACTNORMAL_HPP diff --git a/include/RandomLib/ExactPower.hpp b/include/RandomLib/ExactPower.hpp deleted file mode 100644 index dbbb3009..00000000 --- a/include/RandomLib/ExactPower.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/** - * \file ExactPower.hpp - * \brief Header for ExactPower - * - * Sample exactly from a power distribution. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_EXACTPOWER_HPP) -#define RANDOMLIB_EXACTPOWER_HPP 1 - -#include - -namespace RandomLib { - /** - * \brief Sample exactly from a power distribution. - * - * Sample exactly from power distribution (n + 1) - * xn for \e x in (0,1) and integer \e n ≥ 0 using - * infinite precision. The template parameter \e bits specifies the number - * of bits in the base used for RandomNumber (i.e., base = - * 2bits). - * - * This class uses some mutable RandomNumber objects. So a single ExactPower - * object cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific ExactPower object. - * In addition, these should be invoked with thread-specific random generator - * objects. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class ExactPower { - public: - /** - * Return the random deviate with a power distribution, (n + 1) - * xn for \e x in (0,1) and integer \e n ≥ 0. - * Returned result is a RandomNumber with base 2bits. - * For \e bits = 1, the number of random bits in the result and consumed - * are as follows: \verbatim - n random bits - result consumed - 0 0 0 - 1 2 4 - 2 2.33 6.67 - 3 2.67 9.24 - 4 2.96 11.71 - 5 3.20 14.11 - 6 3.41 16.45 - 7 3.59 18.75 - 8 3.75 21.01 - 9 3.89 23.25 - 10 4.02 25.47 - \endverbatim - * The relative frequency of the results with \e bits = 1 and \e n = 2 can - * be is shown by the histogram - * \image html powerhist.png - * The base of each rectangle gives the range represented by the - * corresponding binary number and the area is proportional to its - * frequency. A PDF version of this figure - * here. This allows the figure to be - * magnified to show the rectangles for all binary numbers up to 9 bits. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] n the power. - * @return the random sample. - **********************************************************************/ - template - RandomNumber operator()(Random& r, unsigned n) const; - private: - mutable RandomNumber _x; - mutable RandomNumber _y; - }; - - template template RandomNumber - ExactPower::operator()(Random& r, unsigned n) const { - // Return max(u_0, u_1, u_2, ..., u_n). Equivalent to taking the - // (n+1)th root of u_0. - _x.Init(); - for (; n--;) { - _y.Init(); - // For bits = 1, we can save 1 bit on the first iteration by using a - // technique suggested by Knuth and Yao (1976). When comparing the - // digits of x and y, use 1 bit to determine if the digits are the same. - // If they are, then use another bit for the value of the digit. If they - // are not, then the next bit of the maximum must be 1 (avoiding using a - // second bit). Applying this optimization to subsequent iterations - // (when x already is filled with some bits) gets trickier. - if (_x.LessThan(r, _y)) - _x.swap(_y); // x = y; - } - return _x; - } - -} // namespace RandomLib - -#endif // RANDOMLIB_EXACTPOWER_HPP diff --git a/include/RandomLib/ExponentialDistribution.hpp b/include/RandomLib/ExponentialDistribution.hpp deleted file mode 100644 index 3ebb0ca8..00000000 --- a/include/RandomLib/ExponentialDistribution.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/** - * \file ExponentialDistribution.hpp - * \brief Header for ExponentialDistribution - * - * Sample from an exponential distribution. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP) -#define RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP 1 - -#include - -namespace RandomLib { - /** - * \brief The exponential distribution. - * - * Sample from the distribution exp(−x/μ) for \e x ≥ 0. - * This uses the logarithm method, see Knuth, TAOCP, Vol 2, Sec 3.4.1.D. - * Example \code - #include - - RandomLib::Random r; - std::cout << "Seed set to " << r.SeedString() << "\n"; - RandomLib::ExponentialDistribution expdist; - std::cout << "Select from exponential distribution:"; - for (size_t i = 0; i < 10; ++i) - std::cout << " " << expdist(r); - std::cout << "\n"; - \endcode - * - * @tparam RealType the real type of the results (default double). - **********************************************************************/ - template class ExponentialDistribution { - public: - /** - * The type returned by ExponentialDistribution::operator()(Random&) - **********************************************************************/ - typedef RealType result_type; - /** - * Return a sample of type RealType from the exponential distribution and - * mean μ. This uses Random::FloatU() which avoids taking log(0) and - * allows rare large values to be returned. If μ = 1, minimum returned - * value = 0 with prob 1/2p; maximum returned value = - * log(2)(\e p + \e e) with prob 1/2p + e. Here - * \e p is the precision of real type RealType and \e e is the exponent - * range. - * - * @tparam Random the type of RandomCanonical generator. - * @param[in,out] r the RandomCanonical generator. - * @param[in] mu the mean value of the exponential distribution (default 1). - * @return the random sample. - **********************************************************************/ - template - RealType operator()(Random& r, RealType mu = RealType(1)) const throw(); - }; - - template template inline RealType - ExponentialDistribution::operator()(Random& r, RealType mu) const - throw() { - return -mu * std::log(r.template FloatU()); - } - -} // namespace RandomLib - -#endif // RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP diff --git a/include/RandomLib/ExponentialProb.hpp b/include/RandomLib/ExponentialProb.hpp deleted file mode 100644 index 119f3aa1..00000000 --- a/include/RandomLib/ExponentialProb.hpp +++ /dev/null @@ -1,166 +0,0 @@ -/** - * \file ExponentialProb.hpp - * \brief Header for ExponentialProb - * - * Return true with probabililty exp(-\e p). - * - * Copyright (c) Charles Karney (2006-2012) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_EXPONENTIALPROB_HPP) -#define RANDOMLIB_EXPONENTIALPROB_HPP 1 - -#include -#include - -#if defined(_MSC_VER) -// Squelch warnings about constant conditional expressions -# pragma warning (push) -# pragma warning (disable: 4127) -#endif - -namespace RandomLib { - /** - * \brief The exponential probability. - * - * Return true with probability exp(−\e p). Basic method taken from:\n - * J. von Neumann,\n Various Techniques used in Connection with Random - * Digits,\n J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38 - * (1951),\n reprinted in Collected Works, Vol. 5, 768--770 (Pergammon, - * 1963).\n See also the references given for the ExactExponential class. - * - * Here the method is extended to be exact by generating sufficient bits in - * the random numbers in the algorithm to allow the unambiguous comparisons - * to be made. - * - * Here's one way of sampling from a normal distribution with zero mean and - * unit variance in the interval [−1,1] with reasonable accuracy: - * \code - #include - #include - - double Normal(RandomLib::Random& r) { - double x; - RandomLib::ExponentialProb e; - do - x = r.FloatW(); - while ( !e(r, - 0.5 * x * x) ); - return x; - } - \endcode - * (Note that the ExactNormal class samples from the normal distribution - * exactly.) - * - * This class uses a mutable private vector. So a single ExponentialProb - * object cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific ExponentialProb - * object. - **********************************************************************/ - class ExponentialProb { - private: - typedef unsigned word; - public: - - ExponentialProb() : _v(std::vector(alloc_incr)) {} - /** - * Return true with probability exp(−\e p). Returns false if \e p - * ≤ 0. For in \e p (0,1], it requires about exp(\e p) random deviates. - * For \e p large, it requires about exp(1)/(1 − exp(−1)) - * random deviates. - * - * @tparam RealType the real type of the argument. - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] p the probability. - * @return true with probability \e p. - **********************************************************************/ - template - bool operator()(Random& r, RealType p) const; - - private: - /** - * Return true with probability exp(−\e p) for \e p in [0,1]. - **********************************************************************/ - template - bool ExpFraction(Random& r, RealType p) const; - /** - * Holds as much of intermediate uniform deviates as needed. - **********************************************************************/ - mutable std::vector _v; - /** - * Increment on size of _v. - **********************************************************************/ - static const unsigned alloc_incr = 16; - }; - - template - bool ExponentialProb::operator()(Random& r, RealType p) const { - STATIC_ASSERT(!std::numeric_limits::is_integer, - "ExponentialProb(): invalid real type RealType"); - return p <= 0 || // True if p <=0 - // Ensure p - 1 < p. Also deal with IsNaN(p) - ( p < RealType(1)/std::numeric_limits::epsilon() && - // exp(a+b) = exp(a) * exp(b) - ExpFraction(r, p < RealType(1) ? p : RealType(1)) && - ( p <= RealType(1) || operator()(r, p - RealType(1)) ) ); - } - - template - bool ExponentialProb::ExpFraction(Random& r, RealType p) const { - // Base of _v is 2^c. Adjust so that word(p) doesn't lose precision. - static const int c = // The Intel compiler needs this to be static?? - std::numeric_limits::digits < - std::numeric_limits::digits ? - std::numeric_limits::digits : - std::numeric_limits::digits; - // m gives number of valid words in _v - unsigned m = 0, l = unsigned(_v.size()); - if (p < RealType(1)) - while (true) { - if (p <= RealType(0)) - return true; - // p in (0, 1) - if (l == m) - _v.resize(l += alloc_incr); - _v[m++] = r.template Integer(); - p *= std::pow(RealType(2), c); // p in (0, 2^c) - word w = word(p); // w in [0, 2^c) - if (_v[m - 1] > w) - return true; - else if (_v[m - 1] < w) - break; - else // _v[m - 1] == w - p -= RealType(w); // p in [0, 1) - } - // Here _v < p. Now loop finding decreasing V. Exit when first increasing - // one is found. - for (unsigned s = 0; ; s ^= 1) { // Parity of loop count - for (unsigned j = 0; ; ++j) { - if (j == m) { - // Need more bits in the old V - if (l == m) - _v.resize(l += alloc_incr); - _v[m++] = r.template Integer(); - } - word w = r.template Integer(); - if (w > _v[j]) - return s != 0u; // New V is bigger, so exit - else if (w < _v[j]) { - _v[j] = w; // New V is smaller, update _v - m = j + 1; // adjusting its size - break; // and generate the next V - } - // Else w == _v[j] and we need to check the next c bits - } - } - } - -} // namespace RandomLib - -#if defined(_MSC_VER) -# pragma warning (pop) -#endif - -#endif // RANDOMLIB_EXPONENTIALPROB_HPP diff --git a/include/RandomLib/InverseEProb.hpp b/include/RandomLib/InverseEProb.hpp deleted file mode 100644 index 100b1795..00000000 --- a/include/RandomLib/InverseEProb.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * \file InverseEProb.hpp - * \brief Header for InverseEProb - * - * Return true with probabililty 1/\e e. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_INVERSEEPROB_HPP) -#define RANDOMLIB_INVERSEEPROB_HPP 1 - -#include -#include - -namespace RandomLib { - - /** - * \brief Return true with probability 1/\e e = exp(−1). - * - * InverseEProb p; p(Random& r) returns true with prob 1/\e e using von - * Neumann's rejection method. It consumes 4.572 bits per call on average. - * - * This class illustrates how to return an exact result using coin tosses - * only. A more efficient way of returning an exact result would be to use - * ExponentialProb p; p(r, 1.0f); - **********************************************************************/ - class InverseEProb { - private: - mutable std::vector _p; - template bool exph(Random& r) { - // Return true with prob 1/sqrt(e). - if (r.Boolean()) return true; - _p.clear(); // vector of bits in p - _p.push_back(false); - for (bool s = false; ; s = !s) { // s is a parity - for (size_t i = 0; ; ++i) { // Compare bits of p and q - if (i == _p.size()) - _p.push_back(r.Boolean()); // Generate next bit of p if necessary - if (r.Boolean()) { // Half the time the bits differ - if (_p[i]) { // p's bit is 1, so q is smaller, update p - _p[i] = false; // Last bit of q 0 - if (++i < _p.size()) _p.resize(i); // p = q - break; - } else - return s; // p's bit is 0, so q is bigger, return parity - } // The other half of the time the bits match, so go to next bit - } - } - } - public: - /** - * Return true with probability 1/\e e. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return true with probability 1/\e e. - **********************************************************************/ - template bool operator()(Random& r) - { return exph(r) && exph(r); } - }; - -} // namespace RandomLib - -#endif // RANDOMLIB_INVERSEEPROB_HPP diff --git a/include/RandomLib/InversePiProb.hpp b/include/RandomLib/InversePiProb.hpp deleted file mode 100644 index 21f105c6..00000000 --- a/include/RandomLib/InversePiProb.hpp +++ /dev/null @@ -1,150 +0,0 @@ -/** - * \file InversePiProb.hpp - * \brief Header for InversePiProb - * - * Return true with probabililty 1/π. - * - * Copyright (c) Charles Karney (2012) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_INVERSEPIPROB_HPP) -#define RANDOMLIB_INVERSEPIPROB_HPP 1 - -#include // for abs(int) -#include - -namespace RandomLib { - - /** - * \brief Return true with probability 1/π. - * - * InversePiProb p; p(Random& r) returns true with prob 1/π using the - * method of Flajolet et al. It consumes 9.6365 bits per call on average. - * - * The method is given in Section 3.3 of - * - P. Flajolet, M. Pelletier, and M. Soria,
- * On Buffon Machines and Numbers,
Proc. 22nd ACM-SIAM Symposium on - * Discrete Algorithms (SODA), Jan. 2011.
- * http://www.siam.org/proceedings/soda/2011/SODA11_015_flajoletp.pdf
- * . - * using the identity - * \f[ \frac 1\pi = \sum_{n=0}^\infty - * {{2n}\choose n}^3 \frac{6n+1}{2^{8n+2}} \f] - * - * It is based on the expression for 1/π given by Eq. (28) of
- * - S. Ramanujan,
- * Modular Equations and Approximations to π,
- * Quart. J. Pure App. Math. 45, 350--372 (1914);
- * In Collected Papers, edited by G. H. Hardy, P. V. Seshu Aiyar, - * B. M. Wilson (Cambridge Univ. Press, 1927; reprinted AMS, 2000).
- * http://books.google.com/books?id=oSioAM4wORMC&pg=PA36
- * . - * \f[\frac4\pi = 1 + \frac74 \biggl(\frac 12 \biggr)^3 - * + \frac{13}{4^2} \biggl(\frac {1\cdot3}{2\cdot4} \biggr)^3 - * + \frac{19}{4^3} \biggl(\frac {1\cdot3\cdot5}{2\cdot4\cdot6} \biggr)^3 - * + \ldots \f] - * - * The following is a description of how to carry out the algorithm "by hand" - * with a real coin, together with a worked example: - * -# Perform three coin tossing experiments in which you toss a coin until - * you get tails, e.g., HHHHT; HHHT; HHT. Let - * h1 = 4, h2 = 3, - * h3 = 2 be the numbers of heads tossed in each - * experiment. - * -# Compute n = ⌊h1/2⌋ + - * ⌊h2/2⌋ + - * mod(⌊(h3 − 1)/3⌋, 2) = 2 + 1 + 0 - * = 3. Here is a table of the 3 contributions to n:\verbatim - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 h - 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 floor(h1/2) - 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 floor(h2/2) - 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 mod(floor((h3-1)/3), 2) - \endverbatim - * -# Perform three additional coin tossing experiments in each of which you - * toss a coin 2n = 6 times, e.g., TTHHTH; - * HHTHH|H; THHHHH. Are the number of heads and tails - * equal in each experiment? yes and no and no → - * false. (Here, you can give up at the |.) - * . - * The final result in this example is false. The most common way a - * true result is obtained is with n = 0, in which case the - * last step vacuously returns true. - * - * Proof of the algorithm: Flajolet et al. rearrange Ramanujan's identity as - * \f[ \frac 1\pi = \sum_{n=0}^\infty - * \biggl[{2n\choose n} \frac1{2^{2n}} \biggr]^3 - * \frac{6n+1}{2^{2n+2}}. \f] - * Noticing that - * \f[ \sum_{n=0}^\infty - * \frac{6n+1}{2^{2n+2}} = 1, \f] - * the algorithm becomes: - * -# pick n ≥ 0 with prob (6n+1) / 22n+2 - * (mean n = 11/9); - * -# return true with prob (binomial(2n, n) / - * 22n)3. - * - * Implement (1) as - * - geom4(r) + geom4(r) returns n with probability 9(n + - * 1) / 22n+4; - * - geom4(r) + geom4(r) + 1 returns n with probability - * 36n / 22n+4; - * - combine these with probabilities [4/9, 5/9] to yield (6n + - * 1) / 22n+2, as required. - * . - * Implement (2) as the outcome of 3 coin tossing experiments of 2n - * tosses with success defined as equal numbers of heads and tails in each - * trial. - * - * This class illustrates how to return an exact result using coin tosses - * only. A more efficient implementation (which is still exact) would - * replace prob59 by r.Prob(5,9) and geom4 by LeadingZeros z; z(r)/2. - **********************************************************************/ - class InversePiProb { - private: - template bool prob59(Random& r) { - // true with prob 5/9 = 0.1 000 111 000 111 000 111 ... (binary expansion) - if (r.Boolean()) return true; - for (bool res = false; ; res = !res) - for (int i = 3; i--; ) if (r.Boolean()) return res; - } - - template int geom4(Random& r) { // Geom(1/4) - int sum = 0; - while (r.Boolean() && r.Boolean()) ++sum; - return sum; - } - - template bool binom(Random& r, int n) { - // Probability of equal heads and tails on 2*n tosses - // = binomial(2*n, n) / 2^(2*n) - int d = 0; - for (int k = n; k--; ) d += r.Boolean() ? 1 : -1; - for (int k = n; k--; ) { - d += r.Boolean() ? 1 : -1; - // This optimization saves 0.1686 bit per call to operator() on average. - if (std::abs(d) > k) return false; - } - return true; - } - - public: - /** - * Return true with probability 1/π. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return true with probability 1/π. - **********************************************************************/ - template bool operator()(Random& r) { - // Return true with prob 1/pi. - int n = geom4(r) + geom4(r) + (prob59(r) ? 1 : 0); - for (int j = 3; j--; ) if (!binom(r, n)) return false; - return true; - } - }; - -} // namespace RandomLib - -#endif // RANDOMLIB_INVERSEPIPROB_HPP diff --git a/include/RandomLib/LeadingZeros.hpp b/include/RandomLib/LeadingZeros.hpp deleted file mode 100644 index b8ee2678..00000000 --- a/include/RandomLib/LeadingZeros.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * \file LeadingZeros.hpp - * \brief Header for LeadingZeros - * - * Count the leading zeros in a real number. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_LEADINGZEROS_HPP) -#define RANDOMLIB_LEADINGZEROS_HPP 1 - -namespace RandomLib { - /** - * \brief Count of leading zeros. - * - * Count of leading zero bits after the binary point in a real number - * uniformly distributed in (0,1). (This is equivalent to the geometric - * distribution with probability 1/2.) For example - * \code - #include - - RandomLib::Random r; // A RandomGenerator works here too - std::cout << "Seed set to " << r.SeedString() << "\n"; - LeadingZeros zeros; - std::cout << "Count of leading zeros:"; - for (size_t i = 0; i < 20; ++i) - std::cout << " " << zeros(r); - std::cout << "\n"; - \endcode - **********************************************************************/ - class LeadingZeros { - public: - /** - * Return the number of zero bits after the binary point in a real number - * uniformly distributed in (0,1). Thus \e k is returned with probability - * 1/2k+1. Because MT19937 is \e not a perfect random - * number generator, this always returns a result in [0, 19937). - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return the random sample. - **********************************************************************/ - template unsigned operator()(Random& r) const throw(); - }; - - template - unsigned LeadingZeros::operator()(Random& r) const throw() { - // It's simpler to count the number of trailing ones in each w-bit block - // stopping when we get to a zero bit. - // - // Process a word in chunks of size m. The algorithm here can deal with - // any m assuming that z is modified accordingly. m = 4 is an approximate - // optimum. - // - // Can also adapt this routine to use RandomNumber::highest_bit_idx - // instead. However the result is considerably slower. - const int m = 4; - STATIC_ASSERT(m <= Random::width, "LeadingZeros: m too large"); - // mask with m low bits set - const typename Random::result_type mask = ~(Random::max << m); - // Number of trailing 1 bits in [0, 1<>= m; // shift out the chunk we've processed - } - // x is all ones (prob 1/2^w); process the next word. - return Random::width + operator()(r); - } - -} // namespace RandomLib - -#endif // RANDOMLIB_LEADINGZEROS_HPP diff --git a/include/RandomLib/MPFRExponential.hpp b/include/RandomLib/MPFRExponential.hpp deleted file mode 100644 index 078b22af..00000000 --- a/include/RandomLib/MPFRExponential.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * \file MPFRExponential.hpp - * \brief Header for MPFRExponential - * - * Sampling exactly from the normal distribution for MPFR. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFREXPONENTIAL_HPP) -#define RANDOMLIB_MPFREXPONENTIAL_HPP 1 - -#include - -#if HAVE_MPFR || defined(DOXYGEN) - -namespace RandomLib { - - /** - * \brief The exponential distribution for MPFR. - * - * This is a transcription of ExactExponential (version 1.4) for use with - * MPFR. - * - * This class uses mutable private objects. So a single MPFRExponential - * object cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific MPFRExponential - * object. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class MPFRExponential { - public: - - /** - * Initialize the MPFRExponential object. - **********************************************************************/ - MPFRExponential() {}; - /** - * Sample from the exponential distribution with mean 1 returning a - * MPFRRandom. - * - * @param[out] t the MPFRRandom result. - * @param[in,out] r a GMP random generator. - **********************************************************************/ - void operator()(MPFRRandom& t, gmp_randstate_t r) const - { Compute(r); _x.swap(t); } - /** - * Sample from the exponential distribution with mean 1. - * - * @param[out] val the sample from the exponential distribution - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (± if val is larger/smaller than - * the exact sample). - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const - { Compute(r); return _x(val, r, round); } - private: - // Disable copy constructor and assignment operator - MPFRExponential(const MPFRExponential&); - MPFRExponential& operator=(const MPFRExponential&); - int ExpFraction(gmp_randstate_t r, MPFRRandom& p) const { - // The early bale out - if (p.TestHighBit(r)) return 0; - // Implement the von Neumann algorithm - _w.Init(); - if (!_w.LessThan(r, p)) return 1; - while (true) { - _v.Init(); if (!_v.LessThan(r, _w)) return 0; - _w.Init(); if (!_w.LessThan(r, _v)) return 1; - } - } - void Compute(gmp_randstate_t r) const { - _x.Init(); - unsigned k = 0; - while (!ExpFraction(r, _x)) { ++k; _x.Init(); } - if (k & 1) _x.SetHighBit(r); - _x.AddInteger(k >> 1); - return; - } - mutable MPFRRandom _x; - mutable MPFRRandom _v; - mutable MPFRRandom _w; - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFREXPONENTIAL_HPP diff --git a/include/RandomLib/MPFRExponentialL.hpp b/include/RandomLib/MPFRExponentialL.hpp deleted file mode 100644 index da250e5b..00000000 --- a/include/RandomLib/MPFRExponentialL.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/** - * \file MPFRExponentialL.hpp - * \brief Header for MPFRExponentialL - * - * Sampling exactly from the exponential distribution for MPFR using the - * traditional method. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFREXPONENTIALL_HPP) -#define RANDOMLIB_MPFREXPONENTIALL_HPP 1 - -#include // for log -#include - -#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3) - -#if HAVE_MPFR || defined(DOXYGEN) - -namespace RandomLib { - - /** - * \brief The exponential distribution for MPFR (the log method). - * - * This class is DEPRECATED. It is included for illustrative purposes - * only. The MPFRExponential class provides a much more efficient method for - * sampling from the exponential distribution. - * - * This is an adaption of ExponentialDistribution to MPFR. The changes are - * - Use MPFR's random number generator - * - Use sufficient precision internally to ensure that a correctly rounded - * result is returned. - * - * This class uses mutable private objects. So a single MPFRExponentialL - * object cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific MPFRExponentialL - * object. - **********************************************************************/ - class MPFRExponentialL { - private: - // The number of bits of randomness to add at a time. - static const long chunk_ = 32; - - public: - /** - * Initialize the MPFRExponentialL object. - **********************************************************************/ - MPFRExponentialL() { - mpz_init(_vi); - mpfr_init2(_eps, chunk_); - mpfr_init2(_v1, chunk_); - mpfr_init2(_v2, chunk_); - } - /** - * Destroy the MPFRExponentialL object. - **********************************************************************/ - ~MPFRExponentialL() { - mpfr_clear(_v2); - mpfr_clear(_v1); - mpfr_clear(_eps); - mpz_clear(_vi); - } - /** - * Sample from the exponential distribution with mean 1. - * - * @param[out] val the sample from the exponential distribution - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (± if val is larger/smaller than - * the exact sample). - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const { - - mpfr_prec_t prec0 = mpfr_get_prec (val); - mpfr_prec_t prec = prec0 + 10; // A rough optimum - mpz_urandomb(_vi, r, prec); - mpfr_set_ui_2exp(_eps, 1u, -prec, MPFR_RNDN); - mpfr_set_prec(_v1, prec); - mpfr_set_z_2exp(_v1, _vi, -prec, MPFR_RNDN); - mpfr_set_prec(_v2, prec); - mpfr_add(_v2, _v1, _eps, MPFR_RNDN); - while (true) { - int f2 = mpfr_log(val, _v2, round); // val = log(upper bound) - mpfr_set_prec(_v2, prec0); - int f1 = mpfr_log(_v2, _v1, round); // v2 = log(lower bound) - if (f1 == f2 && mpfr_equal_p(val, _v2)) { - mpfr_neg(val, val, MPFR_RNDN); - return -f1; - } - prec = Refine(r, prec); - } - } - private: - // disable copy constructor and assignment operator - MPFRExponentialL(const MPFRExponentialL&); - MPFRExponentialL& operator=(const MPFRExponentialL&); - // Refine the random interval - mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec) - const { - prec += chunk_; - mpfr_div_2ui(_eps, _eps, chunk_, MPFR_RNDN); - mpz_urandomb(_vi, r, chunk_); - mpfr_set_prec(_v2, prec); - mpfr_set_z_2exp(_v2, _vi, -prec, MPFR_RNDN); - mpfr_add(_v2, _v1, _v2, MPFR_RNDN); - mpfr_swap(_v1, _v2); // v1 = v2; - mpfr_set_prec(_v2, prec); - mpfr_add(_v2, _v1, _eps, MPFR_RNDN); - return prec; - } - mutable mpz_t _vi; - mutable mpfr_t _eps; - mutable mpfr_t _v1; - mutable mpfr_t _v2; - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFREXPONENTIALL_HPP diff --git a/include/RandomLib/MPFRNormal.hpp b/include/RandomLib/MPFRNormal.hpp deleted file mode 100644 index 08b4a992..00000000 --- a/include/RandomLib/MPFRNormal.hpp +++ /dev/null @@ -1,144 +0,0 @@ -/** - * \file MPFRNormal.hpp - * \brief Header for MPFRNormal - * - * Sampling exactly from the normal distribution for MPFR. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFRNORMAL_HPP) -#define RANDOMLIB_MPFRNORMAL_HPP 1 - -#include // for max/min -#include - -#if HAVE_MPFR || defined(DOXYGEN) - -namespace RandomLib { - - /** - * \brief The normal distribution for MPFR. - * - * This is a transcription of ExactNormal (version 1.3) for use with MPFR. - * - * This class uses mutable private objects. So a single MPFRNormal object - * cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific MPFRNormal object. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class MPFRNormal { - public: - - /** - * Initialize the MPFRNormal object. - **********************************************************************/ - MPFRNormal() { mpz_init(_tt); } - /** - * Destroy the MPFRNormal object. - **********************************************************************/ - ~MPFRNormal() { mpz_clear(_tt); } - /** - * Sample from the normal distribution with mean 0 and variance 1 returning - * a MPFRRandom. - * - * @param[out] t the MPFRRandom result. - * @param[in,out] r a GMP random generator. - **********************************************************************/ - void operator()(MPFRRandom& t,gmp_randstate_t r) const - { Compute(r); return _x.swap(t); } - /** - * Sample from the normal distribution with mean 0 and variance 1. - * - * @param[out] val the sample from the normal distribution - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (±1 if val is larger/smaller than - * the exact sample). - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const - { Compute(r); return _x(val, r, round); } - private: - // Disable copy constructor and assignment operator - MPFRNormal(const MPFRNormal&); - MPFRNormal& operator=(const MPFRNormal&); - // True with prob exp(-1/2) - int ExpProbH(gmp_randstate_t r) const { - _p.Init(); if (_p.TestHighBit(r)) return 1; - // von Neumann rejection - while (true) { - _q.Init(); if (!_q.LessThan(r, _p)) return 0; - _p.Init(); if (!_p.LessThan(r, _q)) return 1; - } - } - // True with prob exp(-n/2) - int ExpProb(gmp_randstate_t r, unsigned n) const { - while (n--) { if (!ExpProbH(r)) return 0; } - return 1; - } - // n with prob (1-exp(-1/2)) * exp(-n/2) - unsigned ExpProbN(gmp_randstate_t r) const { - unsigned n = 0; - while (ExpProbH(r)) ++n; - return n; - } - // Return: - // 1 with prob 2k/(2k + 2) - // 0 with prob 1/(2k + 2) - // -1 with prob 1/(2k + 2) - int Choose(gmp_randstate_t r, int k) const { - const int b = 15; // To avoid integer overflow on multiplication - const int m = 2 * k + 2; - int n1 = m - 2, n2 = m - 1; - while (true) { - mpz_urandomb(_tt, r, b); - int d = int( mpz_get_ui(_tt) ) * m; - n1 = (std::max)((n1 << b) - d, 0); - if (n1 >= m) return 1; - n2 = (std::min)((n2 << b) - d, m); - if (n2 <= 0) return -1; - if (n1 == 0 && n2 == m) return 0; - } - } - void Compute(gmp_randstate_t r) const { - while (true) { - unsigned k = ExpProbN(r); // the integer part of the result. - if (ExpProb(r, (k - 1) * k)) { - _x.Init(); - unsigned s = 1; - for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times - bool first; - for (s = 1, first = true; ; s ^= 1, first = false) { - if (k == 0 && _x.Boolean(r)) break; - _q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break; - int y = k == 0 ? 0 : Choose(r, k); - if (y < 0) - break; - else if (y == 0) { - _p.Init(); if (!_p.LessThan(r, _x)) break; - } - _p.swap(_q); // a fast way of doing p = q - } - if (s == 0) break; - } - if (s != 0) { - _x.AddInteger(k); - if (_x.Boolean(r)) _x.Negate(); - return; - } - } - } - } - mutable mpz_t _tt; // A temporary - mutable MPFRRandom _x; - mutable MPFRRandom _p; - mutable MPFRRandom _q; - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFRNORMAL_HPP diff --git a/include/RandomLib/MPFRNormalK.hpp b/include/RandomLib/MPFRNormalK.hpp deleted file mode 100644 index 74d8e742..00000000 --- a/include/RandomLib/MPFRNormalK.hpp +++ /dev/null @@ -1,138 +0,0 @@ -/** - * \file MPFRNormalK.hpp - * \brief Header for MPFRNormalK - * - * Sampling exactly from the normal distribution for MPFR. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFRNORMALK_HPP) -#define RANDOMLIB_MPFRNORMALK_HPP 1 - -#include // for max -#include -#include - -#if HAVE_MPFR || defined(DOXYGEN) - -namespace RandomLib { - - /** - * \brief The normal distribution for MPFR (Kahn algorithm). - * - * This class is DEPRECATED. It is included for illustrative purposes - * only. The MPFRNormal class provides a somewhat more efficient method for - * sampling from the normal distribution. - * - * Refs: - * - H. Kahn, Rand Report RM-1237-AEC, p. 41 (1954). - * - M. Abramowitz and I. A. Stegun, p. 953, Sec. 26.8.6.a(4) (1964). - * . - * N.B. Damien Stehle' drew my attention to this algorithm as a useful way to - * compute normal deviates exactly. - * - * This class uses mutable private objects. So a single MPFRNormalK object - * cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific MPFRNormalK object. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class MPFRNormalK { - public: - - /** - * Initialize the MPFRNormalK object. - **********************************************************************/ - MPFRNormalK() - { mpfr_init2(_xf, MPFR_PREC_MIN); mpfr_init2(_zf, MPFR_PREC_MIN); } - /** - * Destroy the MPFRNormalK object. - **********************************************************************/ - ~MPFRNormalK() - { mpfr_clear(_zf); mpfr_clear(_xf); } - /** - * Sample from the normal distribution with mean 0 and variance 1 returning - * a MPFRRandom. - * - * @param[out] t the MPFRRandom result. - * @param[in,out] r a GMP random generator. - **********************************************************************/ - void operator()(MPFRRandom& t, gmp_randstate_t r) const - { Compute(r); _x.swap(t); } - /** - * Sample from the normal distribution with mean 0 and variance 1. - * - * @param[out] val the sample from the normal distribution - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (±1 if val is larger/smaller than - * the exact sample). - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const - { Compute(r); return _x(val, r, round); } - private: - // disable copy constructor and assignment operator - MPFRNormalK(const MPFRNormalK&); - MPFRNormalK& operator=(const MPFRNormalK&); - void Compute(gmp_randstate_t r) const { - // The algorithm is sample x and z from the exponential distribution; if - // (x-1)^2 < 2*z, return (random sign)*x; otherwise repeat. Probability - // of acceptance is sqrt(pi/2) * exp(-1/2) = 0.7602. - while (true) { - _edist(_x, r); - _edist(_z, r); - for (mp_size_t k = 1; ; ++k) { - _x.ExpandTo(r, k - 1); - _z.ExpandTo(r, k - 1); - mpfr_prec_t prec = (std::max)(mpfr_prec_t(MPFR_PREC_MIN), k * bits); - mpfr_set_prec(_xf, prec); - mpfr_set_prec(_zf, prec); - // Try for acceptance first; so compute upper limit on (y-1)^2 and - // lower limit on 2*z. - if (_x.UInteger() == 0) { - _x(_xf, MPFR_RNDD); - mpfr_ui_sub(_xf, 1u, _xf, MPFR_RNDU); - } else { - _x(_xf, MPFR_RNDU); - mpfr_sub_ui(_xf, _xf, 1u, MPFR_RNDU); - } - mpfr_sqr(_xf, _xf, MPFR_RNDU); - _z(_zf, MPFR_RNDD); - mpfr_mul_2ui(_zf, _zf, 1u, MPFR_RNDD); - if (mpfr_cmp(_xf, _zf) < 0) { // (y-1)^2 < 2*z, so accept - if (_x.Boolean(r)) _x.Negate(); // include a random sign - return; - } - // Try for rejection; so compute lower limit on (y-1)^2 and upper - // limit on 2*z. - if (_x.UInteger() == 0) { - _x(_xf, MPFR_RNDU); - mpfr_ui_sub(_xf, 1u, _xf, MPFR_RNDD); - } else { - _x(_xf, MPFR_RNDD); - mpfr_sub_ui(_xf, _xf, 1u, MPFR_RNDD); - } - mpfr_sqr(_xf, _xf, MPFR_RNDD); - _z(_zf, MPFR_RNDU); - mpfr_mul_2ui(_zf, _zf, 1u, MPFR_RNDU); - if (mpfr_cmp(_xf, _zf) > 0) // (y-1)^2 > 2*z, so reject - break; - // Otherwise repeat with more precision - } - // Reject and start over with a new y and z - } - } - mutable MPFRRandom _x; - mutable MPFRRandom _z; - mutable mpfr_t _xf; - mutable mpfr_t _zf; - const MPFRExponential _edist; - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFRNORMALK_HPP diff --git a/include/RandomLib/MPFRNormalR.hpp b/include/RandomLib/MPFRNormalR.hpp deleted file mode 100644 index 237606c0..00000000 --- a/include/RandomLib/MPFRNormalR.hpp +++ /dev/null @@ -1,255 +0,0 @@ -/** - * \file MPFRNormalR.hpp - * \brief Header for MPFRNormalR - * - * Sampling exactly from the normal distribution for MPFR using the ratio - * method. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFRNORMALR_HPP) -#define RANDOMLIB_MPFRNORMALR_HPP 1 - -#include // for max/min -#include // for pow -#include - -#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3) - -#if HAVE_MPFR || defined(DOXYGEN) - -namespace RandomLib { - - /** - * \brief The normal distribution for MPFR (ratio method). - * - * This class is DEPRECATED. It is included for illustrative purposes - * only. The MPFRNormal class provides a much more efficient method for - * sampling from the normal distribution. - * - * This is an adaption of NormalDistribution to MPFR. The changes are - * - Use MPFR's random number generator - * - Use sufficient precision internally to ensure that a correctly rounded - * result is returned. - * - * This class uses a mutable private object. So a single MPFRNormalR - * object cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific MPFRNormalR - * object. - **********************************************************************/ - class MPFRNormalR { - private: - // The number of bits of randomness to add at a time. Require that Leva's - // bounds "work" at a precision of 2^-chunk and that an unsigned long can - // hold this many bits. - static const long chunk_ = 32; - static const unsigned long m = 3684067834; // ceil(2^chunk*sqrt(2/e)) - - public: - /** - * Initialize the MPFRNormalR object. - **********************************************************************/ - MPFRNormalR() { - mpz_init(_ui); - mpz_init(_vi); - mpfr_init2(_eps, chunk_); - mpfr_init2(_u, chunk_); - mpfr_init2(_v, chunk_); - mpfr_init2(_up, chunk_); - mpfr_init2(_vp, chunk_); - mpfr_init2(_vx, chunk_); - mpfr_init2(_x1, chunk_); - mpfr_init2(_x2, chunk_); - } - /** - * Destroy the MPFRNormalR object. - **********************************************************************/ - ~MPFRNormalR() { - mpfr_clear(_x2); - mpfr_clear(_x1); - mpfr_clear(_vx); - mpfr_clear(_vp); - mpfr_clear(_up); - mpfr_clear(_v); - mpfr_clear(_u); - mpfr_clear(_eps); - mpz_clear(_vi); - mpz_clear(_ui); - } - /** - * Sample from the normal distribution with mean 0 and variance 1. - * - * @param[out] val the sample from the normal distribution - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (±1 if val is larger/smaller than - * the exact sample). - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const { - const double - s = 0.449871, // Constants from Leva - t = -0.386595, - a = 0.19600 , - b = 0.25472 , - r1 = 0.27597 , - r2 = 0.27846 , - u1 = 0.606530, // sqrt(1/e) rounded down and up - u2 = 0.606531, - scale = std::pow(2.0, -chunk_); // for turning randoms into doubles - - while (true) { - mpz_urandomb(_vi, r, chunk_); - if (mpz_cmp_ui(_vi, m) >= 0) continue; // Very early reject - double vf = (mpz_get_ui(_vi) + 0.5) * scale; - mpz_urandomb(_ui, r, chunk_); - double uf = (mpz_get_ui(_ui) + 0.5) * scale; - double - x = uf - s, - y = vf - t, - Q = x*x + y * (a*y - b*x); - if (Q >= r2) continue; // Early reject - mpfr_set_ui_2exp(_eps, 1u, -chunk_, MPFR_RNDN); - mpfr_prec_t prec = chunk_; - mpfr_set_prec(_u, prec); - mpfr_set_prec(_v, prec); - // (u,v) = sw corner of range - mpfr_set_z_2exp(_u, _ui, -prec, MPFR_RNDN); - mpfr_set_z_2exp(_v, _vi, -prec, MPFR_RNDN); - mpfr_set_prec(_up, prec); - mpfr_set_prec(_vp, prec); - // (up,vp) = ne corner of range - mpfr_add(_up, _u, _eps, MPFR_RNDN); - mpfr_add(_vp, _v, _eps, MPFR_RNDN); - // Estimate how many extra bits will be needed to achieve the desired - // precision. - mpfr_prec_t prec_guard = 3 + chunk_ - - (std::max)(mpz_sizeinbase(_ui, 2), mpz_sizeinbase(_vi, 2)); - if (Q > r1) { - int reject; - while (true) { - // Rejection curve v^2 + 4 * u^2 * log(u) < 0 has a peak at u = - // exp(-1/2) = 0.60653066. So treat uf in (0.606530, 0.606531) = - // (u1, u2) specially - - // Try for rejection first - if (uf <= u1) - reject = Reject(_u, _vp, prec, MPFR_RNDU); - else if (uf >= u2) - reject = Reject(_up, _vp, prec, MPFR_RNDU); - else { // u in (u1, u2) - mpfr_set_prec(_vx, prec); - mpfr_add(_vx, _vp, _eps, MPFR_RNDN); - reject = Reject(_u, _vx, prec, MPFR_RNDU); // Could use _up too - } - if (reject < 0) break; // tried to reject but failed, so accept - - // Try for acceptance - if (uf <= u1) - reject = Reject(_up, _v, prec, MPFR_RNDD); - else if (uf >= u2) - reject = Reject(_u, _v, prec, MPFR_RNDD); - else { // u in (u2, u2) - mpfr_sub(_vx, _v, _eps, MPFR_RNDN); - reject = Reject(_u, _vx, prec, MPFR_RNDD); // Could use _up too - } - if (reject > 0) break; // tried to accept but failed, so reject - - prec = Refine(r, prec); // still can't decide, to refine - } - if (reject > 0) continue; // reject, back to outer loop - } - // Now evaluate v/u to the necessary precision - mpfr_prec_t prec0 = mpfr_get_prec (val); - // while (prec < prec0 + prec_guard) prec = Refine(r, prec); - if (prec < prec0 + prec_guard) - prec = Refine(r, prec, - (prec0 + prec_guard - prec + chunk_ - 1) / chunk_); - mpfr_set_prec(_x1, prec0); - mpfr_set_prec(_x2, prec0); - int flag; - while (true) { - int - f1 = mpfr_div(_x1, _v, _up, round), // min slope - f2 = mpfr_div(_x2, _vp, _u, round); // max slope - if (f1 == f2 && mpfr_equal_p(_x1, _x2)) { - flag = f1; - break; - } - prec = Refine(r, prec); - } - mpz_urandomb(_ui, r, 1); - if (mpz_tstbit(_ui, 0)) { - flag = -flag; - mpfr_neg(val, _x1, MPFR_RNDN); - } else - mpfr_set(val, _x1, MPFR_RNDN); - // std::cerr << uf << " " << vf << " " << Q << "\n"; - return flag; - } - } - private: - // disable copy constructor and assignment operator - MPFRNormalR(const MPFRNormalR&); - MPFRNormalR& operator=(const MPFRNormalR&); - // Refine the random square - mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec, long num = 1) - const { - if (num <= 0) return prec; - // Use _vx as scratch - prec += num * chunk_; - mpfr_div_2ui(_eps, _eps, num * chunk_, MPFR_RNDN); - - mpz_urandomb(_ui, r, num * chunk_); - mpfr_set_prec(_up, prec); - mpfr_set_z_2exp(_up, _ui, -prec, MPFR_RNDN); - mpfr_set_prec(_vx, prec); - mpfr_add(_vx, _u, _up, MPFR_RNDN); - mpfr_swap(_u, _vx); // u = vx - mpfr_add(_up, _u, _eps, MPFR_RNDN); - - mpz_urandomb(_vi, r, num * chunk_); - mpfr_set_prec(_vp, prec); - mpfr_set_z_2exp(_vp, _vi, -prec, MPFR_RNDN); - mpfr_set_prec(_vx, prec); - mpfr_add(_vx, _v, _vp, MPFR_RNDN); - mpfr_swap(_v, _vx); // v = vx - mpfr_add(_vp, _v, _eps, MPFR_RNDN); - - return prec; - } - // Evaluate the sign of the rejection condition v^2 + 4*u^2*log(u) - int Reject(mpfr_t u, mpfr_t v, mpfr_prec_t prec, mpfr_rnd_t round) const { - // Use x1, x2 as scratch - mpfr_set_prec(_x1, prec); - - mpfr_log(_x1, u, round); - mpfr_mul(_x1, _x1, u, round); // Important to do the multiplications in - mpfr_mul(_x1, _x1, u, round); // this order so that rounding works right. - mpfr_mul_2ui(_x1, _x1, 2u, round); // 4*u^2*log(u) - - mpfr_set_prec(_x2, prec); - mpfr_mul(_x2, v, v, round); // v^2 - - mpfr_add(_x1, _x1, _x2, round); // v^2 + 4*u^2*log(u) - - return mpfr_sgn(_x1); - } - mutable mpz_t _ui; - mutable mpz_t _vi; - mutable mpfr_t _eps; - mutable mpfr_t _u; - mutable mpfr_t _v; - mutable mpfr_t _up; - mutable mpfr_t _vp; - mutable mpfr_t _vx; - mutable mpfr_t _x1; - mutable mpfr_t _x2; - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFRNORMALR_HPP diff --git a/include/RandomLib/MPFRRandom.hpp b/include/RandomLib/MPFRRandom.hpp deleted file mode 100644 index e59cb0aa..00000000 --- a/include/RandomLib/MPFRRandom.hpp +++ /dev/null @@ -1,383 +0,0 @@ -/** - * \file MPFRRandom.hpp - * \brief Header for MPFRRandom - * - * Utility class for MPFRUniform, MPFRExponential, and MPFRNormal. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFRRANDOM_HPP) -#define RANDOMLIB_MPFRRANDOM_HPP 1 - -#include // for swap -#include - -#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3) - -#if HAVE_MPFR || defined(DOXYGEN) - -/** - * A compile-time assert. Use C++11 static_assert, if available. - **********************************************************************/ -#if !defined(STATIC_ASSERT) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define STATIC_ASSERT static_assert -# elif defined(_MSC_VER) && _MSC_VER >= 1600 -# define STATIC_ASSERT static_assert -# else -# define STATIC_ASSERT(cond,reason) \ - { enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; } -# endif -#endif - -namespace RandomLib { - - /** - * \brief Handling random numbers in MPFR. - * - * This class provides roughly the same capabilities as RandomNumber. The - * fraction is represented by a mpz integer \e f and an exponent \e e. We - * have \e e ≥ 0 and 0 ≤ \e f < be, and \e b = - * 2bits. This represents the number \e x = \e f - * be, with x in [0, 1). - * - * @tparam bits the number of bits in each digit. - * - * \e bits must divide GMP_LIMB_BITS. The default value \e bits = 32 yields - * portable results on all MPFR platforms. - **********************************************************************/ - template class MPFRRandom { - private: - static const int limb_ = GMP_LIMB_BITS; // How many bits in a limb - static const int loglimb_ = (limb_ == 32 ? 5 : - (limb_ == 64 ? 6 : - (limb_ == 128 ? 7 : -1))); - static const int logbits_ = (bits == 1 ? 0 : - (bits == 2 ? 1 : - (bits == 4 ? 2 : - (bits == 8 ? 3 : - (bits == 16 ? 4 : - (bits == 32 ? 5 : - (bits == 64 ? 6 : - (bits == 128 ? 7 : -1)))))))); - static const mp_limb_t mask_ = (bits == limb_ ? ~0UL : // Digit mask - ~(~0UL << (bits < limb_ ? bits : 0))); - static const int logw_ = loglimb_ - logbits_; // 2^logw digits per limb - static const unsigned wmask_ = ~(~0U << logw_); - - mutable mpz_t _tt; // A temporary - mpz_t _f; // The fraction - mp_size_t _e; // Count of digits - unsigned long _n; // Integer part - int _s; // Sign - void AddDigits(gmp_randstate_t r, long num = 1) { // Add num more digits - if (num <= 0) return; - mpz_mul_2exp(_f, _f, num << logbits_); - mpz_urandomb(_tt, r, num << logbits_); - mpz_add(_f, _f, _tt); - _e += num; - } - // return k'th digit counting k = 0 as most significant - mp_limb_t Digit(gmp_randstate_t r, mp_size_t k) { - ExpandTo(r, k); // Now e > k - k = _e - 1 - k; // Reverse k so k = 0 is least significant - // (k >> logw) is the limb index - // (k & wmask) is the digit position within the limb - return mask_ & - (mpz_getlimbn(_f, k >> logw_) >> ((k & wmask_) << logbits_)); - } - // Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x - // = ~0. (From Algorithms for programmers by Joerg Arndt.) - static int highest_bit_idx(unsigned long x) throw() { - if (x == 0) return 0; - int r = 1; - // STILL TO DO: handle 64-bit unsigned longs. - if (x & 0xffff0000UL) { x >>= 16; r += 16; } - if (x & 0x0000ff00UL) { x >>= 8; r += 8; } - if (x & 0x000000f0UL) { x >>= 4; r += 4; } - if (x & 0x0000000cUL) { x >>= 2; r += 2; } - if (x & 0x00000002UL) { r += 1; } - return r; - } - public: - /** - * Initialize the MPFRRandom object. - **********************************************************************/ - MPFRRandom() : _e(0u), _n(0u), _s(1) { - STATIC_ASSERT(logbits_ >= 0 && loglimb_ >= 0 && logbits_ <= loglimb_, - "MPRFRandom: unsupported value for bits"); - mpz_init(_f); mpz_init(_tt); - } - /** - * Initialize the MPFRRandom object from another one. - * - * @param[in] t the MPFRRandom to copy. - **********************************************************************/ - MPFRRandom(const MPFRRandom& t) : _e(t._e), _n(t._n), _s(t._s) - { mpz_init(_f); mpz_set(_f, t._f); mpz_init(_tt); } - /** - * Destroy the MPFRRandom object. - **********************************************************************/ - ~MPFRRandom() { mpz_clear(_f); mpz_clear(_tt); } - /** - * Assignment operator. (But swapping is typically faster.) - * - * @param[in] t the MPFRRandom to copy. - **********************************************************************/ - MPFRRandom& operator=(const MPFRRandom& t) { - _e = t._e; - _n = t._n; - _s = t._s; - mpz_set(_f, t._f); // Don't copy _tt - return *this; - } - /** - * Swap with another MPFRRandom. This is a fast way of doing an - * assignment. - * - * @param[in,out] t the MPFRRandom to swap with. - **********************************************************************/ - void swap(MPFRRandom& t) throw() { - if (this != &t) { - std::swap(_e, t._e); - std::swap(_n, t._n); - std::swap(_s, t._s); - mpz_swap(_f, t._f); // Don't swap _tt - } - } - /** - * Reinitialize the MPFRRandom object, setting its value to [0,1]. - **********************************************************************/ - void Init() { mpz_set_ui(_f, 0u); _e = 0; _n = 0; _s = 1; } - /** - * @return the sign of the MPFRRandom (± 1). - **********************************************************************/ - int Sign() const throw() { return _s; } - /** - * Change the sign of the MPFRRandom. - **********************************************************************/ - void Negate() throw() { _s *= -1; } - /** - * @return the floor of the MPFRRandom - **********************************************************************/ - long Floor() const throw() { return _s > 0 ? long(_n) : -1 - long(_n); } - /** - * @return the ceiling of the MPFRRandom - **********************************************************************/ - long Ceiling() const throw() { return _s > 0 ? 1 + long(_n) : -long(_n); } - /** - * @return the unsigned integer component of the MPFRRandom. - **********************************************************************/ - unsigned long UInteger() const throw() { return _n; } - /** - * @return the number of digits in fraction - **********************************************************************/ - unsigned long Size() const throw() { return unsigned(_e); } - /** - * Add integer \e k to the MPRFRandom. - * - * @param[in] k the integer to add. - **********************************************************************/ - void AddInteger(long k) { - k += Floor(); // The new floor - int ns = k < 0 ? -1 : 1; // The new sign - if (ns != _s) { // If sign changes, set f = 1 - f - mpz_set_ui(_tt, 1u); - mpz_mul_2exp(_tt, _tt, _e << logbits_); - mpz_sub_ui(_tt, _tt, 1u); - mpz_sub(_f, _tt, _f); - _s = ns; - } - _n = ns > 0 ? k : -(k + 1); - } - /** - * Compare with another MPFRRandom, *this < \e t. - * - * @param[in,out] r a random generator. - * @param[in,out] t a MPFRRandom to compare. - * @return true if *this < \e t. - **********************************************************************/ - int LessThan(gmp_randstate_t r, MPFRRandom& t) { - if (this == &t) return false; // same object - if (_s != t._s) return _s < t._s; - if (_n != t._n) return (_s < 0) ^ (_n < t._n); - for (mp_size_t k = 0; ; ++k) { - mp_limb_t x = Digit(r, k); - mp_limb_t y = t.Digit(r, k); - if (x != y) return (_s < 0) ^ (x < y); - } - } - /** - * Set high bit of fraction to 1. - * - * @param[in,out] r a random generator. - **********************************************************************/ - void SetHighBit(gmp_randstate_t r) { // Set the msb to 1 - ExpandTo(r, 0); // Generate msb if necessary - mpz_setbit(_f, (_e << logbits_) - 1); - } - /** - * Test high bit of fraction. - * - * @param[in,out] r a random generator. - **********************************************************************/ - int TestHighBit(gmp_randstate_t r) { // test the msb of f - ExpandTo(r, 0); // Generate msb if necessary - return mpz_tstbit(_f, (_e << logbits_) - 1); - } - /** - * Return the position of the most significant bit in the MPFRRandom. - * - * @param[in,out] r a random generator. - * - * The bit position is numbered such the 1/2 bit is 0, the 1/4 bit is -1, - * etc. - **********************************************************************/ - mp_size_t LeadingBit(gmp_randstate_t r) { - if (_n) return highest_bit_idx(_n); - while (true) { - int sgn = mpz_sgn(_f); - if (sgn != 0) - return mp_size_t(mpz_sizeinbase(_f, 2)) - mp_size_t(_e << logbits_); - AddDigits(r); - } - } - /** - * Ensure that the k'th digit of the fraction is computed. - * - * @param[in,out] r a random generator. - * @param[in] k the digit number (0 is the most significant, 1 is the next - * most significant, etc. - **********************************************************************/ - void ExpandTo(gmp_randstate_t r, mp_size_t k) - { if (_e <= k) AddDigits(r, k - _e + 1); } - /** - * Convert to a MPFR number \e without adding more bits. - * - * @param[out] val the value of s * (n + *this). - * @param[in] round the rounding direction. - * @return the MPFR ternary result (± if val is larger/smaller than - * the exact sample). - * - * If round is MPFR_RNDN, then the rounded midpoint of the interval - * represented by the MPFRRandom is returned. Otherwise it is the rounded - * lower or upper bound of the interval (whichever is appropriate). - **********************************************************************/ - int operator()(mpfr_t val, mpfr_rnd_t round) - { return operator()(val, NULL, round); } - /** - * Convert to a MPFR number. - * - * @param[out] val the value of s * (n + *this). - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (± if val is larger/smaller than - * the exact sample). - * - * If \e r is NULL, then no additional random bits are generated and the - * lower bound, midpoint, or upper bound of the MPFRRandom interval is - * returned, depending on the value of \e round. - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) { - // The value is constructed as a positive quantity, so adjust rounding - // mode to account for this. - switch (round) { - case MPFR_RNDD: - case MPFR_RNDU: - case MPFR_RNDN: - break; - case MPFR_RNDZ: - round = _s < 0 ? MPFR_RNDU : MPFR_RNDD; - break; - case MPFR_RNDA: - round = _s < 0 ? MPFR_RNDD : MPFR_RNDU; - break; - default: - round = MPFR_RNDN; // New rounding modes are variants of N - break; - } // Now round is one of MPFR_RND{D,N,U} - - mp_size_t excess; - mpfr_exp_t expt; - if (r == NULL) { - // If r is NULL then all the bits currently generated are considered - // significant. Thus no excess bits need to be squeezed out. - excess = 0; - // And the exponent shift in mpfr_set_z_2exp is just... - expt = -(_e << logbits_); - // However, if rounding to nearest, we need to make room for the - // midpoint bit. - if (round == MPFR_RNDN) { - excess = -1; - --expt; - } - } else { // r is non-NULL - // Generate enough digits, i.e., enough to generate prec significant - // figures for RNDD and RNDU; for RNDN we need to generate an - // additional guard bit. - mp_size_t lead = LeadingBit(r); - mpfr_prec_t prec = mpfr_get_prec (val); - mp_size_t trail = lead - prec; // position one past trailing bit - mp_size_t guard = trail + (round == MPFR_RNDN ? 0 : 1); // guard bit pos - // Generate the bits needed. - if (guard <= 0) ExpandTo(r, (-guard) >> logbits_); - // Unless bits = 1, the generation process will typically have - // generated too many bits. We figure out how many, but leaving room - // for one additional "inexact" bit. The inexact bit is set to 1 in - // order to force MPFR to treat the result as inexact, to break RNDN - // ties, and to get the ternary value set correctly. - // - // expt is the exponent used when forming the number using - // mpfr_set_z_2exp. Without the inexact bit, it's (guard - 1). - // Subtract 1 to account for the inexact bit. - expt = guard - 2; - // The number of excess bits is now the difference between the number - // of bits in the fraction (e << logbits) and -expt. Note that this - // may be -1 (meaning we'll need to shift the number left to - // accommodate the inexact bit). - excess = (_e << logbits_) + expt; - } - mpz_set_ui(_tt, _n); // The integer part - mpz_mul_2exp(_tt, _tt, _e << logbits_); // Shift to allow for fraction - mpz_add(_tt, _tt, _f); // Add fraction - if (excess > 0) - mpz_tdiv_q_2exp(_tt, _tt, excess); - else if (excess < 0) - mpz_mul_2exp(_tt, _tt, -excess); - if (r || round == MPFR_RNDN) - // Set the inexact bit (or compute the midpoint if r is NULL). - mpz_setbit(_tt, 0); - else if (round == MPFR_RNDU) - // If r is NULL, compute the upper bound. - mpz_add_ui(_tt, _tt, 1u); - - // Convert to a mpfr number. If r is specified, then there are - // sufficient bits in tt that the result is inexact and that (in the case - // of RNDN) there are no ties. - int flag = mpfr_set_z_2exp(val, _tt, expt, round); - if (_s < 0) { - mpfr_neg (val, val, MPFR_RNDN); - flag = -flag; - } - return flag; - } - /** - * A coin toss. (This should really be a static function. But it uses the - * MPFRRandom temporary variable.) - * - * @param[in,out] r a GMP random generator. - * @return true or false. - **********************************************************************/ - int Boolean(gmp_randstate_t r) const { - mpz_urandomb(_tt, r, 1); - return mpz_tstbit(_tt, 0); - } - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFRRANDOM_HPP diff --git a/include/RandomLib/MPFRUniform.hpp b/include/RandomLib/MPFRUniform.hpp deleted file mode 100644 index 38b8ffb1..00000000 --- a/include/RandomLib/MPFRUniform.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * \file MPFRUniform.hpp - * \brief Header for MPFRUniform - * - * Sampling exactly from a uniform distribution for MPFR. - * - * Copyright (c) Charles Karney (2012) and licensed under - * the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_MPFRUNIFORM_HPP) -#define RANDOMLIB_MPFRUNIFORM_HPP 1 - -#include - -#if HAVE_MPFR || defined(DOXYGEN) - -namespace RandomLib { - - /** - * \brief The uniform distribution for MPFR. - * - * This is just a thin layer on top of MPFRRandom to provide random numbers - * uniformly distributed in [0,1]. - * - * This class uses a mutable private object. So a single MPFRUniform object - * cannot safely be used by multiple threads. In a multi-processing - * environment, each thread should use a thread-specific MPFRUniform object. - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class MPFRUniform { - public: - - /** - * Initialize the MPFRUniform object. - **********************************************************************/ - MPFRUniform() {}; - /** - * Sample from the uniform distribution in [0,1] returning a MPFRRandom. - * This function takes an unused GMP random generator as a parameter, in - * order to parallel the usage of MPFRExponential and MPFRNormal. - * - * @param[out] t the MPFRRandom result. - * @param[in,out] r a GMP random generator (unused). - **********************************************************************/ - void operator()(MPFRRandom& t, gmp_randstate_t r) const - { Compute(r); _x.swap(t); } - /** - * Sample from the uniform distribution in [0,1]. - * - * @param[out] val the sample from the uniform distribution - * @param[in,out] r a GMP random generator. - * @param[in] round the rounding direction. - * @return the MPFR ternary result (± if val is larger/smaller than - * the exact sample). - **********************************************************************/ - int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const - { Compute(r); return _x(val, r, round); } - private: - // disable copy constructor and assignment operator - MPFRUniform(const MPFRUniform&); - MPFRUniform& operator=(const MPFRUniform&); - void Compute(gmp_randstate_t /* r */) const { _x. Init(); } - mutable MPFRRandom _x; - }; - -} // namespace RandomLib - -#endif // HAVE_MPFR -#endif // RANDOMLIB_MPFRUNIFORM_HPP diff --git a/include/RandomLib/NormalDistribution.hpp b/include/RandomLib/NormalDistribution.hpp deleted file mode 100644 index fbe2811d..00000000 --- a/include/RandomLib/NormalDistribution.hpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * \file NormalDistribution.hpp - * \brief Header for NormalDistribution - * - * Compute normal deviates. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_NORMALDISTRIBUTION_HPP) -#define RANDOMLIB_NORMALDISTRIBUTION_HPP 1 - -#include // for std::log - -namespace RandomLib { - /** - * \brief Normal deviates - * - * Sample from the normal distribution. - * - * This uses the ratio method; see Knuth, TAOCP, Vol 2, Sec. 3.4.1.C, - * Algorithm R. Unlike the Box-Muller method which generates two normal - * deviates at a time, this method generates just one. This means that this - * class has no state that needs to be saved when checkpointing a - * calculation. Original citation is\n A. J. Kinderman, J. F. Monahan,\n - * Computer Generation of Random Variables Using the Ratio of Uniform - * Deviates,\n ACM TOMS 3, 257--260 (1977). - * - * Improved "quadratic" bounds are given by\n J. L. Leva,\n A Fast Normal - * Random Number Generator,\n ACM TOMS 18, 449--453 and 454--455 - * (1992). - * - * The log is evaluated 1.369 times per normal deviate with no bounds, 0.232 - * times with Knuth's bounds, and 0.012 times with the quadratic bounds. - * Time is approx 0.3 us per deviate (1GHz machine, optimized, RealType = - * float). - * - * Example - * \code - * #include - * - * RandomLib::Random r; - * std::cout << "Seed set to " << r.SeedString() << "\n"; - * RandomLib::NormalDistribution normdist; - * std::cout << "Select from normal distribution:"; - * for (size_t i = 0; i < 10; ++i) - * std::cout << " " << normdist(r); - * std::cout << "\n"; - * \endcode - * - * @tparam RealType the real type of the results (default double). - **********************************************************************/ - template class NormalDistribution { - public: - /** - * The type returned by NormalDistribution::operator()(Random&) - **********************************************************************/ - typedef RealType result_type; - /** - * Return a sample of type RealType from the normal distribution with mean - * μ and standard deviation σ. - * - * For μ = 0 and σ = 1 (the defaults), the distribution is - * symmetric about zero and is nonzero. The maximum result is less than 2 - * sqrt(log(2) \e p) where \e p is the precision of real type RealType. - * The minimum positive value is approximately 1/2p+1. - * Here \e p is the precision of real type RealType. - * - * @tparam Random the type of RandomCanonical generator. - * @param[in,out] r the RandomCanonical generator. - * @param[in] mu the mean value of the normal distribution (default 0). - * @param[in] sigma the standard deviation of the normal distribution - * (default 1). - * @return the random sample. - **********************************************************************/ - template - RealType operator()(Random& r, RealType mu = RealType(0), - RealType sigma = RealType(1)) const throw(); - }; - - template template inline RealType - NormalDistribution::operator()(Random& r, RealType mu, - RealType sigma) const throw() { - // N.B. These constants can be regarded as "exact", so that the same number - // of significant figures are used in all versions. (They serve to - // "bracket" the real boundary specified by the log expression.) - const RealType - m = RealType( 1.7156 ), // sqrt(8/e) (rounded up) - s = RealType( 0.449871), // Constants from Leva - t = RealType(-0.386595), - a = RealType( 0.19600 ), - b = RealType( 0.25472 ), - r1 = RealType( 0.27597 ), - r2 = RealType( 0.27846 ); - RealType u, v, Q; - do { // This loop is executed 1.369 times on average - // Pick point P = (u, v) - u = r.template FixedU(); // Sample u in (0,1] - v = m * r.template FixedS(); // Sample v in (-m/2, m/2); avoid 0 - // Compute quadratic form Q - const RealType x = u - s; - const RealType y = (v < 0 ? -v : v) - t; // Sun has no long double abs! - Q = x*x + y * (a*y - b*x); - } while ( Q >= r1 && // accept P if Q < r1 - ( Q > r2 || // reject P if Q > r2 - v*v > - 4 * u*u * std::log(u) ) ); // accept P if v^2 <= ... - return mu + sigma * (v / u); // return the slope of P (note u != 0) - } - -} // namespace RandomLib - -#endif // RANDOMLIB_NORMALDISTRIBUTION_HPP diff --git a/include/RandomLib/Random.hpp b/include/RandomLib/Random.hpp deleted file mode 100644 index cc679123..00000000 --- a/include/RandomLib/Random.hpp +++ /dev/null @@ -1,141 +0,0 @@ -/** - * \file Random.hpp - * \brief Header for Random, RandomGenerator. - * - * This loads up the header for RandomCanonical, RandomEngine, etc., to - * provide access to random integers of various sizes, random reals with - * various precisions, a random probability, etc. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOM_HPP) -#define RANDOMLIB_RANDOM_HPP 1 - -#include - -#if defined(_MSC_VER) -typedef unsigned uint32_t; -typedef unsigned long long uint64_t; -#else -#include -#endif - -/** - * Use table, Power2::power2, for pow2? This isn't necessary with g++ 4.0 - * because calls to std::pow are optimized. g++ 4.1 seems to have lost this - * capability though! And it's back in g++ 4.4. So, for simplicity, assume - * that all "current" versions of g++ perform the optimization. - **********************************************************************/ -#if !defined(RANDOMLIB_POWERTABLE) -#if defined(__GNUC__) -#define RANDOMLIB_POWERTABLE 0 -#else -// otherwise use a lookup table -#define RANDOMLIB_POWERTABLE 1 -#endif -#endif - -#if !HAVE_LONG_DOUBLE || defined(_MSC_VER) -#define RANDOMLIB_LONGDOUBLEPREC 53 -#elif defined(__sparc) -#define RANDOMLIB_LONGDOUBLEPREC 113 -#else -/** - * The precision of long doubles, used for sizing Power2::power2. 64 on - * Linux/Intel, 106 on MaxOS/PowerPC - **********************************************************************/ -#define RANDOMLIB_LONGDOUBLEPREC __LDBL_MANT_DIG__ -#endif - -/** - * A compile-time assert. Use C++11 static_assert, if available. - **********************************************************************/ -#if !defined(STATIC_ASSERT) -# if __cplusplus >= 201103 -# define STATIC_ASSERT static_assert -# elif defined(__GXX_EXPERIMENTAL_CXX0X__) -# define STATIC_ASSERT static_assert -# elif defined(_MSC_VER) && _MSC_VER >= 1600 -# define STATIC_ASSERT static_assert -# else -# define STATIC_ASSERT(cond,reason) \ - { enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; } -# endif -#endif - -/** - * Are denormalized reals of type RealType supported? - **********************************************************************/ -#define RANDOMLIB_HASDENORM(RealType) 1 - -#if defined(_MSC_VER) && defined(RANDOMLIB_SHARED_LIB) && RANDOMLIB_SHARED_LIB -# if RANDOMLIB_SHARED_LIB > 1 -# error RANDOMLIB_SHARED_LIB must be 0 or 1 -# elif defined(RandomLib_EXPORTS) -# define RANDOMLIB_EXPORT __declspec(dllexport) -# else -# define RANDOMLIB_EXPORT __declspec(dllimport) -# endif -#else -# define RANDOMLIB_EXPORT -#endif - -#include - -/** - * \brief Namespace for %RandomLib - * - * All of %RandomLib is defined within the RandomLib namespace. In addtiion - * all the header files are included via %RandomLib/filename. This minimizes - * the likelihood of conflicts with other packages. - **********************************************************************/ -namespace RandomLib { - - /** - * \brief Exception handling for %RandomLib - * - * A class to handle exceptions. It's derived from std::runtime_error so it - * can be caught by the usual catch clauses. - **********************************************************************/ - class RandomErr : public std::runtime_error { - public: - - /** - * Constructor - * - * @param[in] msg a string message, which is accessible in the catch - * clause, via what(). - **********************************************************************/ - RandomErr(const std::string& msg) : std::runtime_error(msg) {} - }; - -} // namespace RandomLib - -#include - -#if !defined(RANDOMLIB_BUILDING_LIBRARY) - -namespace RandomLib { - -#if !defined(RANDOMLIB_DEFAULT_GENERATOR) -#define RANDOMLIB_DEFAULT_GENERATOR SRandomGenerator32 -#endif - - /** - * Point Random to one of a specific MT19937 generators. - **********************************************************************/ - typedef RANDOMLIB_DEFAULT_GENERATOR RandomGenerator; - - /** - * Hook Random to RandomGenerator - **********************************************************************/ - typedef RandomCanonical Random; - -} // namespace RandomLib - -#endif // !defined(RANDOMLIB_BUILDING_LIBRARY) - -#endif // RANDOMLIB_RANDOM_HPP diff --git a/include/RandomLib/RandomAlgorithm.hpp b/include/RandomLib/RandomAlgorithm.hpp deleted file mode 100644 index 0ceaf113..00000000 --- a/include/RandomLib/RandomAlgorithm.hpp +++ /dev/null @@ -1,384 +0,0 @@ -/** - * \file RandomAlgorithm.hpp - * \brief Header for MT19937 and SFMT19937. - * - * This provides an interface to the Mersenne Twister - * - * MT19937 and SIMD oriented Fast Mersenne Twister - * - * SFMT19937 random number engines. - * - * Interface routines written by Charles Karney and - * licensed under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMALGORITHM_HPP) -#define RANDOMLIB_RANDOMALGORITHM_HPP 1 - -#include -#include -#include -#if defined(HAVE_SSE2) && HAVE_SSE2 -#include -#endif - -#if (defined(HAVE_SSE2) && HAVE_SSE2) && (defined(HAVE_ALTIVEC) && HAVE_ALTIVEC) -#error "HAVE_SSE2 and HAVE_ALTIVEC should not both be defined" -#endif - -#if defined(_MSC_VER) -// Squelch warnings about casts truncating constants -# pragma warning (push) -# pragma warning (disable: 4310) -#endif - -namespace RandomLib { - - /** - * \brief The %MT19937 random number engine. - * - * This provides an interface to Mersenne Twister random number engine, - * - * MT19937. See\n Makoto Matsumoto and Takuji Nishimura,\n Mersenne - * Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number - * Generator,\n ACM TOMACS 8, 3--30 (1998) - * - * This is adapted from the 32-bit and 64-bit C versions available at - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html and - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html - * - * The template argument give the type \e RandomType of the "natural" result. - * This incorporates the bit width and the C++ type of the result. Although - * the two versions of MT19937 produce different sequences, the - * implementations here are portable across 32-bit and 64-bit architectures. - * - * The class chiefly supplies the method for advancing the state by - * Transition. - * - * @tparam RandomType the type of the results, either Random_u32 or - * Random_u64. - * - * Interface routines written by Charles Karney and - * licensed under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - template class RANDOMLIB_EXPORT MT19937 { - public: - /** - * The result RandomType - **********************************************************************/ - typedef RandomType engine_t; - /** - * The internal numeric type for MT19337::Transition - **********************************************************************/ - typedef typename engine_t::type internal_type; - private: - /** - * The unsigned type of engine_t - **********************************************************************/ - typedef typename engine_t::type engine_type; - /** - * The width of the engine_t - **********************************************************************/ - static const unsigned width = engine_t::width; - enum { - /** - * The Mersenne prime is 2P − 1 - **********************************************************************/ - P = 19937, - /** - * The short lag for MT19937 - **********************************************************************/ - M = width == 32 ? 397 : 156, - /** - * The number of ignored bits in the first word of the state - **********************************************************************/ - R = ((P + width - 1)/width) * width - P - }; - static const engine_type mask = engine_t::mask; - /** - * Magic matrix for MT19937 - **********************************************************************/ - static const engine_type magic = - width == 32 ? 0x9908b0dfULL : 0xb5026f5aa96619e9ULL; - /** - * Mask for top \e width − \e R bits of a word - **********************************************************************/ - static const engine_type upper = mask << R & mask; - /** - * Mask for low \e R bits of a width-bit word - **********************************************************************/ - static const engine_type lower = ~upper & mask; - - public: - /** - * A version number "EnMT" or "EnMU" to ensure safety of Save/Load. This - * needs to be unique across RandomAlgorithms. - **********************************************************************/ - static const unsigned version = 0x456e4d54UL + (engine_t::width/32 - 1); - enum { - /** - * The size of the state. This is the long lag for MT19937. - **********************************************************************/ - N = (P + width - 1)/width - }; - /** - * Advance state by \e count batches. For speed all \e N words of state - * are advanced together. If \e count is negative, the state is stepped - * backwards. This is the meat of the MT19937 engine. - * - * @param[in] count how many batches to advance. - * @param[in,out] statev the internal state of the random number generator. - **********************************************************************/ - static void Transition(long long count, internal_type statev[]) throw(); - - /** - * Manipulate a word of the state prior to output. - * - * @param[in] y a word of the state. - * @return the result. - **********************************************************************/ - static engine_type Generate(engine_type y) throw(); - - /** - * Convert an arbitrary state into a legal one. This consists of (a) - * turning on one bit if the state is all zero and (b) making 31 bits of - * the state consistent with the other 19937 bits. - * - * @param[in,out] state the state of the generator. - **********************************************************************/ - static void NormalizeState(engine_type state[]) throw(); - - /** - * Check that the state is legal, throwing an exception if it is not. At - * the same time, accumulate a checksum of the state. - * - * @param[in] state the state of the generator. - * @param[in,out] check an accumulated checksum. - **********************************************************************/ - static void CheckState(const engine_type state[], Random_u32::type& check); - - /** - * Return the name of the engine - * - * @return the name. - **********************************************************************/ - static std::string Name() throw() { - return "MT19937"; - } - }; - - /// \cond SKIP - template<> - inline Random_u32::type MT19937::Generate(engine_type y) throw() { - y ^= y >> 11; - y ^= y << 7 & engine_type(0x9d2c5680UL); - y ^= y << 15 & engine_type(0xefc60000UL); - y ^= y >> 18; - - return y; - } - - template<> - inline Random_u64::type MT19937::Generate(engine_type y) throw() { - // Specific tempering instantiation for width = 64 given in - // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html - y ^= y >> 29 & engine_type(0x5555555555555555ULL); - y ^= y << 17 & engine_type(0x71d67fffeda60000ULL); - y ^= y << 37 & engine_type(0xfff7eee000000000ULL); - y ^= y >> 43; - - return y; - } - /// \endcond - - /** - * \brief The SFMT random number engine. - * - * This provides an implementation of the SIMD-oriented Fast Mersenne Twister - * random number engine, - * - * SFMT. See\n Mutsuo Saito,\n An Application of Finite Field: Design - * and Implementation of 128-bit Instruction-Based Fast Pseudorandom Number - * Generator,\n Master's Thesis, Dept. of Math., Hiroshima University - * (Feb. 2007).\n - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/M062821.pdf - * Mutsuo Saito and Makoto Matsumoto,\n - * SIMD-oriented Fast Mersenne Twister: a 128-bit Pseudorandom Number - * Generator,\n accepted in the proceedings of MCQMC2006\n - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/sfmt.pdf - * - * The template argument gives the type \e RandomType of the "natural" - * result. This incorporates the bit width and the C++ type of the result. - * The 32-bit and 64-bit versions of SFMT19937 produce the same sequences and - * the differing only in whether how the state is represented. The - * implementation includes a version using 128-bit SSE2 instructions. On - * machines without these instructions, portable implementations using - * traditional operations are provided. With the same starting seed, - * SRandom32::Ran64() and SRandom64::Ran64() produces the same sequences. - * Similarly SRandom64::Ran32() produces every other member of the sequence - * produced by SRandom32::Ran32(). - * - * The class chiefly supplies the method for advancing the state by - * Transition. - * - * @tparam RandomType the type of the results, either Random_u32 or - * Random_u64. - * - * Written by Charles Karney and licensed under the - * MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - template class RANDOMLIB_EXPORT SFMT19937 { - public: - /** - * The result RandomType - **********************************************************************/ - typedef RandomType engine_t; -#if defined(HAVE_SSE2) && HAVE_SSE2 - typedef __m128i internal_type; -#elif defined(HAVE_ALTIVEC) && HAVE_ALTIVEC - typedef vector unsigned internal_type; -#else - /** - * The internal numeric type for SFMT19337::Transition - **********************************************************************/ - typedef typename engine_t::type internal_type; -#endif - private: - /** - * The unsigned type of engine_t - **********************************************************************/ - typedef typename engine_t::type engine_type; - /** - * The width of the engine_t - **********************************************************************/ - static const unsigned width = engine_t::width; - enum { - /** - * The Mersenne prime is 2P − 1 - **********************************************************************/ - P = 19937, - /** - * The long lag for SFMT19937 in units of 128-bit words - **********************************************************************/ - N128 = (P + 128 - 1)/128, - /** - * How many width words per 128-bit word. - **********************************************************************/ - R = 128 / width, - /** - * The short lag for SFMT19937 in units of 128-bit words - **********************************************************************/ - M128 = 122, - /** - * The short lag for SFMT19937 - **********************************************************************/ - M = M128 * R - }; -#if (defined(HAVE_SSE2) && HAVE_SSE2) || (defined(HAVE_ALTIVEC) && HAVE_ALTIVEC) - static const Random_u32::type magic0 = 0x1fffefUL; - static const Random_u32::type magic1 = 0x1ecb7fUL; - static const Random_u32::type magic2 = 0x1affffUL; - static const Random_u32::type magic3 = 0x1ffff6UL; -#else - /** - * Magic matrix for SFMT19937. Only the low 21 (= 32 − 11) bits need - * to be set. (11 is the right shift applied to the words before masking. - **********************************************************************/ - static const engine_type - magic0 = width == 32 ? 0x1fffefULL : 0x1ecb7f001fffefULL; - static const engine_type - magic1 = width == 32 ? 0x1ecb7fULL : 0x1ffff6001affffULL; - static const engine_type - magic2 = width == 32 ? 0x1affffULL : 0ULL; - static const engine_type - magic3 = width == 32 ? 0x1ffff6ULL : 0ULL; -#endif - /** - * Mask for simulating u32 << 18 with 64-bit words - **********************************************************************/ - static const engine_type mask18 = engine_type(0xfffc0000fffc0000ULL); - /** - * Magic constants needed by "period certification" - **********************************************************************/ - static const engine_type PARITY0 = 1U; - static const engine_type PARITY1 = width == 32 ? 0U : 0x13c9e68400000000ULL; - static const engine_type PARITY2 = 0U; - static const engine_type PARITY3 = width == 32 ? 0x13c9e684UL : 0U; - /** - * Least significant bit of PARITY - **********************************************************************/ - static const unsigned PARITY_LSB = 0; - static const engine_type mask = engine_t::mask; - - public: - /** - * A version number "EnSM" or "EnSN" to ensure safety of Save/Load. This - * needs to be unique across RandomAlgorithms. - **********************************************************************/ - static const unsigned version = 0x456e534dUL + (engine_t::width/32 - 1); - enum { - /** - * The size of the state. The long lag for SFMT19937 - **********************************************************************/ - N = N128 * R - }; - /** - * Advance state by \e count batches. For speed all \e N words of state - * are advanced together. If \e count is negative, the state is stepped - * backwards. This is the meat of the SFMT19937 engine. - * - * @param[in] count how many batches to advance. - * @param[in,out] statev the internal state of the random number generator. - **********************************************************************/ - static void Transition(long long count, internal_type statev[]) - throw(); - - /** - * Manipulate a word of the state prior to output. This is a no-op for - * SFMT19937. - * - * @param[in] y a word of the state. - * @return the result. - **********************************************************************/ - static engine_type Generate(engine_type y) throw() { return y; } - - /** - * Convert an arbitrary state into a legal one. This consists a "period - * certification to ensure that the period of the generator is at least - * 2P − 1. - * - * @param[in,out] state the state of the generator. - **********************************************************************/ - static void NormalizeState(engine_type state[]) throw(); - - /** - * Check that the state is legal, throwing an exception if it is not. This - * merely verifies that the state is not all zero. At the same time, - * accumulate a checksum of the state. - * - * @param[in] state the state of the generator. - * @param[in,out] check an accumulated checksum. - **********************************************************************/ - static void CheckState(const engine_type state[], Random_u32::type& check); - - /** - * Return the name of the engine - * - * @return the name. - **********************************************************************/ - static std::string Name() throw() { - return "SFMT19937"; - } - }; - -} // namespace RandomLib - -#if defined(_MSC_VER) -# pragma warning (pop) -#endif - -#endif // RANDOMLIB_RANDOMALGORITHM_HPP diff --git a/include/RandomLib/RandomCanonical.hpp b/include/RandomLib/RandomCanonical.hpp deleted file mode 100644 index f9083010..00000000 --- a/include/RandomLib/RandomCanonical.hpp +++ /dev/null @@ -1,1301 +0,0 @@ -/** - * \file RandomCanonical.hpp - * \brief Header for RandomCanonical. - * - * Use the random bits from Generator to produce random integers of various - * sizes, random reals with various precisions, a random probability, etc. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMCANONICAL_HPP) -#define RANDOMLIB_RANDOMCANONICAL_HPP 1 - -#include -#include -#include - -#if defined(_MSC_VER) -// Squelch warnings about constant conditional expressions and casts truncating -// constants -# pragma warning (push) -# pragma warning (disable: 4127 4310) -#endif - -namespace RandomLib { - /** - * \brief Generate random integers, reals, and booleans. - * - * Use the random bits from Generator to produce random integers of various - * sizes, random reals with various precisions, a random probability, etc. - * RandomCanonical assumes that Generator produces random results as 32-bit - * quantities (of type uint32_t) via Generator::Ran32(), 64-bit quantities - * (of type uint64_t) via Generator::Ran64(), and in "natural" units of - * Generator::width bits (of type Generator::result_type) via - * Generator::Ran(). - * - * For the most part this class uses Ran() when needing \e width or fewer - * bits, otherwise it uses Ran64(). However, when \e width = 64, the - * resulting code is RandomCanonical::Unsigned(\e n) is inefficient because - * of the 64-bit arithmetic. For this reason RandomCanonical::Unsigned(\e n) - * uses Ran32() if less than 32 bits are required (even though this results - * in more numbers being produced by the Generator). - * - * This class has been tested with the 32-bit and 64-bit versions of MT19937 - * and SFMT19937. Other random number generators could be used provided that - * they provide a whole number of random bits so that Ran() is uniformly - * distributed in [0,2w). Probably some modifications - * would be needed if \e w is not 32 or 64. - * - * @tparam Generator the type of the underlying generator. - **********************************************************************/ - template - class RandomCanonical : public Generator { - public: - /** - * The type of operator()(). - **********************************************************************/ - typedef typename Generator::result_type result_type; - /** - * The type of elements of Seed(). - **********************************************************************/ - typedef typename RandomSeed::seed_type seed_type; - enum { - /** - * The number of random bits in result_type. - **********************************************************************/ - width = Generator::width - }; - - /** - * \name Constructors which set the seed - **********************************************************************/ - ///@{ - /** - * Initialize from a vector. - * - * @tparam IntType the integral type of the elements of the vector. - * @param[in] v the vector of elements. - **********************************************************************/ - template - explicit RandomCanonical(const std::vector& v) : Generator(v) {} - /** - * Initialize from a pair of iterator setting seed to [\e a, \e b) - * - * @tparam InputIterator the type of the iterator. - * @param[in] a the beginning iterator. - * @param[in] b the ending iterator. - **********************************************************************/ - template - RandomCanonical(InputIterator a, InputIterator b) : Generator(a, b) {} - /** - * Initialize with seed [\e n] - * - * @param[in] n the new seed to use. - **********************************************************************/ - explicit RandomCanonical(seed_type n); - /** - * Initialize with seed []. This can be followed by a call to Reseed() to - * select a unique seed. - **********************************************************************/ - RandomCanonical() : Generator() {} - /** - * Initialize from a string. See RandomCanonical::StringToVector - * - * @param[in] s the string to be decoded into a seed. - **********************************************************************/ - explicit RandomCanonical(const std::string& s) : Generator(s) {} - ///@} - - /** - * \name Member functions returning integers - **********************************************************************/ - ///@{ - /** - * Return a raw result in [0, 2w) from the - * underlying Generator. - * - * @return a w-bit random number. - **********************************************************************/ - result_type operator()() throw() { return Generator::Ran(); } - - /** - * A random integer in [0, \e n). This allows a RandomCanonical object to - * be passed to those standard template library routines that require - * random numbers. E.g., - * \code - RandomCanonical r; - int a[] = {0, 1, 2, 3, 4}; - std::random_shuffle(a, a+5, r); - \endcode - * - * @param[in] n the upper end of the interval. The upper end of the - * interval is open, so \e n is never returned. - * @return the random integer in [0, \e n). - **********************************************************************/ - result_type operator()(result_type n) throw() - { return Integer(n); } - - // Integer results (binary range) - - /** - * A random integer of type IntType in [0, 2b). - * - * @tparam IntType the integer type of the returned random numbers. - * @tparam bits how many random bits to return. - * @return the random result. - **********************************************************************/ - template IntType Integer() throw() { - // A random integer of type IntType in [0, 2^bits) - STATIC_ASSERT(std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "Integer(): bad integer type IntType"); - // Check that we have enough digits in Ran64 - STATIC_ASSERT(bits > 0 && bits <= std::numeric_limits::digits && - bits <= 64, "Integer(): invalid value for bits"); - // Prefer masking to shifting so that we don't have to worry about sign - // extension (a non-issue, because Ran/64 are unsigned?). - return bits <= width ? - IntType(Generator::Ran() & Generator::mask - >> (bits <= width ? width - bits : 0)) : - IntType(Generator::Ran64() & u64::mask >> (64 - bits)); - } - - /** - * A random integer in [0, 2b). - * - * @tparam bits how many random bits to return. - * @return the random result. - **********************************************************************/ - template - result_type Integer() throw() { return Integer(); } - - /** - * A random integer of type IntType in - * [std::numeric_limits::min(), std::numeric_limits::max()]. - * - * @tparam IntType the integer type of the returned random numbers. - * @return the random result. - **********************************************************************/ - template IntType Integer() throw(); - - /** - * A random result_type in [0, std::numeric_limits::max()]. - * - * @return the random result. - **********************************************************************/ - result_type Integer() throw() - { return Integer(); } - - // Integer results (finite range) - - /** - * A random integer of type IntType in [0, \e n). \e Excludes \e n. If \e - * n == 0, treat as std::numeric_limits::max() + 1. If \e n < 0, return 0. - * Compare RandomCanonical::Integer(0) which returns a result in - * [0,231) with RandomCanonical::Integer() which returns a - * result in [−231,231). - * - * @tparam IntType the integer type of the returned random numbers. - * @param[in] n the upper end of the semi-open interval. - * @return the random result in [0, \e n). - **********************************************************************/ - template IntType Integer(IntType n) throw(); - /** - * A random integer of type IntType in Closed interval [0, \e n]. \e - * Includes \e n. If \e n < 0, return 0. - * - * @tparam IntType the integer type of the returned random numbers. - * @param[in] n the upper end of the closed interval. - * @return the random result in [0, \e n]. - **********************************************************************/ - template IntType IntegerC(IntType n) throw(); - /** - * A random integer of type IntType in Closed interval [\e m, \e n]. \e - * Includes both endpoints. If \e n < \e m, return \e m. - * - * @tparam IntType the integer type of the returned random numbers. - * @param[in] m the lower end of the closed interval. - * @param[in] n the upper end of the closed interval. - * @return the random result in [\e m, \e n]. - **********************************************************************/ - template IntType IntegerC(IntType m, IntType n) throw(); - ///@} - - /** - * \name Member functions returning real fixed-point numbers - **********************************************************************/ - ///@{ - /** - * In the description of the functions FixedX returning \ref fixed - * "fixed-point" numbers, \e u is a random real number uniformly - * distributed in (0, 1), \e p is the precision, and \e h = - * 1/2p. Each of the functions come in three variants, - * e.g., - * - RandomCanonical::Fixed() --- return \ref fixed - * "fixed-point" real of type RealType, precision \e p; - * - RandomCanonical::Fixed() --- as above with \e p = - * std::numeric_limits::digits; - * - RandomCanonical::Fixed() --- as above with RealType = double. - * - * See the \ref reals "summary" for a comparison of the functions. - * - * Return \e i \e h with \e i in [0,2p) by rounding \e u - * down to the previous \ref fixed "fixed" real. Result is in default - * interval [0,1). - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType Fixed() throw() { - // RandomCanonical reals in [0, 1). Results are of the form i/2^prec for - // integer i in [0,2^prec). - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "Fixed(): bad real type RealType"); - STATIC_ASSERT(prec > 0 && prec <= std::numeric_limits::digits, - "Fixed(): invalid precision"); - RealType x = 0; // Accumulator - int s = 0; // How many bits so far - // Let n be the loop count. Typically prec = 24, n = 1 for float; prec = - // 53, n = 2 for double; prec = 64, n = 2 for long double. For Sun - // Sparc's, we have prec = 113, n = 4 for long double. For Windows, long - // double is the same as double (prec = 53). - do { - s += width; - x += RandomPower2::shiftf - (RealType(Generator::Ran() >> (s > prec ? s - prec : 0)), - -(s > prec ? prec : s)); - } while (s < prec); - return x; - } - /** - * See documentation for RandomCanonical::Fixed(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType Fixed() throw() - { return Fixed::digits>(); } - /** - * See documentation for RandomCanonical::Fixed(). - * - * @return the random double. - **********************************************************************/ - double Fixed() throw() { return Fixed(); } - - /** - * An alias for RandomCanonical::Fixed(). Returns a random - * number of type RealType in [0,1). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType Real() throw() - { return Fixed(); } - /** - * An alias for RandomCanonical::Fixed(). Returns a random double in - * [0,1). - * - * @return the random double. - **********************************************************************/ - double Real() throw() { return Fixed(); } - - /** - * Return \e i \e h with \e i in (0,2p] by rounding \e u - * up to the next \ref fixed "fixed" real. Result is in upper interval - * (0,1]. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FixedU() throw() - { return RealType(1) - Fixed(); } - /** - * See documentation for RandomCanonical::FixedU(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FixedU() throw() - { return FixedU::digits>(); } - /** - * See documentation for RandomCanonical::FixedU(). - * - * @return the random double. - **********************************************************************/ - double FixedU() throw() { return FixedU(); } - - /** - * Return \e i \e h with \e i in [0,2p] by rounding \e u - * to the nearest \ref fixed "fixed" real. Result is in nearest interval - * [0,1]. The probability of returning interior values is h while - * the probability of returning the endpoints is h/2. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FixedN() throw() { - const RealType x = Fixed(); - return x || Boolean() ? x : RealType(1); - } - /** - * See documentation for RandomCanonical::FixedN(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FixedN() throw() - { return FixedN::digits>(); } - /** - * See documentation for RandomCanonical::FixedN(). - * - * @return the random double. - **********************************************************************/ - double FixedN() throw() { return FixedN(); } - - /** - * Return \e i \e h with \e i in [−2p, - * 2p] by rounding 2\e u − 1 to the nearest \ref - * fixed "fixed" real. Result is in wide interval [−1,1]. The - * probability of returning interior values is h/2 while the - * probability of returning the endpoints is h/4. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FixedW() throw() { - // Random reals in [-1, 1]. Round random in [-1, 1] to nearest multiple - // of 1/2^prec. Results are of the form i/2^prec for integer i in - // [-2^prec,2^prec]. - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "FixedW(): bad real type RealType"); - STATIC_ASSERT(prec > 0 && prec <= std::numeric_limits::digits, - "FixedW(): invalid precision"); - RealType x = -RealType(1); // Accumulator - int s = -1; // How many bits so far - do { - s += width; - x += RandomPower2::shiftf - (RealType(Generator::Ran() >> (s > prec ? s - prec : 0)), - -(s > prec ? prec : s)); - } while (s < prec); - return (x + RealType(1) != RealType(0)) || Boolean() ? x : RealType(1); - } - /** - * See documentation for RandomCanonical::FixedW(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FixedW() throw() - { return FixedW::digits>(); } - /** - * See documentation for RandomCanonical::FixedW(). - * - * @return the random double. - **********************************************************************/ - double FixedW() throw() { return FixedW(); } - - /** - * Return (i+1/2)\e h with \e i in [2p−1, - * 2p−1) by rounding \e u − 1/2 to nearest - * offset \ref fixed "fixed" real. Result is in symmetric interval - * (−1/2,1/2). - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FixedS() throw() - { return Fixed() - - ( RealType(1) - RandomPower2::pow2(-prec) ) / 2; } - /** - * See documentation for RandomCanonical::FixedS(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FixedS() throw() - { return FixedS::digits>(); } - /** - * See documentation for RandomCanonical::FixedS(). - * - * @return the random double. - **********************************************************************/ - double FixedS() throw() { return FixedS(); } - - /** - * Return \e i \e h with \e i in (0,2p) by rounding (1 - * − \e h)\e u up to next \ref fixed "fixed" real. Result is in open - * interval (0,1). - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FixedO() throw() { - // A real of type RealType in (0, 1) with precision prec - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "FixedO(): bad real type RealType"); - STATIC_ASSERT(prec > 0 && prec <= std::numeric_limits::digits, - "FixedO(): invalid precision"); - RealType x; - // Loop executed 2^prec/(2^prec-1) times on average. - do - x = Fixed(); - while (x == 0); - return x; - } - /** - * See documentation for RandomCanonical::FixedO(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FixedO() throw() - { return FixedO::digits>(); } - /** - * See documentation for RandomCanonical::FixedO(). - * - * @return the random double. - **********************************************************************/ - double FixedO() throw() { return FixedO(); } - - /** - * Return \e i \e h with \e i in [0,2p] by rounding (1 + - * \e h)\e u down to previous \ref fixed "fixed" real. Result is in closed - * interval [0,1]. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FixedC() throw() { - // A real of type RealType in [0, 1] with precision prec - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "FixedC(): bad real type RealType"); - STATIC_ASSERT(prec > 0 && prec <= std::numeric_limits::digits, - "FixedC(): invalid precision"); - if (prec < width) { - // Sample an integer in [0, n) where n = 2^prec + 1. This uses the - // same logic as Unsigned(n - 1). However, unlike Unsigned, there - // doesn't seem to be much of a penalty for the 64-bit arithmetic here - // when result_type = unsigned long long. Presumably this is because - // the compiler can do some of the arithmetic. - const result_type - n = (result_type(1) << (prec < width ? prec : 0)) + 1, - // Computing this instead of 2^width/n suffices, because of the form - // of n. - r = Generator::mask / n, - m = r * n; - result_type u; - do - u = Generator::Ran(); - while (u >= m); - // u is rv in [0, r * n) - return RandomPower2::shiftf(RealType(u / r), -prec); - // Could also special case prec < 64, using Ran64(). However the - // general code below is faster. - } else { // prec >= width - // Synthesize a prec+1 bit random, Y, width bits at a time. If number - // is odd, return Fixed() (w prob 1/2); else if number - // is zero, return 1 (w prob 1/2^(prec+1)); else repeat. Normalizing - // probabilities on returned results we find that Fixed() is returned with prob 2^prec/(2^prec+1), and 1 is return - // with prob 1/(2^prec+1), as required. Loop executed twice on average - // and so consumes 2rvs more than rvs for Fixed(). As - // in FloatZ, do NOT try to save on calls to Ran() by using the - // leftover bits from Fixed. - while (true) { - // If prec + 1 < width then mask x with (1 << prec + 1) - 1 - const result_type x = Generator::Ran(); // Low width bits of Y - if (x & 1u) // Y odd? - return Fixed(); // Prob 1/2 on each loop iteration - if (x) - continue; // Y nonzero - int s = prec + 1 - width; // Bits left to check (s >= 0) - while (true) { - if (s <= 0) // We're done. Y = 0 - // Prob 1/2^(prec+1) on each loop iteration - return RealType(1); // We get here once every 60000 yrs (p = 64)! - // Check the next min(s, width) bits. - if (Generator::Ran() >> (s > width ? 0 : width - s)) - break; - s -= width; // Decrement s - } - } - } - } - /** - * See documentation for RandomCanonical::FixedC(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FixedC() throw() - { return FixedC::digits>(); } - /** - * See documentation for RandomCanonical::FixedC(). - * - * @return the random double. - **********************************************************************/ - double FixedC() throw() { return FixedC(); } - ///@} - - /** - * \name Member functions returning real floating-point numbers - **********************************************************************/ - ///@{ - - // The floating results produces results on a floating scale. Here the - // separation between possible results is smaller for smaller numbers. - - /** - * In the description of the functions FloatX returning \ref floating - * "floating-point" numbers, \e u is a random real number uniformly - * distributed in (0, 1), \e p is the precision, and \e e is the exponent - * range. Each of the functions come in three variants, e.g., - * - RandomCanonical::Float() --- return \ref floating - * "floating-point" real of type RealType, precision \e p, and exponent - * range \e e; - * - RandomCanonical::Float() --- as above with \e p = - * std::numeric_limits::digits and \e e = - * - std::numeric_limits::min_exponent; - * - RandomCanonical::Float() --- as above with RealType = double. - * - * See the \ref reals "summary" for a comparison of the functions. - * - * Return result is in default interval [0,1) by rounding \e u down - * to the previous \ref floating "floating" real. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @tparam erange the exponent range of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType Float() throw() - { return FloatZ(0, 0); } - /** - * See documentation for RandomCanonical::Float(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType Float() throw() { - return Float::digits, - -std::numeric_limits::min_exponent>(); - } - /** - * See documentation for RandomCanonical::Float(). - * - * @return the random double. - **********************************************************************/ - double Float() throw() { return Float(); } - - /** - * Return result is in upper interval (0,1] by round \e u up to the - * next \ref floating "floating" real. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @tparam erange the exponent range of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FloatU() throw() - { return FloatZ(0, 0); } - /** - * See documentation for RandomCanonical::FloatU(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FloatU() throw() { - return FloatU::digits, - -std::numeric_limits::min_exponent>(); - } - /** - * See documentation for RandomCanonical::FloatU(). - * - * @return the random double. - **********************************************************************/ - double FloatU() throw() { return FloatU(); } - - /** - * Return result is in nearest interval [0,1] by rounding \e u to - * the nearest \ref floating "floating" real. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @tparam erange the exponent range of the returned random numbers. - * @return the random result. - **********************************************************************/ - template RealType FloatN() - throw() { - // Use Float or FloatU each with prob 1/2, i.e., return Boolean() ? - // Float() : FloatU(). However, rather than use Boolean(), we pick the - // high bit off a Ran() and pass the rest of the number to FloatZ to use. - // This saves 1/2 a call to Ran(). - const result_type x = Generator::Ran(); - return x >> (width - 1) ? // equivalent to Boolean() - // Float() - FloatZ(width - 1, x) : - // FloatU() - FloatZ(width - 1, x); - } - /** - * See documentation for RandomCanonical::FloatN(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FloatN() throw() { - return FloatN::digits, - -std::numeric_limits::min_exponent>(); - } - /** - * See documentation for RandomCanonical::FloatN(). - * - * @return the random double. - **********************************************************************/ - double FloatN() throw() { return FloatN(); } - - /** - * Return result is in wide interval [−1,1], by rounding 2\e u - * − 1 to the nearest \ref floating "floating" real. - * - * @tparam RealType the real type of the returned random numbers. - * @tparam prec the precision of the returned random numbers. - * @tparam erange the exponent range of the returned random numbers. - * @return the random result. - **********************************************************************/ - template - RealType FloatW() throw() { - const result_type x = Generator::Ran(); - const int y = int(x >> (width - 2)); - return (1 - (y & 2)) * // Equiv to (Boolean() ? -1 : 1) * - ( y & 1 ? // equivalent to Boolean() - // Float() - FloatZ(width - 2, x) : - // FloatU() - FloatZ(width - 2, x) ); - } - /** - * See documentation for RandomCanonical::FloatW(). - * - * @tparam RealType the real type of the returned random numbers. - * @return the random result with the full precision of RealType. - **********************************************************************/ - template RealType FloatW() throw() { - return FloatW::digits, - -std::numeric_limits::min_exponent>(); - } - /** - * See documentation for RandomCanonical::FloatW(). - * - * @return the random double. - **********************************************************************/ - double FloatW() throw() { return FloatW(); } - ///@} - - /** - * \name Member functions returning booleans - **********************************************************************/ - ///@{ - /** - * A coin toss. Equivalent to RandomCanonical::Integer(). - * - * @return true with probability 1/2. - **********************************************************************/ - bool Boolean() throw() { return Generator::Ran() & 1u; } - - /** - * The Bernoulli distribution, true with probability \e p. False if \e p - * ≤ 0; true if \e p ≥ 1. Equivalent to RandomCanonical::Float() < - * \e p, but typically faster. - * - * @tparam NumericType the type (integer or real) of the argument. - * @param[in] p the probability. - * @return true with probability \e p. - **********************************************************************/ - template bool Prob(NumericType p) throw(); - - /** - * True with probability m/n. False if \e m ≤ 0 or \e n < - * 0; true if \e m ≥ \e n. With real types, Prob(\e x, \e y) is exact - * but slower than Prob(x/y). - * - * @tparam NumericType the type (integer or real) of the argument. - * @param[in] m the numerator of the probability. - * @param[in] n the denominator of the probability. - * @return true with probability m/n. - **********************************************************************/ - template - bool Prob(NumericType m, NumericType n) throw(); - ///@} - - // Bits - - /** - * \name Functions returning bitsets - * These return random bits in a std::bitset. - **********************************************************************/ - ///@{ - - /** - * Return \e nbits random bits - * - * @tparam nbits the number of bits in the bitset. - * @return the random bitset. - **********************************************************************/ - template std::bitset Bits() throw(); - - ///@} - - /** - * A "global" random number generator (not thread-safe!), initialized with - * a fixed seed []. - **********************************************************************/ - static RANDOMLIB_EXPORT RandomCanonical Global; - - private: - typedef RandomSeed::u32 u32; - typedef RandomSeed::u64 u64; - /** - * A helper for Integer(\e n). A random unsigned integer in [0, \e n]. If - * \e n ≥ 232, this \e must be invoked with \e onep = false. - * Otherwise, it \e should be invoked with \e onep = true. - **********************************************************************/ - template - typename UIntT::type Unsigned(typename UIntT::type n) throw(); - - /** - * A helper for Float and FloatU. Produces \e up ? FloatU() : Float(). On - * entry the low \e b bits of \e m are usable random bits. - **********************************************************************/ - template - RealType FloatZ(int b, result_type m) throw(); - - /** - * The one-argument version of Prob for real types - **********************************************************************/ - template bool ProbF(RealType z) throw(); - /** - * The two-argument version of Prob for real types - **********************************************************************/ - template bool ProbF(RealType x, RealType y) throw(); - }; - - template - RandomCanonical::RandomCanonical(seed_type n) - : Generator(n) { - // Compile-time checks on real types -#if HAVE_LONG_DOUBLE - STATIC_ASSERT(std::numeric_limits::radix == 2 && - std::numeric_limits::radix == 2 && - std::numeric_limits::radix == 2, - "RandomCanonical: illegal floating type"); - STATIC_ASSERT(0 <= std::numeric_limits::digits && - std::numeric_limits::digits <= - std::numeric_limits::digits && - std::numeric_limits::digits <= - std::numeric_limits::digits, - "RandomCanonical: inconsistent floating precision"); -#else - STATIC_ASSERT(std::numeric_limits::radix == 2 && - std::numeric_limits::radix == 2, - "RandomCanonical: illegal floating type"); - STATIC_ASSERT(0 <= std::numeric_limits::digits && - std::numeric_limits::digits <= - std::numeric_limits::digits, - "RandomCanonical: inconsistent floating precision"); -#endif -#if HAVE_LONG_DOUBLE -#endif -#if RANDOMLIB_POWERTABLE - // checks on power2 -#if HAVE_LONG_DOUBLE - STATIC_ASSERT(std::numeric_limits::digits == - RANDOMLIB_LONGDOUBLEPREC, - "RandomPower2: RANDOMLIB_LONGDOUBLEPREC incorrect"); -#else - STATIC_ASSERT(std::numeric_limits::digits == - RANDOMLIB_LONGDOUBLEPREC, - "RandomPower2: RANDOMLIB_LONGDOUBLEPREC incorrect"); -#endif - // Make sure table hasn't underflowed - STATIC_ASSERT(RandomPower2::minpow >= - std::numeric_limits::min_exponent - - (RANDOMLIB_HASDENORM(float) ? - std::numeric_limits::digits : 1), - "RandomPower2 table underflow"); - STATIC_ASSERT(RandomPower2::maxpow >= RandomPower2::minpow + 1, - "RandomPower2 table empty"); - // Needed by RandomCanonical::Fixed() -#if HAVE_LONG_DOUBLE - STATIC_ASSERT(RandomPower2::minpow <= - -std::numeric_limits::digits, - "RandomPower2 minpow not small enough for long double"); -#else - STATIC_ASSERT(RandomPower2::minpow <= - -std::numeric_limits::digits, - "RandomPower2 minpow not small enough for double"); -#endif - // Needed by ProbF - STATIC_ASSERT(RandomPower2::maxpow - width >= 0, - "RandomPower2 maxpow not large enough for ProbF"); -#endif - // Needed for RandomCanonical::Bits() - STATIC_ASSERT(2 * std::numeric_limits::digits - width >= 0, - "Bits(): unsigned long too small"); - } - - template template - inline IntType RandomCanonical::Integer() throw() { - // A random integer of type IntType in [min(IntType), max(IntType)]. - STATIC_ASSERT(std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "Integer: bad integer type IntType"); - const int d = std::numeric_limits::digits + - std::numeric_limits::is_signed; // Include the sign bit - // Check that we have enough digits in Ran64 - STATIC_ASSERT(d > 0 && d <= 64, "Integer: bad bit-size"); - if (d <= width) - return IntType(Generator::Ran()); - else // d <= 64 - return IntType(Generator::Ran64()); - } - - template template - inline typename UIntT::type - RandomCanonical::Unsigned(typename UIntT::type n) throw() { - // A random unsigned in [0, n]. In n fits in 32-bits, call with UIntType = - // u32 and onep = true else call with UIntType = u64 and onep = false. - // There are a few cases (e.g., n = 0x80000000) where on a 64-bit machine - // with a 64-bit Generator it would be quicker to call this with UIntType = - // result_type and invoke Ran(). However this speed advantage disappears - // if the argument isn't a compile time constant. - // - // Special case n == 0 is handled by the callers of Unsigned. The - // following is to guard against a division by 0 in the return statement - // (but it shouldn't happen). - n = n ? n : 1U; // n >= 1 - // n1 = n + 1, but replace overflowed value by 1. Overflow occurs, e.g., - // when n = u32::mask and then we have r1 = 0, m = u32::mask. - const typename UIntT::type n1 = ~n ? n + 1U : 1U; - // "Ratio method". Find m = r * n1 - 1, s.t., 0 < (q - n1) < m <= q, where - // q = max(UIntType), and sample in u in [0, m] and return u / r. If onep - // then we use Ran32() else Rand64(). - const typename UIntT::type - // r = floor((q + 1)/n1), r1 = r - 1, avoiding overflow. Actually - // overflow can occur if std::numeric_limits::digits == 64, because - // then we can have onep && n > U32_MASK. This is however ruled out by - // the callers to Unsigned. (If Unsigned is called in this way, the - // results are bogus, but there is no error condition.) - r1 = ((UIntT::width == 32 ? typename UIntT::type(u32::mask) : - typename UIntT::type(u64::mask)) - n) / n1, - m = r1 * n1 + n; // m = r * n1 - 1, avoiding overflow - // Here r1 in [0, (q-1)/2], m in [(q+1)/2, q] - typename UIntT::type u; // Find a random number in [0, m] - do - // For small n1, this is executed once (since m is nearly q). In the - // worst case the loop is executed slightly less than twice on average. - u = UIntT::width == 32 ? typename UIntT::type(Generator::Ran32()) : - typename UIntT::type(Generator::Ran64()); - while (u > m); - // Now u is in [0, m] = [0, r * n1), so u / r is in [0, n1) = [0, n]. An - // alternative unbiased method would be u % n1; but / appears to be faster. - return u / (r1 + 1U); - } - - template template - inline IntType RandomCanonical::Integer(IntType n) throw() { - // A random integer of type IntType in [0, n). If n == 0, treat as - // max(IntType) + 1. If n < 0, treat as 1 and return 0. - // N.B. Integer(0) is equivalent to Integer() for - // unsigned types. For signed types, the former returns a non-negative - // result and the latter returns a result in the full range. - STATIC_ASSERT(std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "Integer(n): bad integer type IntType"); - const int d = std::numeric_limits::digits; - // Check that we have enough digits in Ran64 - STATIC_ASSERT(d > 0 && d <= 64, "Integer(n): bad bit-size"); - return n > IntType(1) ? - (d <= 32 || n - 1 <= IntType(u32::mask) ? - IntType(Unsigned(u32::type(n - 1))) : - IntType(Unsigned(u64::type(n - 1)))) : - ( n ? IntType(0) : // n == 1 || n < 0 - Integer()); // n == 0 - } - - template template - inline IntType RandomCanonical::IntegerC(IntType n) throw() { - // A random integer of type IntType in [0, n] - STATIC_ASSERT(std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "IntegerC(n): bad integer type IntType"); - const int d = std::numeric_limits::digits; - // Check that we have enough digits in Ran64 - STATIC_ASSERT(d > 0 && d <= 64, "IntegerC(n): bad bit-size"); - return n > IntType(0) ? - (d <= 32 || n <= IntType(u32::mask) ? - IntType(Unsigned(u32::type(n))) : - IntType(Unsigned(u64::type(n)))) - : IntType(0); // n <= 0 - } - - template template - inline IntType RandomCanonical::IntegerC(IntType m, IntType n) - throw() { - // A random integer of type IntType in [m, n] - STATIC_ASSERT(std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "IntegerC(m,n): bad integer type IntType"); - const int d = std::numeric_limits::digits + - std::numeric_limits::is_signed; // Include sign bit - // Check that we have enough digits in Ran64 - STATIC_ASSERT(d > 0 && d <= 64, "IntegerC(m,n): bad bit-size"); - // The unsigned subtraction, n - m, avoids the underflow that is possible - // in the signed operation. - return m + (n <= m ? 0 : - d <= 32 ? - IntType(IntegerC(u32::type(n) - u32::type(m))) : - IntType(IntegerC(u64::type(n) - u64::type(m)))); - } - - template - template inline - RealType RandomCanonical::FloatZ(int b, result_type m) throw() { - // Produce up ? FloatU() : Float(). On entry the low b bits of m are - // usable random bits. - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "FloatZ: bad real type RealType"); - STATIC_ASSERT(prec > 0 && prec <= std::numeric_limits::digits, - "FloatZ: invalid precision"); - STATIC_ASSERT(erange >= 0, "FloatZ: invalid exponent range"); - // With subnormals: condition that smallest number is representable - STATIC_ASSERT(!RANDOMLIB_HASDENORM(RealType) || - // Need 1/2^(erange+prec) > 0 - prec + erange <= std::numeric_limits::digits - - std::numeric_limits::min_exponent, - "FloatZ: smallest number cannot be represented"); - // Without subnormals :condition for no underflow in while loop - STATIC_ASSERT(RANDOMLIB_HASDENORM(RealType) || - // Need 1/2^(erange+1) > 0 - erange <= - std::numeric_limits::min_exponent, - "FloatZ: underflow possible"); - - // Simpler (but slower) version of FloatZ. However this method cannot - // handle the full range of exponents and, in addition, is slower on - // average. - // template - // RealType FloatZ() { - // RealType x = Fixed(); - // int s; // Determine exponent (-erange <= s <= 0) - // frexp(x, &s); // Prob(s) = 2^(s-1) - // // Scale number in [1,2) by 2^(s-1). If x == 0 scale number in [0,1). - // return ((up ? FixedU() : - // Fixed()) + (x ? 1 : 0)) * - // RandomPower2::pow2(s - 1); - // } - // - // Use {a, b} to denote the inteval: up ? (a, b] : [a, b) - // - // The code produces the number as - // - // Interval count prob = spacing - // {1,2} / 2 2^(prec-1) 1/2^prec - // {1,2} / 2^s 2^(prec-1) 1/2^(prec+s-1) for s = 2..erange+1 - // {0,1} / 2^(erange+1) 2^(prec-1) 1/2^(prec+erange) - - // Generate prec bits in {0, 1} - RealType x = up ? FixedU() : Fixed(); - // Use whole interval if erange == 0 and handle the interval {1/2, 1} - if (erange == 0 || (up ? x > RealType(0.5) : x >= RealType(0.5))) - return x; - x += RealType(0.5); // Shift remaining portion to {1/2, 1} - if (b == 0) { - m = Generator::Ran(); // Random bits - b = width; // Bits available in m - } - int sm = erange; // sm = erange - s + 2 - // Here x in {1, 2} / 2, prob 1/2 - do { // s = 2 thru erange+1, sm = erange thru 1 - x /= 2; - if (m & 1u) - return x; // x in {1, 2} / 2^s, prob 1/2^s - if (--b) - m >>= 1; - else { - m = Generator::Ran(); - b = width; - } - } while (--sm); - // x in {1, 2} / 2^(erange+1), prob 1/2^(erange+1). Don't worry about the - // possible overhead of the calls to pow here. We rarely get here. - if (RANDOMLIB_HASDENORM(RealType) || // subnormals allowed - // No subnormals but smallest number still representable - prec + erange <= -std::numeric_limits::min_exponent + 1 || - // Possibility of underflow, so have to test on x. Here, we have -prec - // + 1 < erange + min_exp <= 0 so pow2 can be used - x >= (RealType(1) + - RandomPower2::pow2 - (erange + std::numeric_limits::min_exponent)) * - (erange + 1 > -RandomPower2::minpow ? - std::pow(RealType(2), - erange - 1) : - RandomPower2::pow2(- erange - 1))) - // shift x to {0, 1} / 2^(erange+1) - // Use product of pow's since max(erange + 1) = - // std::numeric_limits::digits - - // std::numeric_limits::min_exponent and pow may underflow - return x - - (erange + 1 > -RandomPower2::minpow ? - std::pow(RealType(2), -(erange + 1)/2) * - std::pow(RealType(2), -(erange + 1) + (erange + 1)/2) : - RandomPower2::pow2(- erange - 1)); - else - return up ? // Underflow to up ? min() : 0 - // pow is OK here. - std::pow(RealType(2), std::numeric_limits::min_exponent - 1) - : RealType(0); - } - - /// \cond SKIP - // True with probability n. Since n is an integer this is equivalent to n > - // 0. - template template - inline bool RandomCanonical::Prob(IntType n) throw() { - STATIC_ASSERT(std::numeric_limits::is_integer, - "Prob(n): invalid integer type IntType"); - return n > 0; - } - /// \endcond - - // True with probability p. true if p >= 1, false if p <= 0 or isnan(p). - template template - inline bool RandomCanonical::ProbF(RealType p) throw() { - // Simulate Float() < p. The definition involves < (instead of - // <=) because Float() is in [0,1) so it is "biased downwards". - // Instead of calling Float(), we generate only as many bits as - // necessary to determine the result. This makes the routine considerably - // faster than Float() < x even for type float. Compared with - // the inexact Fixed() < p, this is about 20% slower with floats - // and 20% faster with doubles and long doubles. - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "ProbF(p): invalid real type RealType"); - // Generate Real() c bits at a time where c is chosen so that cast doesn't - // loose any bits and so that it uses up just one rv. - const int c = std::numeric_limits::digits > width ? - width : std::numeric_limits::digits; - STATIC_ASSERT(c > 0, "ProbF(p): Illegal chunk size"); - const RealType mult = RandomPower2::pow2(c); - // A recursive definition: - // - // return p > RealType(0) && - // (p >= RealType(1) || - // ProbF(mult * p - RealType(Integer()))); - // - // Pre-loop tests needed to avoid overflow - if (!(p > RealType(0))) // Ensure false if isnan(p) - return false; - else if (p >= RealType(1)) - return true; - do { // Loop executed slightly more than once. - // Here p is in (0,1). Write Fixed() = (X + y)/mult where X is an - // integer in [0, mult) and y is a real in [0,1). Then Fixed() < p - // becomes p' > y where p' = p * mult - X. - p *= mult; // Form p'. Multiplication is exact - p -= RealType(Integer()); // Also exact - if (p <= RealType(0)) - return false; // If p' <= 0 the result is definitely false. - // Exit if p' >= 1; the result is definitely true. Otherwise p' is in - // (0,1) and the result is true with probability p'. - } while (p < RealType(1)); - return true; - } - - /// \cond SKIP - // True with probability m/n (ratio of integers) - template template - inline bool RandomCanonical::Prob(IntType m, IntType n) throw() { - STATIC_ASSERT(std::numeric_limits::is_integer, - "Prob(m,n): invalid integer type IntType"); - // Test n >= 0 without triggering compiler warning when n = unsigned - return m > 0 && (n > 0 || n == 0) && (m >= n || Integer(n) < m); - } - /// \endcond - - // True with probability x/y (ratio of reals) - template template - inline bool RandomCanonical::ProbF(RealType x, RealType y) - throw() { - STATIC_ASSERT(!std::numeric_limits::is_integer && - std::numeric_limits::radix == 2, - "ProbF(x,y): invalid real type RealType"); - if (!(x > RealType(0) && y >= RealType(0))) // Do the trivial cases - return false; // Also if either x or y is a nan - else if (x >= y) - return true; - // Now 0 < x < y - int ex, ey; // Extract exponents - x = std::frexp(x, &ex); - y = std::frexp(y, &ey); - // Now 0.5 <= x,y < 1 - if (x > y) { - x *= RealType(0.5); - ++ex; - } - int s = ey - ex; - // Now 0.25 < x < y < 1, s >= 0, 0.5 < x/y <= 1 - // Return true with prob 2^-s * x/y - while (s > 0) { // With prob 1 - 2^-s return false - // Check the next min(s, width) bits. - if (Generator::Ran() >> (s > width ? 0 : width - s)) - return false; - s -= width; - } - // Here with prob 2^-s - const int c = std::numeric_limits::digits > width ? - width : std::numeric_limits::digits; - STATIC_ASSERT(c > 0, "ProbF(x,y): invalid chunk size"); - const RealType mult = RandomPower2::pow2(c); - // Generate infinite precision z = Real(). - // As soon as we know z > y, start again - // As soon as we know z < x, return true - // As soon as we know x < z < y, return false - while (true) { // Loop executed 1/y on average - RealType xa = x, ya = y; - while (true) { // Loop executed slightly more than once - // xa <= ya, ya > 0, xa < 1. - // Here (xa,ya) are in (0,1). Write z = (Z + z')/mult where Z is an - // integer in [0, mult) and z' is a real in [0,1). Then z < x becomes - // z' < x' where x' = x * mult - Z. - const RealType d = RealType(Integer()); - if (ya < RealType(1)) { - ya *= mult; // Form ya' - ya -= d; - if (ya <= RealType(0)) - break; // z > y, start again - } - if (xa > RealType(0)) { - xa *= mult; // Form xa' - xa -= d; - if (xa >= RealType(1)) - return true; // z < x - } - if (xa <= RealType(0) && ya >= RealType(1)) - return false; // x < z < y - } - } - } - - template template - inline std::bitset RandomCanonical::Bits() throw() { - // Return nbits random bits - STATIC_ASSERT(nbits >= 0, "Bits(): invalid nbits"); - const int ulbits = std::numeric_limits::digits; - STATIC_ASSERT(2 * ulbits >= width, - "Bits(): integer constructor type too narrow"); - std::bitset b; - int m = nbits; - - while (m > 0) { - result_type x = Generator::Ran(); - if (m < nbits) - b <<= (width > ulbits ? width - ulbits : width); - if (width > ulbits && // x doesn't fit into a bitset_uint_t - // But on the first time through the loop the most significant bits - // may not be needed. - (nbits > ((nbits-1)/width) * width + ulbits || m < nbits)) { - // Handle most significant width - ulbits bits. - b |= (bitset_uint_t)(x >> (width > ulbits ? ulbits : 0)); - b <<= ulbits; - } - // Bitsets can be constructed from a bitset_uint_t. - b |= (bitset_uint_t)(x); - m -= width; - } - return b; - } - /// \cond SKIP - - // The specialization of Integer is required because bool(int) in the - // template definition will test for non-zeroness instead of returning the - // low bit. -#if HAVE_LONG_DOUBLE -#define RANDOMCANONICAL_SPECIALIZE(RandomType) \ - template<> template<> \ - inline bool RandomType::Integer() \ - throw() { return Boolean(); } \ - RANDOMCANONICAL_SPECIALIZE_PROB(RandomType, float) \ - RANDOMCANONICAL_SPECIALIZE_PROB(RandomType, double) \ - RANDOMCANONICAL_SPECIALIZE_PROB(RandomType, long double) -#else -#define RANDOMCANONICAL_SPECIALIZE(RandomType) \ - template<> template<> \ - inline bool RandomType::Integer() \ - throw() { return Boolean(); } \ - RANDOMCANONICAL_SPECIALIZE_PROB(RandomType, float) \ - RANDOMCANONICAL_SPECIALIZE_PROB(RandomType, double) -#endif - - // Connect Prob(p) with ProbF(p) for all real types - // Connect Prob(x, y) with ProbF(x, y) for all real types -#define RANDOMCANONICAL_SPECIALIZE_PROB(RandomType, RealType) \ - template<> template<> \ - inline bool RandomType::Prob(RealType p) \ - throw() { return ProbF(p); } \ - template<> template<> \ - inline bool RandomType::Prob(RealType x, RealType y) \ - throw() { return ProbF(x, y); } - - RANDOMCANONICAL_SPECIALIZE(RandomCanonical) - RANDOMCANONICAL_SPECIALIZE(RandomCanonical) - RANDOMCANONICAL_SPECIALIZE(RandomCanonical) - RANDOMCANONICAL_SPECIALIZE(RandomCanonical) - -#undef RANDOMCANONICAL_SPECIALIZE -#undef RANDOMCANONICAL_SPECIALIZE_PROB - - /// \endcond - - /** - * Hook XRandomNN to XRandomGeneratorNN - **********************************************************************/ - typedef RandomCanonical MRandom32; - typedef RandomCanonical MRandom64; - typedef RandomCanonical SRandom32; - typedef RandomCanonical SRandom64; - -} // namespace RandomLib - -namespace std { - - /** - * Swap two RandomCanonicals. This is about 3x faster than the default swap. - **********************************************************************/ - template - void swap(RandomLib::RandomCanonical& r, - RandomLib::RandomCanonical& s) throw() { - r.swap(s); - } - -} // namespace srd - -#if defined(_MSC_VER) -# pragma warning (pop) -#endif - -#endif // RANDOMLIB_RANDOMCANONICAL_HPP diff --git a/include/RandomLib/RandomEngine.hpp b/include/RandomLib/RandomEngine.hpp deleted file mode 100644 index a6c2da13..00000000 --- a/include/RandomLib/RandomEngine.hpp +++ /dev/null @@ -1,640 +0,0 @@ -/** - * \file RandomEngine.hpp - * \brief Header for RandomEngine. - * - * Copyright (c) Charles Karney (2006-2012) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMENGINE_HPP) -#define RANDOMLIB_RANDOMENGINE_HPP 1 - -#include -#include -#include -#include -#include -#include -#if defined(HAVE_SSE2) && HAVE_SSE2 && defined(_MSC_VER) && !defined(_WIN64) -#include -#endif - -#if !defined(RANDOMLIB_BUILDING_LIBRARY) && \ - defined(HAVE_BOOST_SERIALIZATION) && HAVE_BOOST_SERIALIZATION -#include -#include -#include -#endif - -namespace RandomLib { - /** - * \brief Uniform random number generator. - * - * This implements a generic random number generator. Such a generator - * requires two data holders RandomSeed, to hold the seed, and RandomEngine, - * to hold the state. In addition we need two piece of machinery, a "Mixer" - * to convert the seed into an initial state and an "Algorithm" to advance the - * state. - * - * @tparam Algorithm the random number algorithm. - * @tparam Mixer the way seeds are turned into state. - * - * RandomSeed is responsible for setting and reporting the seed. - * - * Mixer has no state and implements only static methods. It needs to have - * the following public interface - * - typedef mixer_t: a RandomType giving the output type - * - unsigned version: an identifying version number - * - static std::string Name(): an identifying name for the mixer - * - static method SeedToState: converts a seed into n words of state. - * - * Algorithm has no state and implements only static methods. It needs to - * have the following public interface - * - typedef engine_t: a RandomType giving the output type - * - typedef internal_type: a integer type used by Transition. This is - * usually the same as engine_t::type. However it allows the use of - * vector instructions on some platforms. We require that engine_t::type - * and internal_type line up properly in a union so that there is no need - * to convert the data explicitly between internal_type and - * engine_t::type. - * - unsigned version: an identifying version number - * - static std::string Name(): an identifying name for the mixer - * - enum N: the size of the state in units of engine_t. - * - static method Transition: steps the generator forwards or backwards. - * - static method Generate: tempers the state immediately prior to output - * - static method NormalizeState: force the initial state (the result of - * the Mixer) into a legal state. - * - static method CheckState accumulates the checksum for the state into - * check. In addition it throws an exception if the state is bad. - * - * RandomEngine is the glue that holds everything together. It repacks - * the mixer_t data from Mixer into engine_t if necessary. It deals with - * delivering individual random results, stepping the state forwards and - * backwards, leapfrogging the generator, I/O of the generator, etc. - * - * Written by Charles Karney and licensed under the - * MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - template - class RANDOMLIB_EXPORT RandomEngine : public RandomSeed { - private: - /** - * The result RandomType (carried over from the \e Algorithm). - **********************************************************************/ - typedef typename Algorithm::engine_t result_t; - /** - * The RandomType used by the \e Mixer. - **********************************************************************/ - typedef typename Mixer::mixer_t mixer_t; - /** - * The internal_type used by the Algorithm::Transition(). - **********************************************************************/ - typedef typename Algorithm::internal_type engine_type; - public: - /** - * The number of random bits produced by Ran(). - **********************************************************************/ - enum { - width = result_t::width - }; - - /** - * A type large enough to hold \e width bits. This is used for the - * internal state of the generator and the result returned by Ran(). - **********************************************************************/ - typedef typename result_t::type result_type; - - /** - * The minimum result returned by Ran() = 0. - **********************************************************************/ - static const result_type min = result_t::min; - - /** - * The maximum result returned by Ran() = 2w − 1. - **********************************************************************/ - static const result_type max = result_t::max; - - protected: - - /** - * The mask for the result_t. - **********************************************************************/ - static const result_type mask = result_t::mask; - - private: - /** - * A version number "RandLib0" to ensure safety of Save/Load. The first 7 - * bytes can be regarded as a "signature" and the 8th byte a version - * number. - **********************************************************************/ - static const u64::type version = 0x52616e644c696230ULL; // 'RandLib0' - /** - * Marker for uninitialized object - **********************************************************************/ - static const unsigned UNINIT = 0xffffffffU; - enum { - /** - * The size of the state in units of result_type - **********************************************************************/ - N = Algorithm::N, - /** - * The size of the state in units of mixer_t::type - **********************************************************************/ - NU = (N * width + mixer_t::width - 1) / mixer_t::width, - /** - * The size of the state in units of engine_type. - **********************************************************************/ - NV = N * sizeof(result_type) / sizeof(engine_type) - }; - - /** - * \brief Union for the state. - * - * A union to hold the state in the result_type, mixer_t::type, and - * engine_type representations. - **********************************************************************/ - union { - /** - * the result_type representation returned by Ran() - **********************************************************************/ - result_type _state[N]; - /** - * the mixer_t::type representation returned by Mixer::SeedToState. - **********************************************************************/ - typename mixer_t::type _stateu[NU]; - /** - * the engine_type representation returned by Algorithm::Transition. - **********************************************************************/ - engine_type _statev[NV]; - }; - - /** - * The index for the next random value - **********************************************************************/ - unsigned _ptr; - /** - * How many times has Transition() been called - **********************************************************************/ - long long _rounds; - /** - * Stride for leapfrogging - **********************************************************************/ - unsigned _stride; - - public: - - /** - * \name Constructors - **********************************************************************/ - ///@{ - /** - * Initialize from a vector. Only the low \e 32 bits of each element are - * used. - * - * @tparam IntType the integral type of the elements of the vector. - * @param[in] v the vector of elements. - **********************************************************************/ - template - explicit RandomEngine(const std::vector& v) { Reseed(v); } - /** - * Initialize from a pair of iterators setting seed to [\e a, \e b). The - * iterator must produce results which can be converted into seed_type. - * Only the low \e 32 bits of each element are used. - * - * @tparam InputIterator the type of the iterator. - * @param[in] a the beginning iterator. - * @param[in] b the ending iterator. - **********************************************************************/ - template - RandomEngine(InputIterator a, InputIterator b) { Reseed(a, b); } - /** - * Initialize with seed [\e n]. Only the low \e width bits of \e n are - * used. - * - * @param[in] n the new seed to use. - **********************************************************************/ - explicit RandomEngine(seed_type n) { Reseed(n); } - /** - * Initialize with seed []. This can be followed by a call to Reseed() to - * select a unique seed. - **********************************************************************/ - RandomEngine() { unsigned long s[1]; Reseed(s, s); } - /** - * Initialize from a string. See Reseed(const std::string& s) - * - * @param[in] s the string to be decoded into a seed. - **********************************************************************/ - explicit RandomEngine(const std::string& s) { Reseed(s); } - - ///@} - - /** - * \name Functions for returning random data - **********************************************************************/ - ///@{ - /** - * Return \e width bits of randomness. This is the natural unit of random - * data produced random number generator. - * - * @return the next random number of width \e width. - **********************************************************************/ - result_type Ran() throw() { - if (_ptr >= N) - Next(); - result_type y = _state[_ptr]; - _ptr += _stride; - - return Algorithm::Generate(y); - } - - /** - * Return 32 bits of randomness. - * - * @return a 32-bit random number. - **********************************************************************/ - u32::type Ran32() throw() { - // return width > 32 ? u32::cast(Ran()) : Ran(); - return u32::cast(Ran()); - } - - /** - * Return 64 bits of randomness. - * - * @return a 64-bit random number. - **********************************************************************/ - u64::type Ran64() throw() { - const u64::type x = Ran(); - return width > 32 ? x : u64::cast(Ran()) << (64 - width) | x; - } - - /** - * Return \e width bits of randomness. Result is in [0, - * 2w). (This just calls Ran().) - * - * @return the next random number of width \e width. - **********************************************************************/ - result_type operator()() throw() { return Ran(); } - ///@} - -#if defined(HAVE_SSE2) && HAVE_SSE2 && defined(_MSC_VER) && !defined(_WIN64) - /** - * new operator with alignment (needed for Visual Studio) - **********************************************************************/ - void* operator new(size_t n) { - void* p = _aligned_malloc(n, __alignof(RandomEngine)); - if (p == 0) throw std::bad_alloc(); - return p; - } - - /** - * delete operator with alignment (needed for Visual Studio) - **********************************************************************/ - void operator delete(void* p) { _aligned_free(p); } - - /** - * new[] operator with alignment (needed for Visual Studio) - **********************************************************************/ - void* operator new[](size_t n) { - void* p = _aligned_malloc(n, __alignof(RandomEngine)); - if (p == 0) throw std::bad_alloc(); - return p; - } - - /** - * delete[] operator with alignment (needed for Visual Studio) - **********************************************************************/ - void operator delete[](void* p) { _aligned_free(p); } -#endif - - /** - * \name Comparing Random objects - **********************************************************************/ - ///@{ - /** - * Test equality of two Random objects. This test that the seeds match and - * that they have produced the same number of random numbers. - * - * @param[in] r the RandomEngine object to compare. - * @return true if the RandomEngine objects produce the same results. - **********************************************************************/ - bool operator==(const RandomEngine& r) const throw() - // Ensure that the two Random objects behave the same way. Note however - // that the internal states may still be different, e.g., the following all - // result in Random objects which are == (with Count() == 0) but which all - // have different internal states: - // - // Random r(0); _ptr == UNINIT - // r.StepCount( 1); r.StepCount(-1); _ptr == 0, _rounds == 0 - // r.StepCount(-1); r.StepCount( 1); _ptr == N, _rounds == -1 - { return Count() == r.Count() && _seed == r._seed && - _stride == r._stride; } - /** - * Test inequality of two Random objects. See Random::operator== - * - * @param[in] r the RandomEngine object to compare. - * @return true if the RandomEngine objects produce different results. - **********************************************************************/ - bool operator!=(const RandomEngine& r) const throw() - { return !operator==(r); } - ///@} - - /** - * \name Interchanging Random objects - **********************************************************************/ - ///@{ - /** - * Swap with another Random object. - * - * @param[in,out] t the RandomEngine object to swap with. - **********************************************************************/ - void swap(RandomEngine& t) throw() { - _seed.swap(t._seed); - std::swap(_ptr, t._ptr); - std::swap(_stride, t._stride); - std::swap(_rounds, t._rounds); - std::swap_ranges(_state, _state + N, t._state); - } - ///@} - - /** - * \name Writing to and reading from a stream - **********************************************************************/ - ///@{ - /** - * Save the state of the Random object to an output stream. Format is a - * sequence of unsigned 32-bit integers written either in decimal (\e bin - * false, text format) or in network order with most significant byte first - * (\e bin true, binary format). Data consists of: - * - * - RandomLib magic string + version (2 words) - * - Algorithm version (1 word) - * - Mixer version (1 word) - * - _seed.size() (1 word) - * - _seed data (_seed.size() words) - * - _ptr (1 word) - * - _stride (1 word) - * - if _ptr != UNINIT, _rounds (2 words) - * - if _ptr != UNINIT, _state (N words or 2 N words) - * - checksum - * - * Shortest possible saved result consists of 8 words. This corresponds to - * RandomSeed() = [] and Count() = 0. - * - * @param[in,out] os the output stream. - * @param[in] bin if true (the default) save in binary mode. - **********************************************************************/ - void Save(std::ostream& os, bool bin = true) const; - /** - * Restore the state of the Random object from an input stream. If \e bin, - * read in binary, else use text format. See documentation of - * RandomEngine::Save for the format. Include error checking on data to - * make sure the input has not been corrupted. If an error occurs while - * reading, the Random object is unchanged. - * - * @param[in,out] is the input stream. - * @param[in] bin if true (the default) load in binary mode. - * @exception RandomErr if the state read from \e is is illegal. - **********************************************************************/ - void Load(std::istream& is, bool bin = true) { - // Read state into temporary so as not to change object on error. - RandomEngine t(is, bin); - _seed.reserve(t._seed.size()); - *this = t; - } - ///@} - - /** - * \name Basic I/O - **********************************************************************/ - ///@{ - /** - * Write the state of a generator to stream \e os as text - * - * @param[in,out] os the output stream. - * @param[in] r the RandomEngine object to be saved. - **********************************************************************/ - friend std::ostream& operator<<(std::ostream& os, const RandomEngine& r) { - r.Save(os, false); - return os; - } - - /** - * Read the state of a generator from stream \e is as text - * - * @param[in,out] is the output stream. - * @param[in] r the RandomEngine object to be loaded. - * @exception RandomErr if the state read from \e is is illegal. - **********************************************************************/ - friend std::istream& operator>>(std::istream& is, RandomEngine& r) { - r.Load(is, false); - return is; - } - ///@} - - /** - * \name Examining and advancing the Random generator - **********************************************************************/ - ///@{ - /** - * Return the number of random numbers used. This needs to return a long - * long result since it can reasonably exceed 231. (On a 1GHz - * machine, it takes about a minute to produce 232 random - * numbers.) More precisely this is the (zero-based) index of the next - * random number to be produced. (This distinction is important when - * leapfrogging is in effect.) - * - * @return the count of random numbers used. - **********************************************************************/ - long long Count() const throw() - { return _ptr == UNINIT ? 0 : _rounds * N + _ptr; } - /** - * Step the generator forwards or backwards so that the value returned - * by Count() is \e n - * - * @param[in] n the new count. - **********************************************************************/ - void SetCount(long long n) throw() { StepCount(n - Count()); } - /** - * Step the generator forward \e n steps. \e n can be negative. - * - * @param[in] n how much to step the generator forward. - **********************************************************************/ - void StepCount(long long n) throw(); - /** - * Resets the sequence. Equivalent to SetCount(0), but works by - * reinitializing the Random object from its seed, rather than by stepping - * the sequence backwards. In addition, this undoes leapfrogging. - **********************************************************************/ - void Reset() throw() { _ptr = UNINIT; _stride = 1; } - ///@} - - /** - * \name Leapfrogging - **********************************************************************/ - ///@{ - /** - * Set leapfrogging stride to a positive number \e n and increment Count() - * by \e k < \e n. If the current Count() is \e i, then normally the next - * 3 random numbers would have (zero-based) indices \e i, \e i + 1, \e i + - * 2, and the new Count() is \e i + 2. However, after SetStride(\e n, \e - * k) the next 3 random numbers have indices \e i + \e k, \e i + \e k + \e - * n, \e i + \e k + 2\e n, and the new Count() is \e i + \e k + 3\e n. - * With leapfrogging in effect, the time to produce raw random numbers is - * roughly proportional to 1 + (\e n − 1)/3. Reseed(...) and Reset() - * both reset the stride back to 1. See \ref parallel for a description of - * how to use this facility. - * - * @param[in] n the stride (default 1). - * @param[in] k the initial increment (default 0). - * @exception RandomErr if \e n is 0 or too large or if \e k is not less - * than \e n. - **********************************************************************/ - void SetStride(unsigned n = 1, unsigned k = 0) { - // Limit stride to UNINIT/2. This catches negative numbers that have - // been cast into unsigned. In reality the stride should be no more than - // 10-100. - if (n == 0 || n > UNINIT/2) - throw RandomErr("RandomEngine: Invalid stride"); - if (k >= n) - throw RandomErr("RandomEngine: Invalid offset"); - _stride = n; - StepCount(k); - } - /** - * Return leapfrogging stride. - * - * @return the stride. - **********************************************************************/ - unsigned GetStride() const throw() { return _stride; } - ///@} - - /** - * Tests basic engine. - * - * @exception RandomErr if any of the tests fail. - **********************************************************************/ - static void SelfTest(); - - /** - * Return the name of the generator. This incorporates the names of the \e - * Algorithm and \e Mixer. - * - * @return the name of the generator. - **********************************************************************/ - static std::string Name() { - return "RandomEngine<" + Algorithm::Name() + "," + Mixer::Name() + ">"; - } - - private: - /** - * Compute initial state from seed - **********************************************************************/ - void Init() throw(); - /** - * The interface to Transition used by Ran(). - **********************************************************************/ - void Next() throw() { - if (_ptr == UNINIT) - Init(); - _rounds += _ptr/N; - Algorithm::Transition(_ptr/N, _statev); - _ptr %= N; - } - - u32::type Check(u64::type v, u32::type e, u32::type m) const; - - static result_type SelfTestResult(unsigned) throw() { return 0; } - - /** - * Read from an input stream. Potentially corrupts object. This private - * constructor is used by RandomEngine::Load so that it can avoid - * corrupting its state on bad input. - **********************************************************************/ - explicit RandomEngine(std::istream& is, bool bin); - -#if !defined(RANDOMLIB_BUILDING_LIBRARY) && \ - defined(HAVE_BOOST_SERIALIZATION) && HAVE_BOOST_SERIALIZATION - friend class boost::serialization::access; - /** - * Save to a boost archive. Boost versioning isn't very robust. (It - * allows a RandomGenerator32 to be read back in as a RandomGenerator64. - * It doesn't interact well with templates.) So we do our own versioning - * and supplement this with a checksum. - **********************************************************************/ - template void save(Archive& ar, const unsigned int) const { - u64::type _version = version; - u32::type _eversion = Algorithm::version, - _mversion = Mixer::version, - _checksum = Check(_version, _eversion, _mversion); - ar & boost::serialization::make_nvp("version" , _version ) - & boost::serialization::make_nvp("eversion", _eversion) - & boost::serialization::make_nvp("mversion", _mversion) - & boost::serialization::make_nvp("seed" , _seed ) - & boost::serialization::make_nvp("ptr" , _ptr ) - & boost::serialization::make_nvp("stride" , _stride ); - if (_ptr != UNINIT) - ar & boost::serialization::make_nvp("rounds", _rounds ) - & boost::serialization::make_nvp("state" , _state ); - ar & boost::serialization::make_nvp("checksum", _checksum); - } - /** - * Load from a boost archive. Do this safely so that the current object is - * not corrupted if the archive is bogus. - **********************************************************************/ - template void load(Archive& ar, const unsigned int) { - u64::type _version; - u32::type _eversion, _mversion, _checksum; - ar & boost::serialization::make_nvp("version" , _version ) - & boost::serialization::make_nvp("eversion", _eversion ) - & boost::serialization::make_nvp("mversion", _mversion ); - RandomEngine t(std::vector(0)); - ar & boost::serialization::make_nvp("seed" , t._seed ) - & boost::serialization::make_nvp("ptr" , t._ptr ) - & boost::serialization::make_nvp("stride" , t._stride ); - if (t._ptr != UNINIT) - ar & boost::serialization::make_nvp("rounds", t._rounds ) - & boost::serialization::make_nvp("state" , t._state ); - ar & boost::serialization::make_nvp("checksum", _checksum ); - if (t.Check(_version, _eversion, _mversion) != _checksum) - throw RandomErr("RandomEngine: Checksum failure"); - _seed.reserve(t._seed.size()); - *this = t; - } - /** - * Glue the boost save and load functionality together---a bit of boost - * magic. - **********************************************************************/ - template - void serialize(Archive &ar, const unsigned int file_version) - { boost::serialization::split_member(ar, *this, file_version); } -#endif // HAVE_BOOST_SERIALIZATION - - }; - - typedef RandomEngine, MixerSFMT> MRandomGenerator32; - typedef RandomEngine, MixerSFMT> MRandomGenerator64; - typedef RandomEngine, MixerSFMT> SRandomGenerator32; - typedef RandomEngine, MixerSFMT> SRandomGenerator64; - -} // namespace RandomLib - -namespace std { - /** - * Swap two RandomEngines. This is about 3x faster than the default swap. - * - * @tparam Algorithm the algorithm for the RandomEngine. - * @tparam Mixer the mixer for the RandomEngine. - * @param[in,out] r the first RandomEngine to swap. - * @param[in,out] s the second RandomEngine to swap. - **********************************************************************/ - template - void swap(RandomLib::RandomEngine& r, - RandomLib::RandomEngine& s) throw() { - r.swap(s); - } - -} // namespace std - -#endif // RANDOMLIB_RANDOMENGINE_HPP diff --git a/include/RandomLib/RandomMixer.hpp b/include/RandomLib/RandomMixer.hpp deleted file mode 100644 index d45e8f44..00000000 --- a/include/RandomLib/RandomMixer.hpp +++ /dev/null @@ -1,258 +0,0 @@ -/** - * \file RandomMixer.hpp - * \brief Header for Mixer classes. - * - * Mixer classes convert a seed vector into a random generator state. An - * important property of this method is that "close" seeds should produce - * "widely separated" states. This allows the seeds to be set is some - * systematic fashion to produce a set of uncorrelated random number - * sequences. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMMIXER_HPP) -#define RANDOMLIB_RANDOMMIXER_HPP 1 - -#include -#include -#include - -namespace RandomLib { - - /** - * \brief The original %MT19937 mixing functionality - * - * This implements the functionality of init_by_array in MT19937 - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c - * and init_by_array64 in MT19937_64 - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c - * with the following changes: - * - in the case of an zero-length seed array, behave in the same way if - * MT19937 and MT19937_64 are called without initialization in which case, - * e.g., init_genrand(5489UL) is called. (init_by_array does not allow - * calling with a zero-length seed.) - * - init_by_array64 accepts a seed array of 64-bit unsigned ints. Here with - * seed is an array of 32-bit unsigned ints and these are repacked into - * 64-bit quantities internally using a LSB convention. Thus, to mimic the - * MT19937_64 sample invocation with a seed array {0x12345ULL, 0x23456ULL, - * 0x34567ULL, 0x45678ULL}, MixerMT0::SeedToState needs to - * be invoked with a seed vector [0x12345UL, 0, 0x23456UL, 0, 0x34567UL, 0, - * 0x45678UL, 0]. (Actually the last 0 is unnecessary.) - * - * The template parameter \e RandomType switches between the 32-bit and - * 64-bit versions. - * - * MixerMT0 is specific to the MT19937 generators and should not be used - * for other generators (e.g., SFMT19937). In addition, MixerMT0 has - * known defects and should only be used to check the operation of the - * MT19937 engines against the original implementation. These defects are - * described in the MixerMT1 which is a modification of MixerMT0 - * which corrects these defects. For production use MixerMT1 or, - * preferably, MixerSFMT should be used. - * - * @tparam RandomType the type of the results, either Random_u32 or - * Random_u64. - **********************************************************************/ - template class RANDOMLIB_EXPORT MixerMT0 { - public: - /** - * The RandomType controlling the output of MixerMT0::SeedToState - **********************************************************************/ - typedef RandomType mixer_t; - /** - * A version number which should be unique to this RandomMixer. This - * prevents RandomEngine::Load from loading a saved generator with a - * different RandomMixer. Here the version is "MxMT" or "MxMU". - **********************************************************************/ - static const unsigned version = 0x4d784d54UL + (mixer_t::width == 64); - private: - /** - * The unsigned type corresponding to mixer_t. - **********************************************************************/ - typedef typename mixer_t::type mixer_type; - /** - * The mask for mixer_t. - **********************************************************************/ - static const mixer_type mask = mixer_t::mask; - public: - /** - * Mix the seed vector, \e seed, into the state array, \e state, of size \e - * n. - * - * @param[in] seed the input seed vector. - * @param[out] state the generator state. - * @param[in] n the size of the state. - **********************************************************************/ - static void SeedToState(const std::vector& seed, - mixer_type state[], unsigned n) throw(); - /** - * Return the name of this class. - * - * @return the name. - **********************************************************************/ - static std::string Name() { - return "MixerMT0"; - } - private: - static const mixer_type a0 = 5489ULL; - static const mixer_type a1 = 19650218ULL; - static const mixer_type - b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL; - static const mixer_type - c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL; - static const mixer_type - d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL; - }; - - /** - * \brief The modified %MT19937 mixing functionality - * - * MixerMT0 has two defects - * - The zeroth word of the state is set to a constant (independent of the - * seed). This is a relatively minor defect which halves the accessible - * state space for MT19937 (but the resulting state space is still huge). - * (Actually, for the 64-bit version, it reduces the accessible states by - * 233. On the other hand the 64-bit has better mixing - * properties.) - * - Close seeds, for example, [1] and [1,0], result in the same state. This - * is a potentially serious flaw which might result is identical random - * number sequences being generated instead of independent sequences. - * - * MixerMT1 fixes these defects in a straightforward manner. The - * resulting algorithm was included in one of the proposals for Random Number - * Generation for C++0X, see Brown, et al., - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf - * - * The template parameter \e RandomType switches between the 32-bit and - * 64-bit versions. - * - * MixerMT1 still has a weakness in that it doesn't thoroughly mix the - * state. This is illustrated by an example given to me by Makoto Matsumoto: - * Consider a seed of length \e N and suppose we consider all \e - * WN/2 values for the first half of the seed (here \e W = - * 2width). MixerMT1 has a bottleneck in the way that - * the state is initialized which results in the second half of the state - * only taking on \e W2 possible values. MixerSFMT mixes the - * seed into the state much more thoroughly. - * - * @tparam RandomType the type of the results, either Random_u32 or - * Random_u64. - **********************************************************************/ - template class RANDOMLIB_EXPORT MixerMT1 { - public: - /** - * The RandomType controlling the output of MixerMT1::SeedToState - **********************************************************************/ - typedef RandomType mixer_t; - /** - * A version number which should be unique to this RandomMixer. This - * prevents RandomEngine::Load from loading a saved generator with a - * different RandomMixer. Here the version is "MxMV" or "MxMW". - **********************************************************************/ - static const unsigned version = 0x4d784d56UL + (mixer_t::width == 64); - private: - /** - * The unsigned type corresponding to mixer_t. - **********************************************************************/ - typedef typename mixer_t::type mixer_type; - /** - * The mask for mixer_t. - **********************************************************************/ - static const mixer_type mask = mixer_t::mask; - public: - /** - * Mix the seed vector, \e seed, into the state array, \e state, of size \e - * n. - * - * @param[in] seed the input seed vector. - * @param[out] state the generator state. - * @param[in] n the size of the state. - **********************************************************************/ - static void SeedToState(const std::vector& seed, - mixer_type state[], unsigned n) throw(); - /** - * Return the name of this class. - * - * @return the name. - **********************************************************************/ - static std::string Name() { - return "MixerMT1"; - } - private: - static const mixer_type a = 5489ULL; - static const mixer_type - b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL; - static const mixer_type - c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL; - static const mixer_type - d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL; - }; - - /** - * \brief The SFMT mixing functionality - * - * MixerSFMT is adapted from SFMT's init_by_array Mutsuo Saito given in - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz - * and is part of the C++11 standard; see P. Becker, Working Draft, Standard - * for Programming Language C++, Oct. 2007, Sec. 26.4.7.1, - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf - * - * MixerSFMT contains a single change is to allow it to function properly - * when the size of the state is small. - * - * MixerSFMT mixes the seed much more thoroughly than MixerMT1 and, in - * particular, it removes the mixing bottleneck present in MixerMT1. - * Thus it is the recommended mixing scheme for all production work. - **********************************************************************/ - class RANDOMLIB_EXPORT MixerSFMT { - public: - /** - * The RandomType controlling the output of MixerSFMT::SeedToState - **********************************************************************/ - typedef Random_u32 mixer_t; - /** - * A version number which should be unique to this RandomMixer. This - * prevents RandomEngine::Load from loading a saved generator with a - * different RandomMixer. Here the version is "MxSM". - **********************************************************************/ - static const unsigned version = 0x4d78534dUL; - private: - /** - * The unsigned type corresponding to mixer_t. - **********************************************************************/ - typedef mixer_t::type mixer_type; - /** - * The mask for mixer_t. - **********************************************************************/ - static const mixer_type mask = mixer_t::mask; - public: - /** - * Mix the seed vector, \e seed, into the state array, \e state, of size \e - * n. - * - * @param[in] seed the input seed vector. - * @param[out] state the generator state. - * @param[in] n the size of the state. - **********************************************************************/ - static void SeedToState(const std::vector& seed, - mixer_type state[], unsigned n) throw(); - /** - * Return the name of this class. - * - * @return the name. - **********************************************************************/ - static std::string Name() { return "MixerSFMT"; } - private: - static const mixer_type a = 0x8b8b8b8bUL; - static const mixer_type b = 1664525UL; - static const mixer_type c = 1566083941UL; - }; - -} // namespace RandomLib - -#endif // RANDOMLIB_RANDOMMIXER_HPP diff --git a/include/RandomLib/RandomNumber.hpp b/include/RandomLib/RandomNumber.hpp deleted file mode 100644 index f79fca74..00000000 --- a/include/RandomLib/RandomNumber.hpp +++ /dev/null @@ -1,472 +0,0 @@ -/** - * \file RandomNumber.hpp - * \brief Header for RandomNumber - * - * Infinite precision random numbers. - * - * Copyright (c) Charles Karney (2006-2013) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMNUMBER_HPP) -#define RANDOMLIB_RANDOMNUMBER_HPP 1 - -#include -#include -#include -#include // for std::pow -#include - -namespace RandomLib { - /** - * \brief Infinite precision random numbers. - * - * Implement infinite precision random numbers. Integer part is non-random. - * Fraction part consists of any some number of digits in base - * 2b. If \e m digits have been generated then the - * fraction is uniformly distributed in the open interval - * ∑k=1m - * fk−1/2kb + - * (0,1)/2mb. When a RandomNumber is first constructed the - * integer part is zero and \e m = 0, and the number represents (0,1). A - * RandomNumber is able to represent all numbers in the symmetric open - * interval (−231, 231). In this implementation, - * \e b must one of 1, 2, 3, 4, 8, 12, 16, 20, 24, 28, or 32. (This - * restriction allows printing in hexadecimal and can easily be relaxed. - * There's also no essential reason why the base should be a power of 2.) - * - * @tparam bits the number of bits in each digit. - **********************************************************************/ - template class RandomNumber { - public: - /** - * Constructor sets number to a random number uniformly distributed in - * (0,1). - **********************************************************************/ - RandomNumber() throw() : _n(0), _s(1) {} - /** - * Swap with another RandomNumber. This is a fast way of doing an - * assignment. - * - * @param[in,out] t the RandomNumber to swap with. - **********************************************************************/ - void swap(RandomNumber& t) throw() { - if (this != &t) { - std::swap(_n, t._n); - std::swap(_s, t._s); - _f.swap(t._f); - } - } - /** - * Return to initial state, uniformly distributed in (0,1). - **********************************************************************/ - void Init() throw() { - STATIC_ASSERT(bits > 0 && bits <= w && (bits < 4 || bits % 4 == 0), - "RandomNumber: unsupported value for bits"); - _n = 0; - _s = 1; - _f.clear(); - } - /** - * @return the sign of the RandomNumber (± 1). - **********************************************************************/ - int Sign() const throw() { return _s; } - /** - * Change the sign of the RandomNumber. - **********************************************************************/ - void Negate() throw() { _s *= -1; } - /** - * @return the floor of the RandomNumber. - **********************************************************************/ - int Floor() const throw() { return _s > 0 ? int(_n) : -1 - int(_n); } - /** - * @return the ceiling of the RandomNumber. - **********************************************************************/ - int Ceiling() const throw() { return _s > 0 ? 1 + int(_n) : - int(_n); } - /** - * @return the unsigned integer component of the RandomNumber. - **********************************************************************/ - unsigned UInteger() const throw() { return _n; } - /** - * Add integer \e k to the RandomNumber. - * - * @param[in] k the integer to add. - **********************************************************************/ - void AddInteger(int k) throw() { - k += Floor(); // The new floor - int ns = k < 0 ? -1 : 1; // The new sign - if (ns != _s) // If sign changes, set f = 1 - f - for (size_t k = 0; k < Size(); ++k) - _f[k] = ~_f[k] & mask; - _n = ns > 0 ? k : -(k + 1); - } - /** - * Compare with another RandomNumber, *this < \e t - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in,out] t a RandomNumber to compare. - * @return true if *this < \e t. - **********************************************************************/ - template bool LessThan(Random& r, RandomNumber& t) { - if (this == &t) return false; // same object - if (_s != t._s) return _s < t._s; - if (_n != t._n) return (_s < 0) ^ (_n < t._n); - for (unsigned k = 0; ; ++k) { - // Impose an order on the evaluation of the digits. - const unsigned x = Digit(r,k); - const unsigned y = t.Digit(r,k); - if (x != y) return (_s < 0) ^ (x < y); - // Two distinct numbers are never equal - } - } - /** - * Compare RandomNumber with two others, *this > max(\e u, \e v) - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in,out] u first RandomNumber to compare. - * @param[in,out] v second RandomNumber to compare. - * @return true if *this > max(\e u, \e v). - **********************************************************************/ - template bool GreaterPair(Random& r, - RandomNumber& u, RandomNumber& v) { - // cmps is set to false as soon as u <= *this, and likewise for cmpt. - bool cmpu = this != &u, cmpv = this != &v && &u != &v; - if (!(cmpu || cmpv)) return true; - // Check signs first - if (cmpu) { - if (u._s > _s) return false; // u > *this - if (u._s < _s) cmpu = false; - } - if (cmpv) { - if (v._s > _s) return false; // v > *this - if (v._s < _s) cmpv = false; - } - if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this - // Check integer parts - if (cmpu) { - if ((_s < 0) ^ (u._n > _n)) return false; // u > *this - if ((_s < 0) ^ (u._n < _n)) cmpu = false; - } - if (cmpv) { - if ((_s < 0) ^ (v._n > _n)) return false; // v > *this - if ((_s < 0) ^ (v._n < _n)) cmpv = false; - } - if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this - // Check fractions - for (unsigned k = 0; ; ++k) { - // Impose an order on the evaluation of the digits. Note that this is - // asymmetric on interchange of u and v; since u is tested first, more - // digits of u are generated than v (on average). - const unsigned x = Digit(r,k); - if (cmpu) { - const unsigned y = u.Digit(r,k); - if ((_s < 0) ^ (y > x)) return false; // u > *this - if ((_s < 0) ^ (y < x)) cmpu = false; - } - if (cmpv) { - const unsigned y = v.Digit(r,k); - if ((_s < 0) ^ (y > x)) return false; // v > *this - if ((_s < 0) ^ (y < x)) cmpv = false; - } - if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this - } - } - /** - * Compare with a fraction, *this < p/q - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] p the numerator of the fraction. - * @param[in] q the denominator of the fraction (require \e q > 0). - * @return true if *this < p/q. - **********************************************************************/ - template - bool LessThan(Random& r, IntType p, IntType q) { - for (int k = 0;; ++k) { - if (p <= 0) return false; - if (p >= q) return true; - // Here p is in [1,q-1]. Need to avoid overflow in computation of - // (q-1)<p0 + cj)/q. - **********************************************************************/ - template - bool LessThan(Random& r, IntType p0, IntType c, IntType q, - UniformInteger& j) { - for (int k = 0;; ++k) { - if (j. LessThanEqual(r, - p0, c)) return false; - if (j.GreaterThanEqual(r, q - p0, c)) return true; - p0 = (p0 << bits) - IntType(Digit(r,k)) * q; - c <<= bits; - } - } - - /** - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] k the index of a digit of the fraction - * @return digit number \e k, generating it if necessary. - **********************************************************************/ - template unsigned Digit(Random& r, unsigned k) { - ExpandTo(r, k + 1); - return _f[k]; - } - /** - * Add one digit to the fraction. - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - **********************************************************************/ - template void AddDigit(Random& r) - { _f.push_back(RandomDigit(r)); } - /** - * @param[in] k the index of a digit of the fraction - * @return a const reference to digit number \e k, without generating new - * digits. - * @exception std::out_of_range if the digit hasn't been generated. - **********************************************************************/ - const unsigned& RawDigit(unsigned k) const throw() - { return (const unsigned&)(_f.at(k)); } - /** - * @param[in] k the index of a digit of the fraction - * @return a non-const reference to digit number \e k, without generating - * new digits. - * @exception std::out_of_range if the digit hasn't been generated. - **********************************************************************/ - unsigned& RawDigit(unsigned k) throw() - { return (unsigned&)(_f.at(k)); } - /** - * Return to initial state, uniformly distributed in \e n + (0,1). This is - * similar to Init but also returns the memory used by the object to the - * system. Normally Init should be used. - **********************************************************************/ - void Clear() { - std::vector z(0); - _n = 0; - _s = 1; - _f.swap(z); - } - /** - * @return the number of digits in fraction - **********************************************************************/ - unsigned Size() const throw() { return unsigned(_f.size()); } - /** - * Return the fraction part of the RandomNumber as a floating point number - * of type RealType rounded to the nearest multiple of - * 1/2p, where \e p = - * std::numeric_limits::digits, and, if necessary, creating - * additional digits of the number. - * - * @tparam RealType the floating point type to convert to. - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator for generating the necessary digits. - * @return the fraction of the RandomNumber rounded to a RealType. - **********************************************************************/ - template RealType Fraction(Random& r) { - STATIC_ASSERT(!std::numeric_limits::is_integer, - "RandomNumber::Fraction: invalid real type RealType"); - const int d = std::numeric_limits::digits; - const int k = (d + bits - 1)/bits; - const int kg = (d + bits)/bits; // For guard bit - RealType y = 0; - if (Digit(r, kg - 1) & (1U << (kg * bits - d - 1))) - // if guard bit is set, round up. - y += std::pow(RealType(2), -d); - const RealType fact = std::pow(RealType(2), -bits); - RealType mult = RealType(1); - for (int i = 0; i < k; ++i) { - mult *= fact; - y += mult * RealType(i < k - 1 ? RawDigit(i) : - RawDigit(i) & (~0U << (k * bits - d))); - } - return y; - } - /** - * Return the value of the RandomNumber rounded to nearest floating point - * number of type RealType and, if necessary, creating additional digits of - * the number. - * - * @tparam RealType the floating point type to convert to. - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator for generating the necessary digits. - * @return the value of the RandomNumber rounded to a RealType. - **********************************************************************/ - template RealType Value(Random& r) { - // Ignore the possibility of overflow here (OK because int doesn't - // currently overflow any real type). Assume the real type supports - // denormalized numbers. Need to treat rounding explicitly since the - // missing digits always imply rounding up. - STATIC_ASSERT(!std::numeric_limits::is_integer, - "RandomNumber::Value: invalid real type RealType"); - const int digits = std::numeric_limits::digits, - min_exp = std::numeric_limits::min_exponent; - RealType y; - int lead; // Position of leading bit (0.5 = position 0) - if (_n) lead = highest_bit_idx(_n); - else { - int i = 0; - while ( Digit(r, i) == 0 && i < (-min_exp)/bits ) ++i; - lead = highest_bit_idx(RawDigit(i)) - (i + 1) * bits; - // To handle denormalized numbers set lead = max(lead, min_exp) - lead = lead > min_exp ? lead : min_exp; - } - int trail = lead - digits; // Position of guard bit (0.5 = position 0) - if (trail > 0) { - y = RealType(_n & (~0U << trail)); - if (_n & (1U << (trail - 1))) - y += std::pow(RealType(2), trail); - } else { - y = RealType(_n); - int k = (-trail)/bits; // Byte with guard bit - if (Digit(r, k) & (1U << ((k + 1) * bits + trail - 1))) - // If guard bit is set, round bit (some subsequent bit will be 1). - y += std::pow(RealType(2), trail); - // Byte with trailing bit (can be negative) - k = (-trail - 1 + bits)/bits - 1; - const RealType fact = std::pow(RealType(2), -bits); - RealType mult = RealType(1); - for (int i = 0; i <= k; ++i) { - mult *= fact; - y += mult * - RealType(i < k ? RawDigit(i) : - RawDigit(i) & (~0U << ((k + 1) * bits + trail))); - } - } - if (_s < 0) y *= -1; - return y; - } - /** - * Return the range of possible values for the RandomNumber as pair of - * doubles. This doesn't create any additional digits of the result and - * doesn't try to control roundoff. - * - * @return a pair denoting the range with first being the lower limit and - * second being the upper limit. - **********************************************************************/ - std::pair Range() const throw() { - double y = _n; - const double fact = std::pow(double(2), -bits); - double mult = double(1); - for (unsigned i = 0; i < Size(); ++i) { - mult *= fact; - y += mult * RawDigit(i); - } - return std::pair(_s > 0 ? y : -(y + mult), - _s > 0 ? (y + mult) : -y); - } - /** - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @return a random digit in [0, 2bits). - **********************************************************************/ - template static unsigned RandomDigit(Random& r) throw() - { return unsigned(r.template Integer()); } - - private: - /** - * The integer part - **********************************************************************/ - unsigned _n; - /** - * The sign - **********************************************************************/ - int _s; - /** - * The fraction part - **********************************************************************/ - std::vector _f; - /** - * Fill RandomNumber to \e k digits. - **********************************************************************/ - template void ExpandTo(Random& r, size_t k) { - size_t l = _f.size(); - if (k <= l) - return; - _f.resize(k); - for (size_t i = l; i < k; ++i) - _f[i] = RandomDigit(r); - } - /** - * Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x - * = ~0. (From Algorithms for programmers by Joerg Arndt.) - **********************************************************************/ - static int highest_bit_idx(unsigned x) throw() { - if (x == 0) return 0; - int r = 1; - if (x & 0xffff0000U) { x >>= 16; r += 16; } - if (x & 0x0000ff00U) { x >>= 8; r += 8; } - if (x & 0x000000f0U) { x >>= 4; r += 4; } - if (x & 0x0000000cU) { x >>= 2; r += 2; } - if (x & 0x00000002U) { r += 1; } - return r; - } - /** - * The number of bits in unsigned. - **********************************************************************/ - static const int w = std::numeric_limits::digits; - public: - /** - * A mask for the digits. - **********************************************************************/ - static const unsigned mask = - bits == w ? ~0U : ~(~0U << (bits < w ? bits : 0)); - }; - - /** - * \relates RandomNumber - * Print a RandomNumber. Format is n.dddd... where the base for printing is - * 2max(4,b). The ... represents an infinite sequence of - * ungenerated random digits (uniformly distributed). Thus with \e b = 1, - * 0.0... = (0,1/2), 0.00... = (0,1/4), 0.11... = (3/4,1), etc. - **********************************************************************/ - template - std::ostream& operator<<(std::ostream& os, const RandomNumber& n) { - const std::ios::fmtflags oldflags = os.flags(); - RandomNumber t = n; - os << (t.Sign() > 0 ? "+" : "-"); - unsigned i = t.UInteger(); - os << std::hex << std::setfill('0'); - if (i == 0) - os << "0"; - else { - bool first = true; - const int w = std::numeric_limits::digits; - const unsigned mask = RandomNumber::mask; - for (int s = ((w + bits - 1)/bits) * bits - bits; s >= 0; s -= bits) { - unsigned d = mask & (i >> s); - if (d || !first) { - if (first) { - os << d; - first = false; - } - else - os << std::setw((bits+3)/4) << d; - } - } - } - os << "."; - unsigned s = t.Size(); - for (unsigned i = 0; i < s; ++i) - os << std::setw((bits+3)/4) << t.RawDigit(i); - os << "..." << std::setfill(' '); - os.flags(oldflags); - return os; - } - -} // namespace RandomLib - -#endif // RANDOMLIB_RANDOMNUMBER_HPP diff --git a/include/RandomLib/RandomPower2.hpp b/include/RandomLib/RandomPower2.hpp deleted file mode 100644 index 384474e8..00000000 --- a/include/RandomLib/RandomPower2.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - * \file RandomPower2.hpp - * \brief Header for RandomPower2. - * - * Return and multiply by powers of two. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMPOWER2_HPP) -#define RANDOMLIB_RANDOMPOWER2_HPP 1 - -#include // For std::pow - -namespace RandomLib { - - /** - * \brief Return or multiply by powers of 2 - * - * With some compilers it's fastest to do a table lookup of powers of - * 2. If RANDOMLIB_POWERTABLE is 1, a lookup table is used. If - * RANDOMLIB_POWERTABLE is 0, then std::pow is used. - **********************************************************************/ - class RANDOMLIB_EXPORT RandomPower2 { - public: - /** - * Return powers of 2 (either using a lookup table or std::pow) - * - * @param[in] n the integer power. - * @return 2n. - **********************************************************************/ - template static inline RealType pow2(int n) throw() { -#if RANDOMLIB_POWERTABLE - return RealType(power2[n - minpow]); -#else - return std::pow(RealType(2), n); -#endif - } - /** - * Multiply a real by a power of 2 - * - * @tparam RealType the type of \e x. - * @param[in] x the real number. - * @param[in] n the power (positive or negative). - * @return \e x 2n. - **********************************************************************/ - template - static inline RealType shiftf(RealType x, int n) throw() - // std::ldexp(x, n); is equivalent, but slower - { return x * pow2(n); } - - // Constants - enum { - /** - * Minimum power in RandomPower2::power2 - **********************************************************************/ -#if RANDOMLIB_LONGDOUBLEPREC > 64 - minpow = -120, -#else - minpow = -64, -#endif - maxpow = 64 /**< Maximum power in RandomPower2::power2. */ - }; - private: -#if RANDOMLIB_POWERTABLE - /** - * Table of powers of two - **********************************************************************/ - static const float power2[maxpow - minpow + 1]; // Powers of two -#endif - }; - -} // namespace RandomLib - -#endif // RANDOMLIB_RANDOMPOWER2_HPP diff --git a/include/RandomLib/RandomSeed.hpp b/include/RandomLib/RandomSeed.hpp deleted file mode 100644 index 84a63ee4..00000000 --- a/include/RandomLib/RandomSeed.hpp +++ /dev/null @@ -1,251 +0,0 @@ -/** - * \file RandomSeed.hpp - * \brief Header for RandomSeed - * - * This provides a base class for random generators. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMSEED_HPP) -#define RANDOMLIB_RANDOMSEED_HPP 1 - -#include -#include -#include -#include -#include // For std::transform -#include // For VectorToString -#include - -#if defined(_MSC_VER) -// Squelch warnings about dll vs vector -#pragma warning (push) -#pragma warning (disable: 4251) -#endif - -namespace RandomLib { - /** - * \brief A base class for random generators - * - * This provides facilities for managing the seed and for converting the seed - * into random generator state. - * - * The seed is taken to be a vector of unsigned longs of arbitrary length. - * (Only the low 32 bit of each element of the vector are used.) The class - * provides several methods for setting the seed, static functions for - * producing "random" and "unique" seeds, and facilities for converting the - * seed to a string so that it can be printed easily. - * - * The seeding algorithms are those used by - * - * MT19937 with some modifications to make all states accessible and to - * minimize the likelihood of different seeds giving the same state. - * - * Finally some low-level routines are provided to facilitate the creation of - * I/O methods for the random generator. - * - * A random generator class can be written based on this class. The - * generator class would use the base class methods for setting the seed and - * for converting the seed into state. It would provide the machinery for - * advancing the state and for producing random data. It is also responsible - * for the routine to save and restore the generator state (including the - * seed). - * - * Written by Charles Karney and licensed under the - * MIT/X11 License. The seeding algorithms are adapted from those of - * - * MT19937. For more information, see http://randomlib.sourceforge.net/ - **********************************************************************/ - class RANDOMLIB_EXPORT RandomSeed { - public: - typedef Random_u32 u32; - typedef Random_u64 u64; - - virtual ~RandomSeed() throw() = 0; - /** - * A type large enough to hold the seed words. This is needs to hold 32 - * bits and is an unsigned long for portability. - **********************************************************************/ - typedef RandomType<32, unsigned long> seed_t; - typedef seed_t::type seed_type; - - /** - * \name Resetting the seed - **********************************************************************/ - ///@{ - /** - * Set the seed to a vector \e v. Only the low \e 32 bits of each element - * are used. - * - * @tparam IntType the integral type of the elements of the vector. - * @param[in] v the vector of elements. - **********************************************************************/ - template void Reseed(const std::vector& v) { - Reseed(v.begin(), v.end()); - } - /** - * Set the seed to [\e a, \e b) from a pair of iterators. The iterator - * must produce results which can be converted into seed_type. Only the - * low 32 bits of each element are used. - * - * @tparam InputIterator the type of the iterator. - * @param[in] a the beginning iterator. - * @param[in] b the ending iterator. - **********************************************************************/ - template - void Reseed(InputIterator a, InputIterator b) { - // Read new seed into temporary so as not to change object on error. - std::vector t; - std::transform(a, b, back_inserter(t), - seed_t::cast - ::value_type>); - _seed.swap(t); - Reset(); - } - /** - * Set the seed to [\e n]. Only the low 32 bits of \e n are used. - * - * @param[in] n the new seed to use. - **********************************************************************/ - void Reseed(seed_type n) { - // Reserve space for new seed so as not to change object on error. - _seed.reserve(1); - _seed.resize(1); - _seed[0] = seed_t::cast(n); - Reset(); - } - /** - * Set the seed to [SeedVector()]. This is the standard way to reseed with - * a "unique" seed. - **********************************************************************/ - void Reseed() { Reseed(SeedVector()); } - /** - * Set the seed from the string \e s using Random::StringToVector. - * - * @param[in] s the string to be decoded into a seed. - **********************************************************************/ - void Reseed(const std::string& s) { - // Read new seed into temporary so as not to change object on error. - std::vector t = StringToVector(s); - _seed.swap(t); - Reset(); - } - ///@} - - /** - * \name Examining the seed - **********************************************************************/ - ///@{ - /** - * Return reference to the seed vector (read-only). - * - * @return the seed vector. - **********************************************************************/ - const std::vector& Seed() const throw() { return _seed; } - /** - * Format the current seed suitable for printing. - * - * @return the seedd as a string. - **********************************************************************/ - std::string SeedString() const { return VectorToString(_seed); } - ///@} - - /** - * \name Resetting the random seed - **********************************************************************/ - ///@{ - /** - * Resets the sequence to its just-seeded state. This needs to be declared - * virtual here so that the Reseed functions can call it after saving the - * seed. - **********************************************************************/ - virtual void Reset() throw() = 0; - ///@} - - /** - * \name Static functions for seed management - **********************************************************************/ - ///@{ - /** - * Return a 32 bits of data suitable for seeding the random generator. The - * result is obtained by combining data from /dev/urandom, gettimeofday, - * time, and getpid to provide a reasonably "random" word of data. - * Usually, it is safer to seed the random generator with SeedVector() - * instead of SeedWord(). - * - * @return a single "more-or-less random" seed_type to be used as a seed. - **********************************************************************/ - static seed_type SeedWord(); - /** - * Return a vector of unsigned longs suitable for seeding the random - * generator. The vector is almost certainly unique; however, the results - * of successive calls to Random::SeedVector() will be correlated. If - * several Random objects are required within a single program execution, - * call Random::SeedVector once, print it out (!), push_back additional - * data to identify the instance (e.g., loop index, thread ID, etc.), and - * use the result to seed the Random object. The number of elements - * included in the vector may depend on the operating system. Additional - * elements may be added in future versions of this library. - * - * @return a "unique" vector of seed_type to be uses as a seed. - **********************************************************************/ - static std::vector SeedVector(); - /** - * Convert a vector into a string suitable for printing or as an argument - * for Random::Reseed(const std::string& s). - * - * @tparam IntType the integral type of the elements of the vector. - * @param[in] v the vector to be converted. - * @return the resulting string. - **********************************************************************/ - template - static std::string VectorToString(const std::vector& v) { - std::ostringstream os; - os << "["; - for (typename std::vector::const_iterator n = v.begin(); - n != v.end(); ++n) { - if (n != v.begin()) - os << ","; - // Normalize in case this is called by user. - os << seed_t::cast(*n); - } - os << "]"; - return os.str(); - } - /** - * Convert a string into a vector of seed_type suitable for printing or as - * an argument for Random::Reseed(const std::vector& v). Reads - * consecutive digits in string. Thus "[1,2,3]" => [1,2,3]; "-0.123e-4" => - * [0,123,4], etc. strtoul understands C's notation for octal and - * hexadecimal, for example "012 10 0xa" => [10,10,10]. Reading of a - * number stops at the first illegal character for the base. Thus - * "2006-04-08" => [2006,4,0,8] (i.e., 08 becomes two numbers). Note that - * input numbers greater than ULONG_MAX overflow to ULONG_MAX, which - * probably will result in the number being interpreted as LONG_MASK. - * - * @param[in] s the string to be converted. - * @return the resulting vector of seed_type. - **********************************************************************/ - static std::vector StringToVector(const std::string& s); - ///@} - - protected: - /** - * The seed vector - **********************************************************************/ - std::vector _seed; - - }; - - inline RandomSeed::~RandomSeed() throw() {} - -} // namespace RandomLib - -#if defined(_MSC_VER) -#pragma warning (pop) -#endif - -#endif // RANDOMLIB_RANDOMSEED_HPP diff --git a/include/RandomLib/RandomSelect.hpp b/include/RandomLib/RandomSelect.hpp deleted file mode 100644 index 0c317913..00000000 --- a/include/RandomLib/RandomSelect.hpp +++ /dev/null @@ -1,335 +0,0 @@ -/** - * \file RandomSelect.hpp - * \brief Header for RandomSelect. - * - * An implementation of the Walker algorithm for selecting from a finite set. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_RANDOMSELECT_HPP) -#define RANDOMLIB_RANDOMSELECT_HPP 1 - -#include -#include -#include - -#if defined(_MSC_VER) -// Squelch warnings about constant conditional expressions -# pragma warning (push) -# pragma warning (disable: 4127) -#endif - -namespace RandomLib { - /** - * \brief Random selection from a discrete set. - * - * An implementation of Walker algorithm for selecting from a finite set - * (following Knuth, TAOCP, Vol 2, Sec 3.4.1.A). This provides a rapid way - * of selecting one of several choices depending on a discrete set weights. - * Original citation is\n A. J. Walker,\n An Efficient Method for Generating - * Discrete Random Variables and General Distributions,\n ACM TOMS 3, - * 253--256 (1977). - * - * There are two changes here in the setup algorithm as given by Knuth: - * - * - The probabilities aren't sorted at the beginning of the setup; nor are - * they maintained in a sorted order. Instead they are just partitioned on - * the mean. This improves the setup time from O(\e k2) to O(\e - * k). - * - * - The internal calculations are carried out with type \e NumericType. If - * the input weights are of integer type, then choosing an integer type for - * \e NumericType yields an exact solution for the returned distribution - * (assuming that the underlying random generator is exact.) - * - * Example: - * \code - #include - - // Weights for throwing a pair of dice - unsigned w[] = { 0, 0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 }; - - // Initialize selection - RandomLib::RandomSelect sel(w, w + 13); - - RandomLib::Random r; // Initialize random numbers - std::cout << "Seed set to " << r.SeedString() << "\n"; - - std::cout << "Throw a pair of dice 100 times:"; - for (unsigned i = 0; i < 100; ++i) - std::cout << " " << sel(r); - std::cout << "\n"; - \endcode - * - * @tparam NumericType the numeric type to use (default double). - **********************************************************************/ - template class RandomSelect { - public: - /** - * Initialize in a cleared state (equivalent to having a single - * choice). - **********************************************************************/ - RandomSelect() : _k(0), _wsum(0), _wmax(0) {} - - /** - * Initialize with a weight vector \e w of elements of type \e WeightType. - * Internal calculations are carried out with type \e NumericType. \e - * NumericType needs to allow Choices() * MaxWeight() to be represented. - * Sensible combinations are: - * - \e WeightType integer, \e NumericType integer with - * digits(\e NumericType) ≥ digits(\e WeightType) - * - \e WeightType integer, \e NumericType real - * - \e WeightType real, \e NumericType real with digits(\e NumericType) - * ≥ digits(\e WeightType) - * - * @tparam WeightType the type of the weights. - * @param[in] w the vector of weights. - * @exception RandomErr if any of the weights are negative or if the total - * weight is not positive. - **********************************************************************/ - template - RandomSelect(const std::vector& w) { Init(w.begin(), w.end()); } - - /** - * Initialize with a weight given by a pair of iterators [\e a, \e b). - * - * @tparam InputIterator the type of the iterator. - * @param[in] a the beginning iterator. - * @param[in] b the ending iterator. - * @exception RandomErr if any of the weights are negative or if the total - * weight is not positive. - **********************************************************************/ - template - RandomSelect(InputIterator a, InputIterator b); - - /** - * Clear the state (equivalent to having a single choice). - **********************************************************************/ - void Init() throw() - { _k = 0; _wsum = 0; _wmax = 0; _Q.clear(); _Y.clear(); } - - /** - * Re-initialize with a weight vector \e w. Leave state unaltered in the - * case of an error. - * - * @tparam WeightType the type of the weights. - * @param[in] w the vector of weights. - **********************************************************************/ - template - void Init(const std::vector& w) { Init(w.begin(), w.end()); } - - /** - * Re-initialize with a weight given as a pair of iterators [\e a, \e b). - * Leave state unaltered in the case of an error. - * - * @tparam InputIterator the type of the iterator. - * @param[in] a the beginning iterator. - * @param[in] b the ending iterator. - **********************************************************************/ - template - void Init(InputIterator a, InputIterator b) { - RandomSelect t(a, b); - _Q.reserve(t._k); - _Y.reserve(t._k); - *this = t; - } - - /** - * Return an index into the weight vector with probability proportional to - * the weight. - * - * @tparam Random the type of RandomCanonical generator. - * @param[in,out] r the RandomCanonical generator. - * @return the random index into the weight vector. - **********************************************************************/ - template - unsigned operator()(Random& r) const throw() { - if (_k <= 1) - return 0; // Special cases - const unsigned K = r.template Integer(_k); - // redundant casts to type NumericType to prevent warning from MS Project - return (std::numeric_limits::is_integer ? - r.template Prob(NumericType(_Q[K]), - NumericType(_wsum)) : - r.template Prob(NumericType(_Q[K]))) ? - K : _Y[K]; - } - - /** - * @return the sum of the weights. - **********************************************************************/ - NumericType TotalWeight() const throw() { return _wsum; } - - /** - * @return the maximum weight. - **********************************************************************/ - NumericType MaxWeight() const throw() { return _wmax; } - - /** - * @param[in] i the index in to the weight vector. - * @return the weight for sample \e i. Weight(i) / TotalWeight() gives the - * probability of sample \e i. - **********************************************************************/ - NumericType Weight(unsigned i) const throw() { - if (i >= _k) - return NumericType(0); - else if (_k == 1) - return _wsum; - const NumericType n = std::numeric_limits::is_integer ? - _wsum : NumericType(1); - NumericType p = _Q[i]; - for (unsigned j = _k; j;) - if (_Y[--j] == i) - p += n - _Q[j]; - // If NumericType is integral, then p % _k == 0. - // assert(!std::numeric_limits::is_integer || p % _k == 0); - return (p / NumericType(_k)) * (_wsum / n); - } - - /** - * @return the number of choices, i.e., the length of the weight vector. - **********************************************************************/ - unsigned Choices() const throw() { return _k; } - - private: - - /** - * Size of weight vector - **********************************************************************/ - unsigned _k; - /** - * Vector of cutoffs - **********************************************************************/ - std::vector _Q; - /** - * Vector of aliases - **********************************************************************/ - std::vector _Y; - /** - * The sum of the weights - **********************************************************************/ - NumericType _wsum; - /** - * The maximum weight - **********************************************************************/ - NumericType _wmax; - - }; - - template template - RandomSelect::RandomSelect(InputIterator a, InputIterator b) { - - typedef typename std::iterator_traits::value_type - WeightType; - // Disallow WeightType = real, NumericType = integer - STATIC_ASSERT(std::numeric_limits::is_integer || - !std::numeric_limits::is_integer, - "RandomSelect: inconsistent WeightType and NumericType"); - - // If WeightType and NumericType are the same type, NumericType as precise - // as WeightType - STATIC_ASSERT(std::numeric_limits::is_integer != - std::numeric_limits::is_integer || - std::numeric_limits::digits >= - std::numeric_limits::digits, - "RandomSelect: NumericType insufficiently precise"); - - _wsum = 0; - _wmax = 0; - std::vector p; - - for (InputIterator wptr = a; wptr != b; ++wptr) { - // Test *wptr < 0 without triggering compiler warning when *wptr = - // unsigned - if (!(*wptr > 0 || *wptr == 0)) - // This also catches NaNs - throw RandomErr("RandomSelect: Illegal weight"); - NumericType w = NumericType(*wptr); - if (w > (std::numeric_limits::max)() - _wsum) - throw RandomErr("RandomSelect: Overflow"); - _wsum += w; - _wmax = w > _wmax ? w : _wmax; - p.push_back(w); - } - - _k = unsigned(p.size()); - if (_wsum <= 0) - throw RandomErr("RandomSelect: Zero total weight"); - - if (_k <= 1) { - // We treat k <= 1 as a special case in operator() - _Q.clear(); - _Y.clear(); - return; - } - - if ((std::numeric_limits::max)()/NumericType(_k) < - NumericType(_wmax)) - throw RandomErr("RandomSelect: Overflow"); - - std::vector j(_k); - _Q.resize(_k); - _Y.resize(_k); - - // Pointers to the next empty low and high slots - unsigned u = 0; - unsigned v = _k - 1; - - // Scale input and store in p and setup index array j. Note _wsum = - // mean(p). We could scale out _wsum here, but the following is exact when - // w[i] are low integers. - for (unsigned i = 0; i < _k; ++i) { - p[i] *= NumericType(_k); - j[p[i] > _wsum ? v-- : u++] = i; - } - - // Pointers to the next low and high slots to use. Work towards the - // middle. This simplifies the loop exit test to u == v. - u = 0; - v = _k - 1; - - // For integer NumericType, store the unnormalized probability in _Q and - // select using the exact Prob(_Q[k], _wsum). For real NumericType, store - // the normalized probability and select using Prob(_Q[k]). There will be - // a round off error in performing the division; but there is also the - // potential for round off errors in performing the arithmetic on p. There - // is therefore no point in simulating the division exactly using the - // slower Prob(real, real). - const NumericType n = std::numeric_limits::is_integer ? - NumericType(1) : _wsum; - - while (true) { - // A loop invariant here is mean(p[j[u..v]]) == _wsum - _Q[j[u]] = p[j[u]] / n; - - // If all arithmetic were exact this assignment could be: - // if (p[j[u]] < _wsum) _Y[j[u]] = j[v]; - // But the following is safer: - _Y[j[u]] = j[p[j[u]] < _wsum ? v : u]; - - if (u == v) { - // The following assertion may fail because of roundoff errors - // assert( p[j[u]] == _wsum ); - break; - } - - // Update p, u, and v maintaining the loop invariant - p[j[v]] = p[j[v]] - (_wsum - p[j[u]]); - if (p[j[v]] > _wsum) - ++u; - else - j[u] = j[v--]; - } - return; - } - -} // namespace RandomLib - -#if defined(_MSC_VER) -# pragma warning (pop) -#endif - -#endif // RANDOMLIB_RANDOMSELECT_HPP diff --git a/include/RandomLib/RandomType.hpp b/include/RandomLib/RandomType.hpp deleted file mode 100644 index fa907e42..00000000 --- a/include/RandomLib/RandomType.hpp +++ /dev/null @@ -1,137 +0,0 @@ -/** - * \file RandomType.hpp - * \brief Class to hold bit-width and unsigned type - * - * This provides a simple class to couple a bit-width and an unsigned type - * capable of holding all the bits. In addition is offers static methods for - * I/O and checksumming. - * - * Copyright (c) Charles Karney (2006-2011) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ -#if !defined(RANDOMLIB_RANDOMTYPE_HPP) -#define RANDOMLIB_RANDOMTYPE_HPP 1 - -#include -#include -#include - -namespace RandomLib { - /** - * \brief Class to hold bit-width and unsigned type - * - * This provides a simple class to couple a bit-width and an unsigned type - * capable of holding all the bits. In addition is offers static methods for - * I/O and checksumming. - * - * @tparam bits the number of significant bits. - * @tparam UIntType the C++ unsigned integer type capable of holding the bits. - **********************************************************************/ - template - class RANDOMLIB_EXPORT RandomType { - public: - /** - * The unsigned C++ type - **********************************************************************/ - typedef UIntType type; - /** - * The number of significant bits - **********************************************************************/ - static const unsigned width = bits; - /** - * A mask for the significant bits. - **********************************************************************/ - static const type mask = - ~type(0) >> (std::numeric_limits::digits - width); - /** - * The minimum representable value - **********************************************************************/ - static const type min = type(0); - /** - * The maximum representable value - **********************************************************************/ - static const type max = mask; - /** - * A combined masking and casting operation - * - * @tparam IntType the integer type of the \e x. - * @param[in] x the input integer. - * @return the masked and casted result. - **********************************************************************/ - template static type cast(IntType x) throw() - { return type(x) & mask; } - /** - * Read a data value from a stream of 32-bit quantities (binary or text) - * - * @param[in,out] is the input stream. - * @param[in] bin true if the stream is binary. - * @param[out] x the data value read from the stream. - **********************************************************************/ - static void Read32(std::istream& is, bool bin, type& x); - /** - * Write the data value to a stream of 32-bit quantities (binary or text) - * - * @param[in,out] os the output stream. - * @param[in] bin true if the stream is binary. - * @param[in,out] cnt controls the use of spaces and newlines for text - * output. - * @param[in] x the data value to be written to the stream. - * - * \e cnt should be zero on the first invocation of a series of writes. - * This function increments it by one on each call. - **********************************************************************/ - static void Write32(std::ostream& os, bool bin, int& cnt, type x); - /** - * Accumulate a checksum of a integer into a 32-bit check. This implements - * a very simple checksum and is intended to avoid accidental corruption - * only. - * - * @param[in] n the number to be included in the checksum. - * @param[in,out] check the running checksum. - **********************************************************************/ - static void CheckSum(type n, uint32_t& check) throw(); - }; - - /** - * The standard unit for 32-bit quantities - **********************************************************************/ - typedef RandomType<32, uint32_t> Random_u32; - /** - * The standard unit for 64-bit quantities - **********************************************************************/ - typedef RandomType<64, uint64_t> Random_u64; - - /** - * The integer type of constructing bitsets. This used to be unsigned long. - * C++11 has made this unsigned long long. - **********************************************************************/ -#if defined(_MSC_VER) && _MSC_VER >= 1600 - typedef unsigned long long bitset_uint_t; -#else - typedef unsigned long bitset_uint_t; -#endif - - /// \cond SKIP - - // Accumulate a checksum of a 32-bit quantity into check - template<> - inline void Random_u32::CheckSum(Random_u32::type n, Random_u32::type& check) - throw() { - // Circular shift left by one bit and add new word. - check = (check << 1 | (check >> 31 & Random_u32::type(1))) + n; - check &= Random_u32::mask; - } - - // Accumulate a checksum of a 64-bit quantity into check - template<> - inline void Random_u64::CheckSum(Random_u64::type n, Random_u32::type& check) - throw() { - Random_u32::CheckSum(Random_u32::cast(n >> 32), check); - Random_u32::CheckSum(Random_u32::cast(n ), check); - } - /// \endcond - -} // namespace RandomLib - -#endif // RANDOMLIB_RANDOMTYPE_HPP diff --git a/include/RandomLib/UniformInteger.hpp b/include/RandomLib/UniformInteger.hpp deleted file mode 100644 index c6d267fd..00000000 --- a/include/RandomLib/UniformInteger.hpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * \file UniformInteger.hpp - * \brief Header for UniformInteger - * - * Partially sample a uniform integer distribution. - * - * Copyright (c) Charles Karney (2013) and licensed - * under the MIT/X11 License. For more information, see - * http://randomlib.sourceforge.net/ - **********************************************************************/ - -#if !defined(RANDOMLIB_UNIFORMINTEGER_HPP) -#define RANDOMLIB_UNIFORMINTEGER_HPP 1 - -#include - -namespace RandomLib { - /** - * \brief The partial uniform integer distribution. - * - * A class to sample in [0, \e m). For background, see: - * - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number - * Generation, in "Algorithms and Complexity" (Academic Press, 1976), - * pp. 357--428. - * - J. Lumbroso, Optimal Discrete Uniform Generation from Coin Flips, - * and Applications, http://arxiv.org/abs/1304.1916 (2013) - * . - * Lumbroso's algorithm is a realization of the Knuth-Yao method for the case - * of uniform probabilities. This class generalizes the method to accept - * random digits in a base, \e b = 2\e bits. An important - * additional feature is that only sufficient random digits are drawn to - * narrow the allowed range to a power of b. Thus after - * UniformInteger u(r,5), \e u represents \verbatim - range prob - [0,4) 8/15 - [0,2) 2/15 - [2,4) 2/15 - 4 1/5 \endverbatim - * u.Min() and u.Max() give the extent of the - * closed range. The number of additional random digits needed to fix the - * value is given by u.Entropy(). The comparison operations may - * require additional digits to be drawn and so the range might be narrowed - * down. If you need a definite value then use u(r). - * - * The DiscreteNormalAlt class uses UniformInteger to achieve an - * asymptotically ideal scaling wherein the number of random bits required - * per sample is constant + log2σ. If Lumbroso's algorithm - * for sampling in [0,\e m) were used the log2σ term would - * be multiplied by about 1.4. - * - * It is instructive to look at the Knuth-Yao discrete distribution - * generating (DDG) tree for the case \e m = 5 (the binary expansion of 1/5 - * is 0.00110011...); Lumbroso's algorithm implements this tree. - * \image html ky-5.png "Knuth-Yao for \e m = 5" - * - * UniformInteger collapses all of the full subtrees above to their parent - * nodes to yield this tree where now some of the outcomes are ranges. - * \image html ky-5-collapse.png "Collapsed Knuth-Yao for \e m = 5" - * - * Averaging over many samples, the maximum number of digits required to - * construct a UniformInteger, i.e., invoking - * UniformInteger(r,m), is (2\e b − 1)/(\e b − 1). - * (Note that this does not increase as \e m increases.) The maximum number - * of digits required to sample specific integers, i.e., invoking - * UniformInteger(r,m)(r), is b/(\e b − 1) + - * log\e b\e m. The worst cases are when \e m is slightly more - * than a power of \e b. - * - * The number of random bits required for sampling is shown as a function of - * the fractional part of log2\e m below. The red line shows what - * Lumbroso calls the "toll", the number of bits in excess of the entropy - * that are required for sampling. - * \image html - * uniform-bits.png "Random bits to sample in [0,\e m) for \e b = 2" - * - * @tparam IntType the type of the integer (must be signed). - * @tparam bits the number of bits in each digit used for sampling; - * the base for sampling is \e b = 2\e bits. - **********************************************************************/ - template class UniformInteger { - public: - /** - * Constructor creating a partially sampled integer in [0, \e m) - * - * @param[in] r random object. - * @param[in] m constructed object represents an integer in [0, \e m). - * @param[in] flip if true, rearrange the ranges so that the widest ones - * are at near the upper end of [0, \e m) (default false). - * - * The samples enough random digits to obtain a uniform range whose size is - * a power of the base. The range can subsequently be narrowed by sampling - * additional digits. - **********************************************************************/ - template - UniformInteger(Random& r, IntType m, bool flip = false); - /** - * @return the minimum of the current range. - **********************************************************************/ - IntType Min() const { return _a; } - /** - * @return the maximum of the current range. - **********************************************************************/ - IntType Max() const { return _a + (IntType(1) << (_l * bits)) - 1; } - /** - * @return the entropy of the current range (in units of random digits). - * - * Max() + 1 - Min() = 2Entropy() * \e bits. - **********************************************************************/ - IntType Entropy() const { return _l; } - /** - * Sample until the entropy vanishes, i.e., Min() = Max(). - * - * @return the resulting integer sample. - **********************************************************************/ - template IntType operator()(Random& r) - { while (_l) Refine(r); return _a; } - /** - * Negate the range, [Min(), Max()] → [−Max(), −Min()]. - **********************************************************************/ - void Negate() { _a = -Max(); } - /** - * Add a constant to the range - * - * @param[in] c the constant to be added. - * - * [Min(), Max()] → [Min() + \e c, Max() + \e c]. - **********************************************************************/ - void Add(IntType c) { _a += c; } - /** - * Compare with a fraction, *this < p/q - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] p the numerator of the fraction. - * @param[in] q the denominator of the fraction (require \e q > 0). - * @return true if *this < p/q. - **********************************************************************/ - // test j < p/q (require q > 0) - template bool LessThan(Random& r, IntType p, IntType q) { - for (;;) { - if ( (q * Max() < p)) return true; - if (!(q * Min() < p)) return false; - Refine(r); - } - } - /** - * Compare with a fraction, *this ≤ p/q - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] p the numerator of the fraction. - * @param[in] q the denominator of the fraction (require \e q > 0). - * @return true if *this ≤ p/q. - **********************************************************************/ - template - bool LessThanEqual(Random& r, IntType p, IntType q) - { return LessThan(r, p + 1, q); } - /** - * Compare with a fraction, *this > p/q - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] p the numerator of the fraction. - * @param[in] q the denominator of the fraction (require \e q > 0). - * @return true if *this > p/q. - **********************************************************************/ - template - bool GreaterThan(Random& r, IntType p, IntType q) - { return !LessThanEqual(r, p, q); } - /** - * Compare with a fraction, *this ≥ p/q - * - * @tparam Random the type of the random generator. - * @param[in,out] r a random generator. - * @param[in] p the numerator of the fraction. - * @param[in] q the denominator of the fraction (require \e q > 0). - * @return true if *this ≥ p/q. - **********************************************************************/ - template - bool GreaterThanEqual(Random& r, IntType p, IntType q) - { return !LessThan(r, p, q); } - /** - * Check that overflow will not happen. - * - * @param[in] mmax the largest \e m in the constructor. - * @param[in] qmax the largest \e q in LessThan(). - * @return true if overflow will not happen. - * - * It is important that this check be carried out. If overflow occurs, - * incorrect results are obtained and the constructor may never terminate. - **********************************************************************/ - static bool Check(IntType mmax, IntType qmax) { - return ( mmax - 1 <= ((std::numeric_limits::max)() >> bits) && - mmax - 1 <= (std::numeric_limits::max)() / qmax ); - } - private: - IntType _a, _l; // current range is _a + [0, 2^(bits*_l)). - template static unsigned RandomDigit(Random& r) throw() - { return unsigned(r.template Integer()); } - template void Refine(Random& r) // only gets called if _l > 0. - { _a += IntType(RandomDigit(r) << (bits * --_l)); } - }; - - template template - UniformInteger::UniformInteger(Random& r, IntType m, bool flip) - { - STATIC_ASSERT(std::numeric_limits::is_integer, - "UniformInteger: invalid integer type IntType"); - STATIC_ASSERT(std::numeric_limits::is_signed, - "UniformInteger: IntType must be a signed type"); - STATIC_ASSERT(bits > 0 && bits < std::numeric_limits::digits && - bits <= std::numeric_limits::digits, - "UniformInteger: bits out of range"); - m = m < 1 ? 1 : m; - for (IntType v = 1, c = 0;;) { - _l = 0; _a = c; - for (IntType w = v, a = c, d = 1;;) { - // play out Lumbroso's algorithm without drawing random digits with w - // playing the role of v and c represented by the range [a, a + d). - // Return if both ends of range qualify as return values at the same - // time. Otherwise, fail and draw another random digit. - if (w >= m) { - IntType j = (a / m) * m; a -= j; w -= j; - if (w >= m) { - if (a + d <= m) { _a = !flip ? a : m - a - d; return; } - break; - } - } - w <<= bits; a <<= bits; d <<= bits; ++_l; - } - IntType j = (v / m) * m; v -= j; c -= j; - v <<= bits; c <<= bits; c += IntType(RandomDigit(r)); - } - } - - /** - * \relates UniformInteger - * Print a UniformInteger. Format is [\e min,\e max] unless the entropy is - * zero, in which case it's \e val. - **********************************************************************/ - template - std::ostream& operator<<(std::ostream& os, - const UniformInteger& u) { - if (u.Entropy()) - os << "[" << u.Min() << "," << u.Max() << "]"; - else - os << u.Min(); - return os; - } - -} // namespace RandomLib - -#endif // RANDOMLIB_UNIFORMINTEGER_HPP diff --git a/include/aes256.h b/include/aes256.h new file mode 100644 index 00000000..c5a22ba1 --- /dev/null +++ b/include/aes256.h @@ -0,0 +1,42 @@ +/* +* Byte-oriented AES-256 implementation. +* All lookup tables replaced with 'on the fly' calculations. +* +* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com +* Other contributors: Hal Finney +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#ifndef uint8_t +#define uint8_t unsigned char +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct { + uint8_t key[32]; + uint8_t enckey[32]; + uint8_t deckey[32]; + } aes256_context; + + + void aes256_init(aes256_context *, uint8_t * /* key */); + void aes256_done(aes256_context *); + void aes256_encrypt_ecb(aes256_context *, uint8_t * /* plaintext */); + void aes256_decrypt_ecb(aes256_context *, uint8_t * /* cipertext */); + +#ifdef __cplusplus +} +#endif diff --git a/include/maxminddb.h b/include/maxminddb.h new file mode 100644 index 00000000..76ce9377 --- /dev/null +++ b/include/maxminddb.h @@ -0,0 +1,223 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MAXMINDDB_H +#define MAXMINDDB_H + +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +/* libmaxminddb package version from configure */ +#define PACKAGE_VERSION "1.1.4" + +typedef ADDRESS_FAMILY sa_family_t; + +#if defined(_MSC_VER) +/* MSVC doesn't define signed size_t, copy it from configure */ +#define ssize_t int + +/* MSVC doesn't support restricted pointers */ +#define restrict +#endif +#else +#include +#include +#include +#endif + +#define MMDB_DATA_TYPE_EXTENDED (0) +#define MMDB_DATA_TYPE_POINTER (1) +#define MMDB_DATA_TYPE_UTF8_STRING (2) +#define MMDB_DATA_TYPE_DOUBLE (3) +#define MMDB_DATA_TYPE_BYTES (4) +#define MMDB_DATA_TYPE_UINT16 (5) +#define MMDB_DATA_TYPE_UINT32 (6) +#define MMDB_DATA_TYPE_MAP (7) +#define MMDB_DATA_TYPE_INT32 (8) +#define MMDB_DATA_TYPE_UINT64 (9) +#define MMDB_DATA_TYPE_UINT128 (10) +#define MMDB_DATA_TYPE_ARRAY (11) +#define MMDB_DATA_TYPE_CONTAINER (12) +#define MMDB_DATA_TYPE_END_MARKER (13) +#define MMDB_DATA_TYPE_BOOLEAN (14) +#define MMDB_DATA_TYPE_FLOAT (15) + +/* flags for open */ +#define MMDB_MODE_MMAP (1) +#define MMDB_MODE_MASK (7) + +/* error codes */ +#define MMDB_SUCCESS (0) +#define MMDB_FILE_OPEN_ERROR (1) +#define MMDB_CORRUPT_SEARCH_TREE_ERROR (2) +#define MMDB_INVALID_METADATA_ERROR (3) +#define MMDB_IO_ERROR (4) +#define MMDB_OUT_OF_MEMORY_ERROR (5) +#define MMDB_UNKNOWN_DATABASE_FORMAT_ERROR (6) +#define MMDB_INVALID_DATA_ERROR (7) +#define MMDB_INVALID_LOOKUP_PATH_ERROR (8) +#define MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR (9) +#define MMDB_INVALID_NODE_NUMBER_ERROR (10) +#define MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR (11) + +#if !(MMDB_UINT128_IS_BYTE_ARRAY) +#if MMDB_UINT128_USING_MODE +typedef unsigned int mmdb_uint128_t __attribute__ ((__mode__(TI))); +#else +typedef unsigned __int128 mmdb_uint128_t; +#endif +#endif + +/* This is a pointer into the data section for a given IP address lookup */ +typedef struct MMDB_entry_s { + struct MMDB_s *mmdb; + uint32_t offset; +} MMDB_entry_s; + +typedef struct MMDB_lookup_result_s { + bool found_entry; + MMDB_entry_s entry; + uint16_t netmask; +} MMDB_lookup_result_s; + +typedef struct MMDB_entry_data_s { + bool has_data; + union { + uint32_t pointer; + const char *utf8_string; + double double_value; + const uint8_t *bytes; + uint16_t uint16; + uint32_t uint32; + int32_t int32; + uint64_t uint64; +#if MMDB_UINT128_IS_BYTE_ARRAY + uint8_t uint128[16]; +#else + mmdb_uint128_t uint128; +#endif + bool boolean; + float float_value; + }; + /* This is a 0 if a given entry cannot be found. This can only happen + * when a call to MMDB_(v)get_value() asks for hash keys or array + * indices that don't exist. */ + uint32_t offset; + /* This is the next entry in the data section, but it's really only + * relevant for entries that part of a larger map or array + * struct. There's no good reason for an end user to look at this + * directly. */ + uint32_t offset_to_next; + /* This is only valid for strings, utf8_strings or binary data */ + uint32_t data_size; + /* This is an MMDB_DATA_TYPE_* constant */ + uint32_t type; +} MMDB_entry_data_s; + +/* This is the return type when someone asks for all the entry data in a map or array */ +typedef struct MMDB_entry_data_list_s { + MMDB_entry_data_s entry_data; + struct MMDB_entry_data_list_s *next; +} MMDB_entry_data_list_s; + +typedef struct MMDB_description_s { + const char *language; + const char *description; +} MMDB_description_s; + +typedef struct MMDB_metadata_s { + uint32_t node_count; + uint16_t record_size; + uint16_t ip_version; + const char *database_type; + struct { + size_t count; + const char **names; + } languages; + uint16_t binary_format_major_version; + uint16_t binary_format_minor_version; + uint64_t build_epoch; + struct { + size_t count; + MMDB_description_s **descriptions; + } description; +} MMDB_metadata_s; + +typedef struct MMDB_ipv4_start_node_s { + uint16_t netmask; + uint32_t node_value; +} MMDB_ipv4_start_node_s; + +typedef struct MMDB_s { + uint32_t flags; + const char *filename; + ssize_t file_size; + const uint8_t *file_content; + const uint8_t *data_section; + uint32_t data_section_size; + const uint8_t *metadata_section; + uint32_t metadata_section_size; + uint16_t full_record_byte_size; + uint16_t depth; + MMDB_ipv4_start_node_s ipv4_start_node; + MMDB_metadata_s metadata; +} MMDB_s; + +typedef struct MMDB_search_node_s { + uint64_t left_record; + uint64_t right_record; +} MMDB_search_node_s; + + /* *INDENT-OFF* */ + /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ + extern int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb); + extern MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, + const char *const ipstr, + int *const gai_error, + int *const mmdb_error); + extern MMDB_lookup_result_s MMDB_lookup_sockaddr( + MMDB_s *const mmdb, + const struct sockaddr *const sockaddr, + int *const mmdb_error); + extern int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number, + MMDB_search_node_s *const node); + extern int MMDB_get_value(MMDB_entry_s *const start, + MMDB_entry_data_s *const entry_data, + ...); + extern int MMDB_vget_value(MMDB_entry_s *const start, + MMDB_entry_data_s *const entry_data, + va_list va_path); + extern int MMDB_aget_value(MMDB_entry_s *const start, + MMDB_entry_data_s *const entry_data, + const char *const *const path); + extern int MMDB_get_metadata_as_entry_data_list( + MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list); + extern int MMDB_get_entry_data_list( + MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list); + extern void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list); + extern void MMDB_close(MMDB_s *const mmdb); + extern const char *MMDB_lib_version(void); + extern int MMDB_dump_entry_data_list(FILE *const stream, + MMDB_entry_data_list_s *const entry_data_list, + int indent); + extern const char *MMDB_strerror(int error_code); + /* --prototypes end - don't remove this comment-- */ + /* *INDENT-ON* */ + +#endif /* MAXMINDDB_H */ + +#ifdef __cplusplus +} +#endif diff --git a/modules/ini/Document.cpp b/modules/ini/Document.cpp index 80925b21..85f1fb84 100644 --- a/modules/ini/Document.cpp +++ b/modules/ini/Document.cpp @@ -33,7 +33,7 @@ Int32 Document::Cmp(const Document & o) const { if (m_Doc == o.m_Doc) return 0; - else if (this > &o) + else if (m_Doc.m_Ptr > o.m_Doc.m_Ptr) return 1; else return -1; diff --git a/modules/ini/Document.hpp b/modules/ini/Document.hpp index 0d537341..b49e40ab 100644 --- a/modules/ini/Document.hpp +++ b/modules/ini/Document.hpp @@ -109,14 +109,6 @@ public: return m_Doc; } - /* -------------------------------------------------------------------------------------------- - * See whether any data has been loaded into this document. - */ - bool IsEmpty() const - { - return m_Doc->IsEmpty(); - } - /* -------------------------------------------------------------------------------------------- * Return the number of active references to this document instance. */ @@ -125,6 +117,14 @@ public: return m_Doc.Count(); } + /* -------------------------------------------------------------------------------------------- + * See whether any data has been loaded into this document. + */ + bool IsEmpty() const + { + return m_Doc->IsEmpty(); + } + /* -------------------------------------------------------------------------------------------- * Deallocate all memory stored by this document. */ diff --git a/modules/ini/Entries.cpp b/modules/ini/Entries.cpp index 10c55bba..84fa654e 100644 --- a/modules/ini/Entries.cpp +++ b/modules/ini/Entries.cpp @@ -18,7 +18,7 @@ Int32 Entries::Cmp(const Entries & o) const { if (m_Elem == o.m_Elem) return 0; - else if (this > &o) + else if (m_List.size() > o.m_List.size()) return 1; else return -1; diff --git a/modules/mmdb/Common.cpp b/modules/mmdb/Common.cpp new file mode 100644 index 00000000..4dd512bd --- /dev/null +++ b/modules/mmdb/Common.cpp @@ -0,0 +1,120 @@ +// ------------------------------------------------------------------------------------------------ +#include "Common.hpp" +#include "Module.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include +#include +#include + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +static SQChar g_Buffer[4096]; // Common buffer to reduce memory allocations. + +// ------------------------------------------------------------------------------------------------ +SStr GetTempBuff() +{ + return g_Buffer; +} + +// ------------------------------------------------------------------------------------------------ +Uint32 GetTempBuffSize() +{ + return sizeof(g_Buffer); +} + +// ------------------------------------------------------------------------------------------------ +void SqThrowF(CSStr str, ...) +{ + // Initialize the argument list + va_list args; + va_start (args, str); + // Write the requested contents + if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0) + strcpy(g_Buffer, "Unknown error has occurred"); + // Release the argument list + va_end(args); + // Throw the exception with the resulted message + throw Sqrat::Exception(g_Buffer); +} + +// ------------------------------------------------------------------------------------------------ +CSStr FmtStr(CSStr str, ...) +{ + // Initialize the argument list + va_list args; + va_start (args, str); + // Write the requested contents + if (snprintf(g_Buffer, sizeof(g_Buffer), str, args) < 0) + g_Buffer[0] = 0; /* make sure the string is terminated */ + // Release the argument list + va_end(args); + // Return the data from the buffer + return g_Buffer; +} + +// ------------------------------------------------------------------------------------------------ +StackGuard::StackGuard(HSQUIRRELVM vm) + : m_Top(sq_gettop(vm)), m_VM(vm) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +StackGuard::~StackGuard() +{ + sq_pop(m_VM, sq_gettop(m_VM) - m_Top); +} + +// ------------------------------------------------------------------------------------------------ +DbRef::Pointer DbRef::Create() +{ + return reinterpret_cast< Pointer >(malloc(sizeof(Type))); +} + +// ------------------------------------------------------------------------------------------------ +void DbRef::Destroy(Pointer db) +{ + if (db) + free(db); +} + +// ------------------------------------------------------------------------------------------------ +const char NumLimit< char >::Min = CHAR_MIN; +const signed char NumLimit< signed char >::Min = SCHAR_MIN; +const unsigned char NumLimit< unsigned char >::Min = 0; +const signed short NumLimit< signed short >::Min = SHRT_MIN; +const unsigned short NumLimit< unsigned short >::Min = 0; +const signed int NumLimit< signed int >::Min = INT_MIN; +const unsigned int NumLimit< unsigned int >::Min = 0; +const signed long NumLimit< signed long >::Min = LONG_MIN; +const unsigned long NumLimit< unsigned long >::Min = 0; +const signed long long NumLimit< signed long long >::Min = LLONG_MIN; +const unsigned long long NumLimit< unsigned long long >::Min = 0; +const float NumLimit< float >::Min = FLT_MIN; +const double NumLimit< double >::Min = DBL_MIN; +const long double NumLimit< long double >::Min = LDBL_MIN; + +// ------------------------------------------------------------------------------------------------ +const char NumLimit< char >::Max = CHAR_MAX; +const signed char NumLimit< signed char >::Max = SCHAR_MAX; +const unsigned char NumLimit< unsigned char >::Max = UCHAR_MAX; +const signed short NumLimit< signed short >::Max = SHRT_MAX; +const unsigned short NumLimit< unsigned short >::Max = USHRT_MAX; +const signed int NumLimit< signed int >::Max = INT_MAX; +const unsigned int NumLimit< unsigned int >::Max = UINT_MAX; +const signed long NumLimit< signed long >::Max = LONG_MAX; +const unsigned long NumLimit< unsigned long >::Max = ULONG_MAX; +const signed long long NumLimit< signed long long >::Max = LLONG_MAX; +const unsigned long long NumLimit< unsigned long long >::Max = ULLONG_MAX; +const float NumLimit< float >::Max = FLT_MAX; +const double NumLimit< double >::Max = DBL_MAX; +const long double NumLimit< long double >::Max = LDBL_MAX; + +} // Namespace:: SqMod diff --git a/modules/mmdb/Common.hpp b/modules/mmdb/Common.hpp new file mode 100644 index 00000000..e95bf893 --- /dev/null +++ b/modules/mmdb/Common.hpp @@ -0,0 +1,453 @@ +#ifndef _SQMMDB_COMMON_HPP_ +#define _SQMMDB_COMMON_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "ModBase.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * SOFTWARE INFORMATION +*/ +#define SQMMDB_NAME "Squirrel MaxmindDB Module" +#define SQMMDB_AUTHOR "Sandu Liviu Catalin (S.L.C)" +#define SQMMDB_COPYRIGHT "Copyright (C) 2016 Sandu Liviu Catalin" +#define SQMMDB_HOST_NAME "SqModMMDBHost" +#define SQMMDB_VERSION 001 +#define SQMMDB_VERSION_STR "0.0.1" +#define SQMMDB_VERSION_MAJOR 0 +#define SQMMDB_VERSION_MINOR 0 +#define SQMMDB_VERSION_PATCH 1 + +/* ------------------------------------------------------------------------------------------------ + * Forward declarations. +*/ +class Database; +class SockAddr; +class EntryDataList; +class LookupResult; + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the temporary buffer. +*/ +SStr GetTempBuff(); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the size of the temporary buffer. +*/ +Uint32 GetTempBuffSize(); + +/* ------------------------------------------------------------------------------------------------ + * Throw a formatted exception. +*/ +void SqThrowF(CSStr str, ...); + +/* ------------------------------------------------------------------------------------------------ + * Generate a formatted string. +*/ +CSStr FmtStr(CSStr str, ...); + +/* ------------------------------------------------------------------------------------------------ + * Implements RAII to restore the VM stack to it's initial size on function exit. +*/ +struct StackGuard +{ + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + StackGuard(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~StackGuard(); + +private: + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + StackGuard(const StackGuard &); + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + StackGuard(StackGuard &&); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + StackGuard & operator = (const StackGuard &); + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + StackGuard & operator = (StackGuard &&); + +private: + + // -------------------------------------------------------------------------------------------- + Int32 m_Top; /* The top of the stack when this instance was created. */ + HSQUIRRELVM m_VM; /* The VM where the stack should be restored. */ +}; + +/* ------------------------------------------------------------------------------------------------ + * Manages a reference counted INI document instance. +*/ +class DbRef +{ + // -------------------------------------------------------------------------------------------- + friend class Database; + +public: + + // -------------------------------------------------------------------------------------------- + typedef MMDB_s Type; // The managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type* Pointer; // Pointer to the managed type. + typedef const Type* ConstPtr; // Constant pointer to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type& Reference; // Reference to the managed type. + typedef const Type& ConstRef; // Constant reference to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef unsigned int Counter; // Reference counter type. + +private: + + // -------------------------------------------------------------------------------------------- + Pointer m_Ptr; // The document reader, writer and manager instance. + Counter* m_Ref; // Reference count to the managed instance. + + /* -------------------------------------------------------------------------------------------- + * Creates a database structure. + */ + static Pointer Create(); + + /* -------------------------------------------------------------------------------------------- + * Destroyes the specified database structure. + */ + static void Destroy(Pointer db); + + /* -------------------------------------------------------------------------------------------- + * Grab a strong reference to a document instance. + */ + void Grab() + { + if (m_Ptr) + ++(*m_Ref); + } + + /* -------------------------------------------------------------------------------------------- + * Drop a strong reference to a document instance. + */ + void Drop() + { + if (m_Ptr && --(*m_Ref) == 0) + { + MMDB_close(m_Ptr); + Destroy(m_Ptr); + delete m_Ref; + m_Ptr = NULL; + m_Ref = NULL; + } + } + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + DbRef(bool make) + : m_Ptr(make ? Create() : NULL), m_Ref(m_Ptr ? new Counter(1) : NULL) + { + /* ... */ + } + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor (null). + */ + DbRef() + : m_Ptr(NULL), m_Ref(NULL) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + DbRef(const DbRef & o) + : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref) + + { + Grab(); + } + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + DbRef(DbRef && o) + : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref) + + { + o.m_Ptr = NULL; + o.m_Ref = NULL; + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~DbRef() + { + Drop(); + } + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + DbRef & operator = (const DbRef & o) + { + if (m_Ptr != o.m_Ptr) + { + Drop(); + m_Ptr = o.m_Ptr; + m_Ref = o.m_Ref; + Grab(); + } + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + DbRef & operator = (DbRef && o) + { + if (m_Ptr != o.m_Ptr) + { + m_Ptr = o.m_Ptr; + m_Ref = o.m_Ref; + o.m_Ptr = NULL; + o.m_Ref = NULL; + } + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Perform an equality comparison between two document instances. + */ + bool operator == (const DbRef & o) const + { + return (m_Ptr == o.m_Ptr); + } + + /* -------------------------------------------------------------------------------------------- + * Perform an inequality comparison between two document instances. + */ + bool operator != (const DbRef & o) const + { + return (m_Ptr != o.m_Ptr); + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to boolean for use in boolean operations. + */ + operator bool () const + { + return m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the managed instance pointer. + */ + operator Pointer () + { + return m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the managed instance pointer. + */ + operator ConstPtr () const + { + return m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the managed instance reference. + */ + operator Reference () + { + assert(m_Ptr); + return *m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the managed instance reference. + */ + operator ConstRef () const + { + assert(m_Ptr); + return *m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Member operator for dereferencing the managed pointer. + */ + Pointer operator -> () const + { + assert(m_Ptr); + return m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Indirection operator for obtaining a reference of the managed pointer. + */ + Reference operator * () const + { + assert(m_Ptr); + return *m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the raw handle structure pointer. + */ + Pointer DbPtr() + { + return m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the raw handle structure pointer. + */ + Pointer DbPtr() const + { + return m_Ptr; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of active references to the managed instance. + */ + Counter Count() const + { + return (m_Ptr && m_Ref) ? (*m_Ref) : 0; + } +}; + +// ------------------------------------------------------------------------------------------------ +template < typename T > struct NumLimit; + +// ------------------------------------------------------------------------------------------------ +template <> struct NumLimit< char > { static const char Min, Max; }; +template <> struct NumLimit< signed char > { static const signed char Min, Max; }; +template <> struct NumLimit< unsigned char > { static const unsigned char Min, Max; }; +template <> struct NumLimit< signed short > { static const signed short Min, Max; }; +template <> struct NumLimit< unsigned short > { static const unsigned short Min, Max; }; +template <> struct NumLimit< signed int > { static const signed int Min, Max; }; +template <> struct NumLimit< unsigned int > { static const unsigned int Min, Max; }; +template <> struct NumLimit< signed long > { static const signed long Min, Max; }; +template <> struct NumLimit< unsigned long > { static const unsigned long Min, Max; }; +template <> struct NumLimit< signed long long > { static const signed long long Min, Max; }; +template <> struct NumLimit< unsigned long long > { static const unsigned long long Min, Max; }; +template <> struct NumLimit< float > { static const float Min, Max; }; +template <> struct NumLimit< double > { static const double Min, Max; }; +template <> struct NumLimit< long double > { static const long double Min, Max; }; + +// ------------------------------------------------------------------------------------------------ +template< typename T > inline bool EpsEq(const T a, const T b) +{ + return abs(a - b) <= 0; +} + +template <> inline bool EpsEq(const Float32 a, const Float32 b) +{ + return fabs(a - b) <= 0.000001f; +} + +template <> inline bool EpsEq(const Float64 a, const Float64 b) +{ + return fabs(a - b) <= 0.000000001d; +} + +// ------------------------------------------------------------------------------------------------ +template< typename T > inline bool EpsLt(const T a, const T b) +{ + return !EpsEq(a, b) && (a < b); +} + +template <> inline bool EpsLt(const Float32 a, const Float32 b) +{ + return !EpsEq(a, b) && (a - b) < 0.000001f; +} + +template <> inline bool EpsLt(const Float64 a, const Float64 b) +{ + return !EpsEq(a, b) && (a - b) < 0.000000001d; +} + +// ------------------------------------------------------------------------------------------------ +template< typename T > inline bool EpsGt(const T a, const T b) +{ + return !EpsEq(a, b) && (a > b); +} + +template <> inline bool EpsGt(const Float32 a, const Float32 b) +{ + return !EpsEq(a, b) && (a - b) > 0.000001f; +} + +template <> inline bool EpsGt(const Float64 a, const Float64 b) +{ + return !EpsEq(a, b) && (a - b) > 0.000000001d; +} + +// ------------------------------------------------------------------------------------------------ +template< typename T > inline bool EpsLtEq(const T a, const T b) +{ + return !EpsEq(a, b) || (a < b); +} + +template <> inline bool EpsLtEq(const Float32 a, const Float32 b) +{ + return !EpsEq(a, b) || (a - b) < 0.000001f; +} + +template <> inline bool EpsLtEq(const Float64 a, const Float64 b) +{ + return !EpsEq(a, b) || (a - b) < 0.000000001d; +} + +// ------------------------------------------------------------------------------------------------ +template< typename T > inline bool EpsGtEq(const T a, const T b) +{ + return !EpsEq(a, b) || (a > b); +} + +template <> inline bool EpsGtEq(const Float32 a, const Float32 b) +{ + return !EpsEq(a, b) || (a - b) > 0.000001f; +} + +template <> inline bool EpsGtEq(const Float64 a, const Float64 b) +{ + return !EpsEq(a, b) || (a - b) > 0.000000001d; +} + +// ------------------------------------------------------------------------------------------------ +template< typename T > inline T Clamp(T val, T min, T max) +{ + return val < min ? min : (val > max ? max : val); +} + +} // Namespace:: SqMod + +#endif // _SQMMDB_COMMON_HPP_ diff --git a/modules/mmdb/Database.cpp b/modules/mmdb/Database.cpp new file mode 100644 index 00000000..730a7409 --- /dev/null +++ b/modules/mmdb/Database.cpp @@ -0,0 +1,116 @@ +// ------------------------------------------------------------------------------------------------ +#include "Database.hpp" +#include "SockAddr.hpp" +#include "LookupResult.hpp" +#include "Module.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger Database::Typename(HSQUIRRELVM vm) +{ + static const SQChar name[] = _SC("SqMMDBDatabase"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + +// ------------------------------------------------------------------------------------------------ +void Database::Validate() const +{ + // Is the document handle valid? + if (!m_Db) + SqThrowF("Invalid Maxmind database reference"); +} + +// ------------------------------------------------------------------------------------------------ +Int32 Database::Cmp(const Database & o) const +{ + if (m_Db == o.m_Db) + return 0; + else if (m_Db.m_Ptr > o.m_Db.m_Ptr) + return 1; + else + return -1; +} + +// ------------------------------------------------------------------------------------------------ +void Database::Open(CSStr filepath) +{ + Open(filepath, 0); +} + +// ------------------------------------------------------------------------------------------------ +void Database::Open(CSStr filepath, Uint32 flags) +{ + // Is there a database handle available? + if (!m_Db) + m_Db = DbRef(true); // Create a database handle + // Check if the database handle could be allocated one more time + if (!m_Db) + SqThrowF("Unable to create a Maxmind database reference"); + // Are there any other references? + else if (m_Db.Count() > 1) + // To load new values now, would mean to cause undefined behavior in existing references + SqThrowF("Loading is disabled while database is referenced"); + // Validate the specified file path + else if (!filepath || strlen(filepath) <= 0) + SqThrowF("Invalid database file path"); + // Let's attempt to open the specified database + const Int32 status = MMDB_open(filepath, flags, m_Db.m_Ptr); + // Validate the result of the operation + if (status != MMDB_SUCCESS) + { + // Release the database reference + m_Db.Drop(); + // Now it's safe to throw the error + SqThrowF("Unable to open the specified database [%s]", MMDB_strerror(status)); + } +} + +// ------------------------------------------------------------------------------------------------ +LookupResult Database::LookupString(CSStr addr) +{ + // Validate the database handle + Validate(); + // Validate the specified string + if (!addr || strlen(addr) <= 0) + SqThrowF("Invalid address string"); + // Dummy variables to obtain the status codes + int gai_error, mmdb_error; + // Attempt to perform the actual lookup + MMDB_lookup_result_s result = MMDB_lookup_string(m_Db, addr, &gai_error, &mmdb_error); + // Validate the result of the getaddrinfo() function call + if (gai_error != 0) + SqThrowF("Unable to resolve address (%s) because [%s]", addr, gai_strerror(gai_error)); + // Validate the lookup status code + else if (mmdb_error != MMDB_SUCCESS) + SqThrowF("Unable to lookup address (%s) because [%s]", addr, MMDB_strerror(mmdb_error)); + // Now it's safe to return the lookup result + return LookupResult(m_Db, result); +} + +// ------------------------------------------------------------------------------------------------ +LookupResult Database::LookupSockAddr(SockAddr & addr) +{ + // Validate the database handle + Validate(); + // Validate the specified socket address + if (!addr.IsValid()) + SqThrowF("Invalid address instance"); + // Dummy variable to obtain the status codes + int mmdb_error; + // Attempt to perform the actual lookup + MMDB_lookup_result_s result = MMDB_lookup_sockaddr(m_Db, addr.GetHandle()->ai_addr, &mmdb_error); + // Validate the lookup status code + if (mmdb_error != MMDB_SUCCESS) + SqThrowF("Unable to lookup address (%s) because [%s]", + addr.GetAddress(), MMDB_strerror(mmdb_error)); + // Now it's safe to return the lookup result + return LookupResult(m_Db, result); +} + +} // Namespace:: SqMod diff --git a/modules/mmdb/Database.hpp b/modules/mmdb/Database.hpp new file mode 100644 index 00000000..7cac2749 --- /dev/null +++ b/modules/mmdb/Database.hpp @@ -0,0 +1,132 @@ +#ifndef _SQMMDB_DATABASE_HPP_ +#define _SQMMDB_DATABASE_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Class that can read/write and alter the contents of INI files. +*/ +class Database +{ +protected: + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + Database(const Database &); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + Database & operator = (const Database &); + + /* -------------------------------------------------------------------------------------------- + * Validate the document reference and throw an error if invalid. + */ + void Validate() const; + +private: + + // --------------------------------------------------------------------------------------------- + DbRef m_Db; /* The main INI document instance. */ + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + Database() + : m_Db() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + Database(CSStr filepath) + : m_Db() + { + Open(filepath, 0); + } + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + Database(CSStr filepath, Uint32 flags) + : m_Db() + { + Open(filepath, flags); + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~Database() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const Database & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const + { + return _SC(""); + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * See whether this instance references a valid INI document. + */ + bool IsValid() const + { + return m_Db; + } + + /* -------------------------------------------------------------------------------------------- + * Return the number of active references to this document instance. + */ + Uint32 GetRefCount() const + { + return m_Db.Count(); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to open the specified database. + */ + void Open(CSStr filepath); + + /* -------------------------------------------------------------------------------------------- + * Attempt to open the specified database. + */ + void Open(CSStr filepath, Uint32 addr); + + /* -------------------------------------------------------------------------------------------- + * Look up an IP address that is passed in as a null-terminated string. + */ + LookupResult LookupString(CSStr addr); + + /* -------------------------------------------------------------------------------------------- + * Looks up an IP address that has already been resolved by getaddrinfo(). + */ + LookupResult LookupSockAddr(SockAddr & sockaddr); + +}; + +} // Namespace:: SqMod + +#endif // _SQMMDB_DATABASE_HPP_ diff --git a/modules/mmdb/EntryDataList.cpp b/modules/mmdb/EntryDataList.cpp new file mode 100644 index 00000000..d1e9abd2 --- /dev/null +++ b/modules/mmdb/EntryDataList.cpp @@ -0,0 +1,382 @@ +// ------------------------------------------------------------------------------------------------ +#include "EntryDataList.hpp" +#include "Module.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger EntryDataList::Typename(HSQUIRRELVM vm) +{ + static const SQChar name[] = _SC("SqMMDBEntryDataList"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + +// ------------------------------------------------------------------------------------------------ +void EntryDataList::Validate() const +{ + // Is the document handle valid? + if (!m_Db) + SqThrowF("Invalid Maxmind database reference"); + // Do we have a valid list? + else if (!m_List) + SqThrowF("Invalid entry data list"); +} + +// ------------------------------------------------------------------------------------------------ +void EntryDataList::ValidateElem() const +{ + // Is the document handle valid? + if (!m_Db) + SqThrowF("Invalid Maxmind database reference"); + // Do we have a valid list? + else if (!m_List) + SqThrowF("Invalid entry data list"); + // Do we have a valid element? + else if (!m_Elem) + SqThrowF("Invalid entry data element"); +} + +// ------------------------------------------------------------------------------------------------ +void EntryDataList::ValidateData() const +{ + // Is the document handle valid? + if (!m_Db) + SqThrowF("Invalid Maxmind database reference"); + // Do we have a valid list? + else if (!m_List) + SqThrowF("Invalid entry data list"); + // Do we have a valid element? + else if (!m_Elem) + SqThrowF("Invalid entry data element"); + // Do we have some valid data? + else if (!m_Elem->entry_data.has_data) + SqThrowF("Entry data element has no data"); +} + +// ------------------------------------------------------------------------------------------------ +CSStr EntryDataList::AsTypeStr(Uint32 id) +{ + switch (id) + { + case MMDB_DATA_TYPE_EXTENDED: return _SC("extended"); + case MMDB_DATA_TYPE_POINTER: return _SC("pointer"); + case MMDB_DATA_TYPE_UTF8_STRING: return _SC("string"); + case MMDB_DATA_TYPE_DOUBLE: return _SC("double"); + case MMDB_DATA_TYPE_BYTES: return _SC("bytes"); + case MMDB_DATA_TYPE_UINT16: return _SC("uint16"); + case MMDB_DATA_TYPE_UINT32: return _SC("uint32"); + case MMDB_DATA_TYPE_MAP: return _SC("map"); + case MMDB_DATA_TYPE_INT32: return _SC("int32"); + case MMDB_DATA_TYPE_UINT64: return _SC("uint64"); + case MMDB_DATA_TYPE_UINT128: return _SC("uint128"); + case MMDB_DATA_TYPE_ARRAY: return _SC("array"); + case MMDB_DATA_TYPE_CONTAINER: return _SC("container"); + case MMDB_DATA_TYPE_END_MARKER: return _SC("endmarker"); + case MMDB_DATA_TYPE_BOOLEAN: return _SC("boolean"); + case MMDB_DATA_TYPE_FLOAT: return _SC("float"); + default: return _SC("unknonw"); + } +} + +// ------------------------------------------------------------------------------------------------ +EntryDataList::~EntryDataList() +{ + // Do we have to free any list? + if (m_List) + MMDB_free_entry_data_list(m_List); +} + +// ------------------------------------------------------------------------------------------------ +Int32 EntryDataList::Cmp(const EntryDataList & o) const +{ + if (m_List == o.m_List) + return 0; + else if (m_List > o.m_List) + return 1; + else + return -1; +} + +// ------------------------------------------------------------------------------------------------ +Uint32 EntryDataList::GetCount() const +{ + // Do we even have a list? + if (!m_List) + return 0; + // Get the start of the list + Pointer elem = m_List; + // Prepare a counter + Uint32 count = 1; + // Loop through list elements + while ((elem = elem->next)) ++count; + // Return the counter + return count; +} + +// ------------------------------------------------------------------------------------------------ +bool EntryDataList::Next() +{ + // Validate the database and list handle + Validate(); + // Do we have a valid element currently? + if (m_Elem) + return (m_Elem = m_Elem->next); + // Nothing to advance + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool EntryDataList::Advance(Int32 n) +{ + // Validate the database and list handle + Validate(); + // Do we have a valid element currently? + if (m_Elem) + // Attempt to skip as many elements as possible + while ((n > 0) && (m_Elem = m_Elem->next)) --n; + // Return whether we have a valid element + return m_Elem; +} + +// ------------------------------------------------------------------------------------------------ +void EntryDataList::Reset() +{ + // Validate the database and list handle + Validate(); + // Go back to the first element + m_Elem = m_List; +} + +// ------------------------------------------------------------------------------------------------ +CSStr EntryDataList::GetString() const +{ + // Validate the database, list and element handle + ValidateData(); + // Attempt to perform the requested conversion + switch (m_Elem->entry_data.type) + { + case MMDB_DATA_TYPE_UTF8_STRING: + return m_Elem->entry_data.utf8_string; + case MMDB_DATA_TYPE_DOUBLE: + return FmtStr("%f", m_Elem->entry_data.double_value); + case MMDB_DATA_TYPE_UINT16: + return FmtStr("%u", m_Elem->entry_data.uint16); + case MMDB_DATA_TYPE_UINT32: + return FmtStr("%u", m_Elem->entry_data.uint32); + case MMDB_DATA_TYPE_INT32: + return FmtStr("%d", m_Elem->entry_data.int32); + case MMDB_DATA_TYPE_UINT64: + return FmtStr("%llu", m_Elem->entry_data.uint64); + case MMDB_DATA_TYPE_BOOLEAN: + return m_Elem->entry_data.boolean ? _SC("true") : _SC("false"); + case MMDB_DATA_TYPE_FLOAT: + return FmtStr("%f", m_Elem->entry_data.float_value); + default: + SqThrowF("Unsupported conversion from (%s) to (string)", AsTypeStr(m_Elem->entry_data.type)); + } + // Shouldn't really reach this point + return _SC(""); +} + +// ------------------------------------------------------------------------------------------------ +SQInteger EntryDataList::GetInteger() const +{ + // Validate the database, list and element handle + ValidateData(); + // Attempt to perform the requested conversion + switch (m_Elem->entry_data.type) + { +#ifdef _SQ64 + case MMDB_DATA_TYPE_UTF8_STRING: + return strtoll(m_Elem->entry_data.utf8_string, NULL, 10); + case MMDB_DATA_TYPE_DOUBLE: + return llround(m_Elem->entry_data.double_value); + case MMDB_DATA_TYPE_UINT16: + return m_Elem->entry_data.uint16; + case MMDB_DATA_TYPE_UINT32: + return m_Elem->entry_data.uint32; + case MMDB_DATA_TYPE_INT32: + return m_Elem->entry_data.int32; + case MMDB_DATA_TYPE_UINT64: + return Clamp(m_Elem->entry_data.uint64, 0, Uint64(NumLimit< SQInteger >::Max)); + case MMDB_DATA_TYPE_BOOLEAN: + return m_Elem->entry_data.boolean ? 1 : 0; + case MMDB_DATA_TYPE_FLOAT: + return llround(m_Elem->entry_data.float_value); + default: + SqThrowF("Unsupported conversion from (%s) to (int32)", AsTypeStr(m_Elem->entry_data.type)); +#else + case MMDB_DATA_TYPE_UTF8_STRING: + return strtol(m_Elem->entry_data.utf8_string, NULL, 10); + case MMDB_DATA_TYPE_DOUBLE: + return lround(m_Elem->entry_data.double_value); + case MMDB_DATA_TYPE_UINT16: + return m_Elem->entry_data.uint16; + case MMDB_DATA_TYPE_UINT32: + return Clamp(m_Elem->entry_data.uint32, 0U, Uint32(NumLimit< SQInteger >::Max)); + case MMDB_DATA_TYPE_INT32: + return m_Elem->entry_data.int32; + case MMDB_DATA_TYPE_UINT64: + return Clamp(m_Elem->entry_data.uint64, 0ULL, Uint64(NumLimit< SQInteger >::Max)); + case MMDB_DATA_TYPE_BOOLEAN: + return m_Elem->entry_data.boolean ? 1 : 0; + case MMDB_DATA_TYPE_FLOAT: + return lround(m_Elem->entry_data.float_value); + default: + SqThrowF("Unsupported conversion from (%s) to (int64)", AsTypeStr(m_Elem->entry_data.type)); +#endif // _SQ64 + } + // Shouldn't really reach this point + return 0; +} + +// ------------------------------------------------------------------------------------------------ +SQFloat EntryDataList::GetFloat() const +{ + // Validate the database, list and element handle + ValidateData(); + // Attempt to perform the requested conversion + switch (m_Elem->entry_data.type) + { +#ifdef SQUSEDOUBLE + case MMDB_DATA_TYPE_UTF8_STRING: + return static_cast< SQFloat >(strtod(m_Elem->entry_data.utf8_string, NULL)); +#else + return static_cast< SQFloat >(strtof(m_Elem->entry_data.utf8_string, NULL)); +#endif // SQUSEDOUBLE + case MMDB_DATA_TYPE_DOUBLE: + return static_cast< SQFloat >(m_Elem->entry_data.double_value); + case MMDB_DATA_TYPE_UINT16: + return static_cast< SQFloat >(m_Elem->entry_data.uint16); + case MMDB_DATA_TYPE_UINT32: + return static_cast< SQFloat >(round(m_Elem->entry_data.uint32)); + case MMDB_DATA_TYPE_INT32: + return static_cast< SQFloat >(round(m_Elem->entry_data.int32)); + case MMDB_DATA_TYPE_UINT64: + return static_cast< SQFloat >(round(m_Elem->entry_data.uint64)); + case MMDB_DATA_TYPE_BOOLEAN: + return m_Elem->entry_data.boolean ? 1.0 : 0.0; + case MMDB_DATA_TYPE_FLOAT: + return static_cast< SQFloat >(m_Elem->entry_data.float_value); + default: + SqThrowF("Unsupported conversion from (%s) to (float)", AsTypeStr(m_Elem->entry_data.type)); + } + // Shouldn't really reach this point + return 0.0; +} + +// ------------------------------------------------------------------------------------------------ +Object EntryDataList::GetLong() const +{ + // Validate the database, list and element handle + ValidateData(); + // Where the long number is retrieved + Uint64 longint = 0; + Int64 slong = 0; + // Attempt to perform the requested conversion + switch (m_Elem->entry_data.type) + { + case MMDB_DATA_TYPE_UTF8_STRING: + longint = strtoull(m_Elem->entry_data.utf8_string, NULL, 10); + break; + case MMDB_DATA_TYPE_DOUBLE: + { + slong = llround(m_Elem->entry_data.double_value); + longint = slong >= 0 ? slong : 0; + } break; + case MMDB_DATA_TYPE_UINT16: + longint = m_Elem->entry_data.uint16; + break; + case MMDB_DATA_TYPE_UINT32: + longint = m_Elem->entry_data.uint32; + break; + case MMDB_DATA_TYPE_INT32: + longint = m_Elem->entry_data.int32 >= 0 ? m_Elem->entry_data.int32 : 0; + break; + case MMDB_DATA_TYPE_UINT64: + longint = m_Elem->entry_data.uint64; + break; + case MMDB_DATA_TYPE_BOOLEAN: + longint = m_Elem->entry_data.boolean ? 1 : 0; + break; + case MMDB_DATA_TYPE_FLOAT: + { + slong = llround(m_Elem->entry_data.float_value); + longint = slong >= 0 ? slong : 0; + } + break; + default: + SqThrowF("Unsupported conversion from (%s) to (uint64)", AsTypeStr(m_Elem->entry_data.type)); + } + // Obtain the initial stack size + const StackGuard sg(_SqVM); + // Push a long integer instance with the requested value on the stack + _SqMod->PushULongObject(_SqVM, longint); + // Get the object from the stack and return it + return Var< Object >(_SqVM, -1).value; +} + +// ------------------------------------------------------------------------------------------------ +bool EntryDataList::GetBool() const +{ + // Validate the database, list and element handle + ValidateData(); + // Attempt to perform the requested conversion + switch (m_Elem->entry_data.type) + { + case MMDB_DATA_TYPE_UTF8_STRING: + return !!(m_Elem->entry_data.utf8_string); + case MMDB_DATA_TYPE_DOUBLE: + return EpsGt(m_Elem->entry_data.double_value, 0.0d); + case MMDB_DATA_TYPE_UINT16: + return (m_Elem->entry_data.uint16 > 0); + case MMDB_DATA_TYPE_UINT32: + return (m_Elem->entry_data.uint32 > 0); + case MMDB_DATA_TYPE_INT32: + return (m_Elem->entry_data.int32 > 0); + case MMDB_DATA_TYPE_UINT64: + return (m_Elem->entry_data.uint64 > 0); + case MMDB_DATA_TYPE_BOOLEAN: + return m_Elem->entry_data.boolean; + case MMDB_DATA_TYPE_FLOAT: + return EpsGt(m_Elem->entry_data.float_value, 0.0f); + default: + SqThrowF("Unsupported conversion from (%s) to (boolean)", AsTypeStr(m_Elem->entry_data.type)); + } + // Shouldn't really reach this point + return false; +} + +// ------------------------------------------------------------------------------------------------ +void EntryDataList::DumpTo(CSStr filepath, Int32 indent) const +{ + // Validate the database and list handle + Validate(); + // Validate the specified file path + if (!filepath || strlen(filepath) <= 0) + SqThrowF("Invalid file path"); + // Attempt to open the specified file + FILE * fp = fopen(filepath, "w"); + // Validate the file handle + if (!fp) + SqThrowF("Unable to open file %s", filepath); + // Attempt to dump the entry data list + Int32 status = MMDB_dump_entry_data_list(fp, m_List, indent); + // Close the file handle + fclose(fp); + // Validate the result of the operation + if (status != MMDB_SUCCESS) + // Now it's safe to throw the error + SqThrowF("Unable to dump the list [%s]", MMDB_strerror(status)); +} + +} // Namespace:: SqMod diff --git a/modules/mmdb/EntryDataList.hpp b/modules/mmdb/EntryDataList.hpp new file mode 100644 index 00000000..3fa26638 --- /dev/null +++ b/modules/mmdb/EntryDataList.hpp @@ -0,0 +1,291 @@ +#ifndef _SQMMDB_LOOKUPRESULT_HPP_ +#define _SQMMDB_LOOKUPRESULT_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Class that can be used to traverse a list of results. +*/ +class EntryDataList +{ +protected: + + // -------------------------------------------------------------------------------------------- + typedef MMDB_entry_data_list_s Type; // The managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type* Pointer; // Pointer to the managed type. + typedef const Type* ConstPtr; // Constant pointer to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type& Reference; // Reference to the managed type. + typedef const Type& ConstRef; // Constant reference to the managed type. + + /* -------------------------------------------------------------------------------------------- + * Validate the database pointer and list handle and throw an error if invalid. + */ + void Validate() const; + + /* -------------------------------------------------------------------------------------------- + * Do a regular validation and also validate the currently processed element. + */ + void ValidateElem() const; + + /* -------------------------------------------------------------------------------------------- + * Do a regular validation and also validate the currently processed element data. + */ + void ValidateData() const; + + /* -------------------------------------------------------------------------------------------- + * Used to retrieve the string representation of the specified type identifier. + */ + static CSStr AsTypeStr(Uint32 id); + +private: + + // --------------------------------------------------------------------------------------------- + DbRef m_Db; /* The database from which this list comes from. */ + Pointer m_List; /* The managed entry data list. */ + Pointer m_Elem; /* The currently processed element from the list. */ + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + EntryDataList(const DbRef & db, Pointer list) + : m_Db(db), m_List(list), m_Elem(list) + { + /* ... */ + } + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + EntryDataList(); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + EntryDataList(const EntryDataList &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + EntryDataList(EntryDataList && o) + : m_Db(o.m_Db) + , m_List(o.m_List) + , m_Elem(o.m_Elem) + { + o.m_List = nullptr; + o.m_Elem = nullptr; + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~EntryDataList(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + EntryDataList & operator = (const EntryDataList &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + EntryDataList & operator = (EntryDataList && o) + { + if (m_List != o.m_List) + { + m_Db = o.m_Db; + m_List = o.m_List; + m_Elem = o.m_Elem; + o.m_List = nullptr; + o.m_Elem = nullptr; + } + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal entry data list structure pointer. + */ + Pointer GetHandle() + { + return m_List; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal entry data list structure pointer. + */ + Pointer GetHandle() const + { + return m_List; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const EntryDataList & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const + { + return m_Elem ? AsTypeStr(m_Elem->entry_data.type) : _SC("invalid"); + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * See whether this instance references a valid database and entry data list structure. + */ + bool IsValid() const + { + return m_Db && m_List; + } + + /* -------------------------------------------------------------------------------------------- + * See whether a valid element is currently processed. + */ + bool HaveElement() const + { + return m_Elem; + } + + /* -------------------------------------------------------------------------------------------- + * Used to retrieve the type of the current element as a string. + */ + CSStr TypeStr() const + { + // Validate the database and list handle + Validate(); + // return the requested information + return m_Elem ? AsTypeStr(m_Elem->entry_data.type) : _SC("invalid"); + } + + /* -------------------------------------------------------------------------------------------- + * Return the total entries in the list. + */ + Uint32 GetCount() const; + + /* -------------------------------------------------------------------------------------------- + * Go to the next element. + */ + bool Next(); + + /* -------------------------------------------------------------------------------------------- + * Advance a certain number of elements. + */ + bool Advance(Int32 n); + + /* -------------------------------------------------------------------------------------------- + * Go back to the first element in the list. + */ + void Reset(); + + /* -------------------------------------------------------------------------------------------- + * See whether a valid element is currently processed. + */ + bool HasData() const + { + // Validate the database, list and element handle + ValidateElem(); + // Return the requested information + return m_Elem->entry_data.has_data; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the type identifier of the current element. + */ + SQInteger GetType() const + { + // Validate the database, list and element handle + ValidateElem(); + // Return the requested information + return static_cast< SQInteger >(m_Elem->entry_data.type); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the offset of the current element. + */ + SQInteger GetOffset() const + { + // Validate the database, list and element handle + ValidateElem(); + // Return the requested information + return static_cast< SQInteger >(m_Elem->entry_data.offset); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the offset of the next element. + */ + SQInteger GetOffsetToNext() const + { + // Validate the database, list and element handle + ValidateElem(); + // Return the requested information + return static_cast< SQInteger >(m_Elem->entry_data.offset_to_next); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the offset of the next element. + */ + SQInteger DataSize() const + { + // Validate the database, list and element handle + ValidateElem(); + // Return the requested information + return static_cast< SQInteger >(m_Elem->entry_data.data_size); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value from the current element as a string. + */ + CSStr GetString() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value from the current element as a native integer. + */ + SQInteger GetInteger() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value from the current element as a floating point. + */ + SQFloat GetFloat() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value from the current element as a long integer. + */ + Object GetLong() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value from the current element as a boolean. + */ + bool GetBool() const; + + /* -------------------------------------------------------------------------------------------- + * Dumpt the contents of the list to the specified list. + */ + void DumpTo(CSStr filepath) + { + DumpTo(filepath, 0); + } + + /* -------------------------------------------------------------------------------------------- + * Dumpt the contents of the list to the specified list. + */ + void DumpTo(CSStr filepath, Int32 indent) const; +}; + +} // Namespace:: SqMod + +#endif // _SQMMDB_LOOKUPRESULT_HPP_ diff --git a/modules/mmdb/LookupResult.cpp b/modules/mmdb/LookupResult.cpp new file mode 100644 index 00000000..71f0b27a --- /dev/null +++ b/modules/mmdb/LookupResult.cpp @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------------------------ +#include "LookupResult.hpp" +#include "Module.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger LookupResult::Typename(HSQUIRRELVM vm) +{ + static const SQChar name[] = _SC("SqMMDBLookupResult"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + +// ------------------------------------------------------------------------------------------------ +void LookupResult::Validate() const +{ + // Is the document handle valid? + if (!m_Db) + SqThrowF("Invalid Maxmind database reference"); +} + +// ------------------------------------------------------------------------------------------------ +LookupResult::LookupResult() + : m_Db(), m_Result() +{ + memset(&m_Result, 0, sizeof(Type)); +} + +// ------------------------------------------------------------------------------------------------ +Int32 LookupResult::Cmp(const LookupResult & o) const +{ + if (m_Db == o.m_Db) + return 0; + else if (m_Db.DbPtr() > o.m_Db.DbPtr()) + return 1; + else + return -1; +} + +// ------------------------------------------------------------------------------------------------ +EntryDataList LookupResult::GetValueA(CSStr path, Array & arr) const +{ + +} + +// ------------------------------------------------------------------------------------------------ +EntryDataList LookupResult::GetValueT(CSStr path, Table & tbl) const +{ + +} + +} // Namespace:: SqMod diff --git a/modules/mmdb/LookupResult.hpp b/modules/mmdb/LookupResult.hpp new file mode 100644 index 00000000..857b56a6 --- /dev/null +++ b/modules/mmdb/LookupResult.hpp @@ -0,0 +1,164 @@ +#ifndef _SQMMDB_LOOKUPRESULT_HPP_ +#define _SQMMDB_LOOKUPRESULT_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Class that can hold and be used to work with lookup results. +*/ +class LookupResult +{ + // -------------------------------------------------------------------------------------------- + friend class Database; // Only a valid database instance can construct this type. + +protected: + + // -------------------------------------------------------------------------------------------- + typedef MMDB_lookup_result_s Type; // The managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type* Pointer; // Pointer to the managed type. + typedef const Type* ConstPtr; // Constant pointer to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type& Reference; // Reference to the managed type. + typedef const Type& ConstRef; // Constant reference to the managed type. + + /* -------------------------------------------------------------------------------------------- + * Validate the database pointer and throw an error if invalid. + */ + void Validate() const; + +private: + + // --------------------------------------------------------------------------------------------- + DbRef m_Db; /* The database from which this result comes from. */ + Type m_Result; /* The managed result structure. */ + + /* -------------------------------------------------------------------------------------------- + * Construct and take ownership of a certain result. + */ + LookupResult(const DbRef & db, Reference result) + : m_Db(db), m_Result(result) + { + /* ... */ + } + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. (null) + */ + LookupResult(); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + LookupResult(const LookupResult &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + LookupResult(LookupResult &&) = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~LookupResult() + { + /* We let the smart reference deal with deallocations if necessary. */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + LookupResult & operator = (const LookupResult &) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + LookupResult & operator = (LookupResult &&) = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal result structure reference. + */ + Reference GetHandle() + { + return m_Result; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal result structure reference. + */ + ConstRef GetHandle() const + { + return m_Result; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const LookupResult & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const + { + return FmtStr("%u", m_Result.entry.offset); + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * See whether this instance references a valid database and result structure. + */ + bool IsValid() const + { + return m_Db && m_Result.found_entry; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the result contains a valid entry in the associated database. + */ + bool FoundEntry() const + { + // Validate the database handle + Validate(); + // Return the requested information + return m_Result.found_entry; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the net-mask from the result structure. + */ + SQInteger GetNetMask() const + { + // Validate the database handle + Validate(); + // Return the requested information + return static_cast< SQInteger >(m_Result.netmask); + } + + /* -------------------------------------------------------------------------------------------- + * Lookup data in the associated result using an array as the path. + */ + EntryDataList GetValueA(CSStr path, Array & arr) const; + + /* -------------------------------------------------------------------------------------------- + * Lookup data in the associated result using a table as the path. + */ + EntryDataList GetValueT(CSStr path, Table & tbl) const; + +}; + +} // Namespace:: SqMod + +#endif // _SQMMDB_LOOKUPRESULT_HPP_ diff --git a/modules/mmdb/Module.cpp b/modules/mmdb/Module.cpp new file mode 100644 index 00000000..46a2dc34 --- /dev/null +++ b/modules/mmdb/Module.cpp @@ -0,0 +1,302 @@ +// -------------------------------------------------------------------------------------------- +#include "Module.hpp" +#include "Common.hpp" + +// -------------------------------------------------------------------------------------------- +#include + +// -------------------------------------------------------------------------------------------- +#include +#include +#include + +// -------------------------------------------------------------------------------------------- +#if defined(WIN32) || defined(_WIN32) + #include +#endif + +namespace SqMod { + +// -------------------------------------------------------------------------------------------- +PluginFuncs* _Func = NULL; +PluginCallbacks* _Clbk = NULL; +PluginInfo* _Info = NULL; + +// -------------------------------------------------------------------------------------------- +HSQAPI _SqAPI = NULL; +HSQEXPORTS _SqMod = NULL; +HSQUIRRELVM _SqVM = NULL; + +/* ------------------------------------------------------------------------------------------------ + * Bind speciffic functions to certain server events. +*/ +void BindCallbacks(); + +/* ------------------------------------------------------------------------------------------------ + * Undo changes made with BindCallbacks(). +*/ +void UnbindCallbacks(); + +/* -------------------------------------------------------------------------------------------- + * Register the module API under the specified virtual machine. +*/ +void RegisterAPI(HSQUIRRELVM vm); + +/* -------------------------------------------------------------------------------------------- + * Initialize the plugin by obtaining the API provided by the host plugin. +*/ +void OnSquirrelInitialize() +{ + // Attempt to import the plugin API exported by the host plugin + _SqMod = sq_api_import(_Func); + // Did we failed to obtain the plugin exports? + if(!_SqMod) + OutputError("Failed to attach [%s] on host plugin.", SQMMDB_NAME); + else + { + // Obtain the Squirrel API + _SqAPI = _SqMod->GetSquirrelAPI(); + // Expand the Squirrel API into global functions + sq_api_expand(_SqAPI); + } +} + +/* -------------------------------------------------------------------------------------------- + * Load the module on the virtual machine provided by the host module. +*/ +void OnSquirrelLoad() +{ + // Make sure that we have a valid plugin API + if (!_SqMod) + return; /* Unable to proceed. */ + // Obtain the Squirrel API and VM + _SqVM = _SqMod->GetSquirrelVM(); + // Make sure that a valid virtual machine exists + if (!_SqVM) + return; /* Unable to proceed. */ + // Set this as the default database + DefaultVM::Set(_SqVM); + // Register the module API + RegisterAPI(_SqVM); + // Notify about the current status + OutputMessage("Registered: %s", SQMMDB_NAME); +} + +/* -------------------------------------------------------------------------------------------- + * The virtual machine is about to be terminated and script resources should be released. +*/ +void OnSquirrelTerminate() +{ + OutputMessage("Terminating: %s", SQMMDB_NAME); + // Release the current database (if any) + DefaultVM::Set(NULL); + // Release script resources... +} + +/* -------------------------------------------------------------------------------------------- + * Validate the module API to make sure we don't run into issues. +*/ +bool CheckAPIVer(CCStr ver) +{ + // Obtain the numeric representation of the API version + long vernum = strtol(ver, NULL, 10); + // Check against version mismatch + if (vernum == SQMOD_API_VER) + return true; + // Log the incident + OutputError("API version mismatch on %s", SQMMDB_NAME); + OutputMessage("=> Requested: %ld Have: %ld", vernum, SQMOD_API_VER); + // Invoker should not attempt to communicate through the module API + return false; +} + +/* -------------------------------------------------------------------------------------------- + * React to command sent by other plugins. +*/ +static int OnInternalCommand(unsigned int type, const char * text) +{ + switch(type) + { + case SQMOD_INITIALIZE_CMD: + if (CheckAPIVer(text)) + OnSquirrelInitialize(); + break; + case SQMOD_LOAD_CMD: + OnSquirrelLoad(); + break; + case SQMOD_TERMINATE_CMD: + OnSquirrelTerminate(); + break; + default: break; + } + return 1; +} + +/* -------------------------------------------------------------------------------------------- + * The server was initialized and this plugin was loaded successfully. +*/ +static int OnInitServer() +{ + return 1; +} + +static void OnShutdownServer(void) +{ + // The server may still send callbacks + UnbindCallbacks(); +} + +// ------------------------------------------------------------------------------------------------ +void BindCallbacks() +{ + _Clbk->OnInitServer = OnInitServer; + _Clbk->OnInternalCommand = OnInternalCommand; + _Clbk->OnShutdownServer = OnShutdownServer; +} + +// ------------------------------------------------------------------------------------------------ +void UnbindCallbacks() +{ + _Clbk->OnInitServer = NULL; + _Clbk->OnInternalCommand = NULL; + _Clbk->OnShutdownServer = NULL; +} + +// -------------------------------------------------------------------------------------------- +void RegisterAPI(HSQUIRRELVM vm) +{ + +} + +// -------------------------------------------------------------------------------------------- +void OutputMessageImpl(const char * msg, va_list args) +{ +#if defined(WIN32) || defined(_WIN32) + HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE); + + CONSOLE_SCREEN_BUFFER_INFO csb_before; + GetConsoleScreenBufferInfo( hstdout, &csb_before); + SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN); + printf("[SQMOD] "); + + SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); + vprintf(msg, args); + puts(""); + + SetConsoleTextAttribute(hstdout, csb_before.wAttributes); +#else + printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27, msg); + vprintf(msg, args); + puts(""); +#endif +} + +// -------------------------------------------------------------------------------------------- +void OutputErrorImpl(const char * msg, va_list args) +{ +#if defined(WIN32) || defined(_WIN32) + HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE); + + CONSOLE_SCREEN_BUFFER_INFO csb_before; + GetConsoleScreenBufferInfo( hstdout, &csb_before); + SetConsoleTextAttribute(hstdout, FOREGROUND_RED | FOREGROUND_INTENSITY); + printf("[SQMOD] "); + + SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); + vprintf(msg, args); + puts(""); + + SetConsoleTextAttribute(hstdout, csb_before.wAttributes); +#else + printf("%c[0;32m[SQMOD]%c[0;37m", 27, 27, msg); + vprintf(msg, args); + puts(""); +#endif +} + +// -------------------------------------------------------------------------------------------- +void OutputDebug(const char * msg, ...) +{ +#ifdef _DEBUG + // Initialize the arguments list + va_list args; + va_start(args, msg); + // Call the output function + OutputMessageImpl(msg, args); + // Finalize the arguments list + va_end(args); +#else + SQMOD_UNUSED_VAR(msg); +#endif +} + +// -------------------------------------------------------------------------------------------- +void OutputMessage(const char * msg, ...) +{ + // Initialize the arguments list + va_list args; + va_start(args, msg); + // Call the output function + OutputMessageImpl(msg, args); + // Finalize the arguments list + va_end(args); +} + +// -------------------------------------------------------------------------------------------- +void OutputError(const char * msg, ...) +{ + // Initialize the arguments list + va_list args; + va_start(args, msg); + // Call the output function + OutputErrorImpl(msg, args); + // Finalize the arguments list + va_end(args); +} + +} // Namespace:: SqMod + +// -------------------------------------------------------------------------------------------- +SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs* functions, PluginCallbacks* callbacks, PluginInfo* info) +{ + using namespace SqMod; + // Output plugin header + puts(""); + OutputMessage("--------------------------------------------------------------------"); + OutputMessage("Plugin: %s", SQMMDB_NAME); + OutputMessage("Author: %s", SQMMDB_AUTHOR); + OutputMessage("Legal: %s", SQMMDB_COPYRIGHT); + OutputMessage("--------------------------------------------------------------------"); + puts(""); + // Attempt to find the host plugin ID + int host_plugin_id = functions->FindPlugin((char *)(SQMOD_HOST_NAME)); + // See if our plugin was loaded after the host plugin + if (host_plugin_id < 0) + { + OutputError("%s could find the host plugin", SQMMDB_NAME); + // Don't load! + return SQMOD_FAILURE; + } + // Should never reach this point but just in case + else if (host_plugin_id > (info->nPluginId)) + { + OutputError("%s loaded after the host plugin", SQMMDB_NAME); + // Don't load! + return SQMOD_FAILURE; + } + // Store server proxies + _Func = functions; + _Clbk = callbacks; + _Info = info; + // Assign plugin information + _Info->uPluginVer = SQMMDB_VERSION; + strcpy(_Info->szName, SQMMDB_HOST_NAME); + // Bind callbacks + BindCallbacks(); + // Notify that the plugin was successfully loaded + OutputMessage("Successfully loaded %s", SQMMDB_NAME); + // Dummy spacing + puts(""); + // Done! + return SQMOD_SUCCESS; +} diff --git a/modules/mmdb/Module.hpp b/modules/mmdb/Module.hpp new file mode 100644 index 00000000..ab8fcfe6 --- /dev/null +++ b/modules/mmdb/Module.hpp @@ -0,0 +1,41 @@ +#ifndef _SQMMDB_MODULE_HPP_ +#define _SQMMDB_MODULE_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "SqMod.h" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Proxies to comunicate with the server. +*/ +extern PluginFuncs* _Func; +extern PluginCallbacks* _Clbk; +extern PluginInfo* _Info; + +/* ------------------------------------------------------------------------------------------------ + * Proxies to comunicate with the Squirrel plugin. +*/ +extern HSQAPI _SqAPI; +extern HSQEXPORTS _SqMod; +extern HSQUIRRELVM _SqVM; + +/* ------------------------------------------------------------------------------------------------ + * Output a message only if the _DEBUG was defined. +*/ +void OutputDebug(const char * msg, ...); + +/* ------------------------------------------------------------------------------------------------ + * Output a formatted user message to the console. +*/ +void OutputMessage(const char * msg, ...); + +/* ------------------------------------------------------------------------------------------------ + * Output a formatted error message to the console. +*/ +void OutputError(const char * msg, ...); + +} // Namespace:: SqMod + +#endif // _SQMMDB_MODULE_HPP_ diff --git a/modules/mmdb/SockAddr.cpp b/modules/mmdb/SockAddr.cpp new file mode 100644 index 00000000..5b647d81 --- /dev/null +++ b/modules/mmdb/SockAddr.cpp @@ -0,0 +1,68 @@ +// ------------------------------------------------------------------------------------------------ +#include "Sockaddr.hpp" +#include "Module.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger SockAddr::Typename(HSQUIRRELVM vm) +{ + static const SQChar name[] = _SC("SqMMDBSockAddr"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + +// ------------------------------------------------------------------------------------------------ +void SockAddr::Validate() const +{ + // Is the document handle valid? + if (!m_Handle) + SqThrowF("Invalid sockaddr structure handle"); +} + +// ------------------------------------------------------------------------------------------------ +SockAddr::SockAddr(CSStr addr) + : m_Handle(NULL), m_Addres(_SC("")) +{ + struct addrinfo hints; + // Configure the hints structure + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + // We set ai_socktype so that we only get one result back + hints.ai_socktype = SOCK_STREAM; + // Attempt to obtain information about the specified address + Int32 status = getaddrinfo(addr, NULL, &hints, &m_Handle); + // Validate the success of the operation + if (!status) + { + // See if we must free any handles (just in case) + if (m_Handle) + freeaddrinfo(m_Handle); + // Now it's safe to throw the error + SqThrowF("Unable to query the specified address for information [%s]", gai_strerror(status)); + } + // Save the specified string address + m_Addres.assign(addr ? addr : _SC("")); +} + +// ------------------------------------------------------------------------------------------------ +SockAddr::~SockAddr() +{ + if (m_Handle) + freeaddrinfo(m_Handle); +} + +// ------------------------------------------------------------------------------------------------ +Int32 SockAddr::Cmp(const SockAddr & o) const +{ + if (m_Handle == o.m_Handle) + return 0; + else if (m_Handle > o.m_Handle) + return 1; + else + return -1; +} + + +} // Namespace:: SqMod diff --git a/modules/mmdb/Sockaddr.hpp b/modules/mmdb/Sockaddr.hpp new file mode 100644 index 00000000..80e79c63 --- /dev/null +++ b/modules/mmdb/Sockaddr.hpp @@ -0,0 +1,147 @@ +#ifndef _SQMMDB_SOCKADDR_HPP_ +#define _SQMMDB_SOCKADDR_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Common.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Class that can obtain information from string addresses and be used repeatedly thereafter. +*/ +class SockAddr +{ +protected: + + // -------------------------------------------------------------------------------------------- + typedef struct addrinfo Type; // The managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type* Pointer; // Pointer to the managed type. + typedef const Type* ConstPtr; // Constant pointer to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type& Reference; // Reference to the managed type. + typedef const Type& ConstRef; // Constant reference to the managed type. + + /* -------------------------------------------------------------------------------------------- + * Validate the sockaddr pointer and throw an error if invalid. + */ + void Validate() const; + +private: + + // --------------------------------------------------------------------------------------------- + Pointer m_Handle; /* The managed sockaddr structure. */ + String m_Addres; /* The address that was queried for information. */ + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + SockAddr() + : m_Handle(NULL), m_Addres(_SC("")) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + SockAddr(CSStr addr); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + SockAddr(const SockAddr &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + SockAddr(SockAddr && o) + : m_Handle(o.m_Handle) + , m_Addres(o.m_Addres) + { + o.m_Handle = nullptr; + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~SockAddr(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + SockAddr & operator = (const SockAddr &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + SockAddr & operator = (SockAddr && o) + { + if (m_Handle != o.m_Handle) + { + m_Handle = o.m_Handle; + m_Addres = o.m_Addres; + o.m_Handle = nullptr; + } + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal addrinfo structure pointer. + */ + Pointer GetHandle() + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal addrinfo structure pointer. + */ + Pointer GetHandle() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const SockAddr & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const + { + return m_Addres.c_str(); + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * See whether this instance references a valid addrinfo structure. + */ + bool IsValid() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated string address. + */ + CSStr GetAddress() const + { + return m_Addres.c_str(); + } +}; + +} // Namespace:: SqMod + +#endif // _SQMMDB_SOCKADDR_HPP_ diff --git a/modules/sqlite/Connection.cpp b/modules/sqlite/Connection.cpp index 32b86311..ed927891 100644 --- a/modules/sqlite/Connection.cpp +++ b/modules/sqlite/Connection.cpp @@ -389,7 +389,7 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm) SQRESULT ret = sqstd_format(vm, 3, &len, &sql); // Did the format failed? if (SQ_FAILED(ret)) - return ret; + return ret; // Propagate the exception // Attempt to execute the resulted query if ((inst.value->m_Handle = sqlite3_exec(inst.value->m_Handle, sql, NULL, NULL, NULL)) != SQLITE_OK) { @@ -399,7 +399,7 @@ SQInteger Connection::ExecF(HSQUIRRELVM vm) // Push the result onto the stack sq_pushinteger(vm, sqlite3_changes(inst.value->m_Handle)); } - // All methods of retrieving the message value failed + // All methods of retrieving the string value failed else return sq_throwerror(vm, "Unable to extract the query string"); // At this point we should have a return value on the stack @@ -455,14 +455,14 @@ SQInteger Connection::QueueF(HSQUIRRELVM vm) SQRESULT ret = sqstd_format(vm, 3, &len, &sql); // Did the format failed? if (SQ_FAILED(ret)) - return ret; + return ret; // Propagate the exception // Is there even a query to queue? else if (IsQueryEmpty(sql)) return sq_throwerror(vm,"No query to queue"); // Attempt to queue the specified query inst.value->m_Handle->mQueue.push_back(sql); } - // All methods of retrieving the message value failed + // All methods of retrieving the string value failed else return sq_throwerror(vm, "Unable to extract the query string"); // This function does not return a value @@ -519,7 +519,7 @@ SQInteger Connection::QueryF(HSQUIRRELVM vm) SQRESULT ret = sqstd_format(vm, 3, &len, &sql); // Did the format failed? if (SQ_FAILED(ret)) - return ret; + return ret; // Propagate the exception // Attempt to create a statement with the specified query try { @@ -530,7 +530,7 @@ SQInteger Connection::QueryF(HSQUIRRELVM vm) return sq_throwerror(vm, e.Message().c_str()); } } - // All methods of retrieving the message value failed + // All methods of retrieving the string value failed else return sq_throwerror(vm, "Unable to extract the query string"); // At this point we should have a return value on the stack diff --git a/shared/SqMod.h b/shared/SqMod.h index 0aecf453..6accee73 100644 --- a/shared/SqMod.h +++ b/shared/SqMod.h @@ -58,17 +58,19 @@ extern "C" { #define SQMOD_TERMINATE_CMD 0xDEADC0DE #define SQMOD_API_VER 1 - /*primitive functions*/ + //primitive functions typedef HSQAPI (*SqEx_GetSquirrelAPI) (void); typedef HSQUIRRELVM (*SqEx_GetSquirrelVM) (void); - /*logging utilities*/ + //logging utilities typedef void (*SqEx_LogMessage) (const SQChar * fmt, ...); - /*long numbers*/ + //script loading + typedef SQRESULT (*SqEx_LoadScript) (const SQChar * filepath); + //long numbers typedef SQRESULT (*SqEx_GetSLongValue) (HSQUIRRELVM vm, SQInteger idx, SqInt64 * num); typedef void (*SqEx_PushSLongObject) (HSQUIRRELVM vm, SqInt64 num); typedef SQRESULT (*SqEx_GetULongValue) (HSQUIRRELVM vm, SQInteger idx, SqUint64 * num); typedef void (*SqEx_PushULongObject) (HSQUIRRELVM vm, SqUint64 num); - /*time utilities*/ + //time utilities typedef SqInt64 (*SqEx_GetCurrentSysTime) (void); typedef SqInt64 (*SqEx_GetEpochTimeMicro) (void); typedef SqInt64 (*SqEx_GetEpochTimeMilli) (void); @@ -80,11 +82,11 @@ extern "C" { */ typedef struct { - unsigned int uStructSize; - /*primitive functions*/ + unsigned int StructSize; + //primitive functions SqEx_GetSquirrelAPI GetSquirrelAPI; SqEx_GetSquirrelVM GetSquirrelVM; - /*logging utilities*/ + //logging utilities SqEx_LogMessage LogDbg; SqEx_LogMessage LogUsr; SqEx_LogMessage LogScs; @@ -99,6 +101,8 @@ extern "C" { SqEx_LogMessage LogSWrn; SqEx_LogMessage LogSErr; SqEx_LogMessage LogSFtl; + //script loading + SqEx_LoadScript LoadScript; /*long numbers*/ SqEx_GetSLongValue GetSLongValue; SqEx_PushSLongObject PushSLongObject; diff --git a/source/Base/AABB.cpp b/source/Base/AABB.cpp index 795860ec..148d63db 100644 --- a/source/Base/AABB.cpp +++ b/source/Base/AABB.cpp @@ -14,6 +14,14 @@ const AABB AABB::MAX = AABB(Vector3::MIN, Vector3::MAX); // ------------------------------------------------------------------------------------------------ SQChar AABB::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger AABB::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("AABB"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ AABB::AABB() : min(-1.0), max(1.0) @@ -49,27 +57,6 @@ AABB::AABB(const Vector3 & vmin, const Vector3 & vmax) /* ... */ } -// ------------------------------------------------------------------------------------------------ -AABB::AABB(const AABB & b) - : min(b.min), max(b.max) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -AABB::~AABB() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -AABB & AABB::operator = (const AABB & b) -{ - min = b.min; - max = b.max; - return *this; -} - // ------------------------------------------------------------------------------------------------ AABB & AABB::operator = (Value s) { @@ -304,7 +291,7 @@ Int32 AABB::Cmp(const AABB & o) const // ------------------------------------------------------------------------------------------------ CSStr AABB::ToString() const { - return ToStringF("%f,%f,%f,%f,%f,%f", min.x, min.y, min.z, max.x, max.y, max.z); + return ToStrF("%f,%f,%f,%f,%f,%f", min.x, min.y, min.z, max.x, max.y, max.z); } // ------------------------------------------------------------------------------------------------ @@ -392,6 +379,7 @@ void Register_AABB(HSQUIRRELVM vm) .Prop(_SC("abs"), &AABB::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &AABB::ToString) + .SquirrelFunc(_SC("_typename"), &AABB::Typename) .Func(_SC("_cmp"), &AABB::Cmp) /* Metamethods */ .Func(_SC("_add"), &AABB::operator +) diff --git a/source/Base/AABB.hpp b/source/Base/AABB.hpp index 3ed95a9f..6ab1adb8 100644 --- a/source/Base/AABB.hpp +++ b/source/Base/AABB.hpp @@ -8,304 +8,328 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent an axis aligned bounding box in three-dimensional space. */ struct AABB { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const AABB NIL; -static const AABB MIN; -static const AABB MAX; + static const AABB MIN; + static const AABB MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The minimum and maximum components of this type. */ Vector3 min, max; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ AABB(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a an equally sized and perfectly shaped box from a scalar value. */ AABB(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a an equally sized but imperfectly shaped box from individual components of a + * three-dimensional point. */ AABB(Value xv, Value yv, Value zv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a an unequally sized and imperfectly shaped box from individual components of two + * three-dimensional points. */ AABB(Value xmin, Value ymin, Value zmin, Value xmax, Value ymax, Value zmax); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a an unequally sized and imperfectly shaped box from two three-dimensional + * vectors representing two three-dimensional points. */ AABB(const Vector3 & vmin, const Vector3 & vmax); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - AABB(const AABB & o); + AABB(const AABB & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~AABB(); + AABB(AABB && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - AABB & operator = (const AABB & o); + ~AABB() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + AABB & operator = (const AABB & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + AABB & operator = (AABB && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ AABB & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Three-dimensional vector assignment operator. */ AABB & operator = (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Four-dimensional vector assignment operator threated as a three-dimensional vector. */ AABB & operator = (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ AABB & operator += (const AABB & b); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ AABB & operator -= (const AABB & b); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ AABB & operator *= (const AABB & b); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ AABB & operator /= (const AABB & b); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ AABB & operator %= (const AABB & b); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ AABB & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ AABB & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ AABB & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ AABB & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ AABB & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ AABB & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ AABB & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ AABB operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ AABB operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ AABB operator + (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ AABB operator - (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ AABB operator * (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ AABB operator / (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ AABB operator % (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ AABB operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ AABB operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ AABB operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ AABB operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ AABB operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ AABB operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ AABB operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const AABB & b) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set an equally sized and perfectly shaped box from a scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set an equally sized but imperfectly shaped box from individual components of a + * three-dimensional point. */ void Set(Value nx, Value ny, Value nz); /* -------------------------------------------------------------------------------------------- - * ... + * Set an unequally sized and imperfectly shaped box from individual components of two + * three-dimensional points. */ void Set(Value xmin, Value ymin, Value zmin, Value xmax, Value ymax, Value zmax); /* -------------------------------------------------------------------------------------------- - * ... + * Set the same box from another instance of this type. */ void Set(const AABB & b); /* -------------------------------------------------------------------------------------------- - * ... + * Set an equally sized and imperfectly shaped box from a single three-dimensional vector + * representing a single three-dimensional point. */ void Set(const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Set an unequally sized and imperfectly shaped box from two three-dimensional vectors + * representing two three-dimensional points. */ void Set(const Vector3 & nmin, const Vector3 & nmax); /* -------------------------------------------------------------------------------------------- - * ... + * Set an equally sized and imperfectly shaped box from a single four-dimensional vector + * representing a single three-dimensional point. */ void Set(const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Set an unequally sized and imperfectly shaped box from two four-dimensional vectors + * representing two three-dimensional points. */ void Set(const Vector4 & nmin, const Vector4 & nmax); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -314,7 +338,7 @@ static const AABB MAX; } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ AABB Abs() const; }; diff --git a/source/Base/Buffer.cpp b/source/Base/Buffer.cpp index ea4b77ee..2698a74d 100644 --- a/source/Base/Buffer.cpp +++ b/source/Base/Buffer.cpp @@ -1,10 +1,10 @@ // ------------------------------------------------------------------------------------------------ -#include "Base/Buffer.hpp" +#include "Buffer.hpp" // ------------------------------------------------------------------------------------------------ -#include -#include -#include +#include +#include +#include #include #include @@ -14,7 +14,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ * Compute the next power of two for the specified number. */ -static inline unsigned int NPow2(unsigned int num) +inline unsigned int NextPow2(unsigned int num) { --num; num |= num >> 1; @@ -40,9 +40,7 @@ void ThrowMemExcept(const char * msg, ...) int ret = vsnprintf(buffer, sizeof(buffer), msg, args); // Check for formatting errors if (ret < 0) - { throw std::runtime_error("Unknown memory error"); - } // Throw the actual exception throw std::runtime_error(buffer); } @@ -53,12 +51,10 @@ void ThrowMemExcept(const char * msg, ...) static Buffer::Pointer AllocMem(Buffer::SzType size) { // Attempt to allocate memory directly - Buffer::Pointer ptr = (Buffer::Pointer)malloc(size); + Buffer::Pointer ptr = reinterpret_cast< Buffer::Pointer >(malloc(size)); // Validate the allocated memory if (!ptr) - { ThrowMemExcept("Unable to allocate (%u) bytes of memory", size); - } // Return the allocated memory return ptr; } @@ -75,36 +71,36 @@ class MemCat public: // -------------------------------------------------------------------------------------------- - typedef Buffer::Value Value; + typedef Buffer::Value Value; // The type of value used to represent a byte. // -------------------------------------------------------------------------------------------- - typedef Buffer::Reference Reference; - typedef Buffer::ConstRef ConstRef; + typedef Buffer::Reference Reference; // A reference to the stored value type. + typedef Buffer::ConstRef ConstRef; // A const reference to the stored value type. // -------------------------------------------------------------------------------------------- - typedef Buffer::Pointer Pointer; - typedef Buffer::ConstPtr ConstPtr; + typedef Buffer::Pointer Pointer; // A pointer to the stored value type. + typedef Buffer::ConstPtr ConstPtr; // A const pointer to the stored value type. // -------------------------------------------------------------------------------------------- - typedef Buffer::SzType SzType; + typedef Buffer::SzType SzType; // The type used to represent size in general. private: /* -------------------------------------------------------------------------------------------- - * + * Structure used to store a memory chunk in the linked list. */ struct Node { // ---------------------------------------------------------------------------------------- - SzType mCap; - Pointer mPtr; - Node* mNext; + SzType mCap; /* The size of the memory chunk. */ + Pointer mPtr; /* Pointer to the memory chunk. */ + Node* mNext; /* The next node in the list. */ /* ---------------------------------------------------------------------------------------- * Base constructor. */ Node(Node * next) - : mCap(0), mPtr(NULL), mNext(next) + : mCap(0), mPtr(nullptr), mNext(next) { /* ... */ } @@ -120,7 +116,7 @@ private: * Default constructor. */ MemCat() - : m_Head(NULL) + : m_Head(nullptr) { /* ... */ } @@ -130,20 +126,18 @@ private: */ ~MemCat() { - for (Node * node = m_Head, * next = NULL; node; node = next) + for (Node * node = m_Head, * next = nullptr; node; node = next) { // Free the memory (if any) if (node->mPtr) - { free(node->mPtr); - } // Save the next node next = node->mNext; // Release the node instance delete node; } // Explicitly set the head node to null - m_Head = NULL; + m_Head = nullptr; } /* -------------------------------------------------------------------------------------------- @@ -151,20 +145,18 @@ private: */ void Clear() { - for (Node * node = m_Head, * next = NULL; node; node = next) + for (Node * node = m_Head, * next = nullptr; node; node = next) { // Free the memory (if any) if (node->mPtr) - { free(node->mPtr); - } // Save the next node next = node->mNext; // Release the node instance Push(node); } // Explicitly set the head node to null - m_Head = NULL; + m_Head = nullptr; } /* -------------------------------------------------------------------------------------------- @@ -174,21 +166,17 @@ private: { // NOTE: Function assumes (size > 0) // Find a buffer large enough to satisfy the requested size - for (Node * node = m_Head, * prev = NULL; node; prev = node, node = node->mNext) + for (Node * node = m_Head, * prev = nullptr; node; prev = node, node = node->mNext) { // Is this buffer large enough? if (node->mCap >= size) { // Was there a previous node? if (prev) - { prev->mNext = node->mNext; - } // Probably this was the head else - { m_Head = node->mNext; - } // Assign the memory ptr = node->mPtr; // Assign the size @@ -200,10 +188,11 @@ private: } } // Round up the size to a power of two number - size = (size & (size - 1)) ? NPow2(size) : size; + size = (size & (size - 1)) ? NextPow2(size) : size; // Allocate the memory directly ptr = AllocMem(size); // See if the memory could be allocated + // (shouldn't reach this point if allocation failed) if (!ptr) { // Revert the size @@ -219,9 +208,7 @@ private: void Drop(Pointer & ptr, SzType & size) { if (!ptr) - { ThrowMemExcept("Cannot store invalid memory buffer"); - } // Request a node instance Node * node = Pull(); // Assign the specified memory @@ -245,9 +232,7 @@ private: s_Nodes = new Node(s_Nodes); // Validate the head node if (!s_Nodes) - { ThrowMemExcept("Unable to allocate memory nodes"); - } } } @@ -256,10 +241,9 @@ private: */ static Node * Pull() { + // Are there any nodes available? if (!s_Nodes) - { - Make(); - } + Make(); // Make some! // Grab the head node Node * node = s_Nodes; // Promote the next node as the head @@ -275,9 +259,7 @@ private: { // See if the node is even valid if (!node) - { ThrowMemExcept("Attempting to push invalid node"); - } // Demote the current head node node->mNext = s_Nodes; // Promote as the head node @@ -286,7 +268,7 @@ private: }; // ------------------------------------------------------------------------------------------------ -MemCat::Node * MemCat::s_Nodes = NULL; +MemCat::Node * MemCat::s_Nodes = nullptr; /* ------------------------------------------------------------------------------------------------ * Lightweight memory allocator to reduce the overhead of small allocations. @@ -294,8 +276,8 @@ MemCat::Node * MemCat::s_Nodes = NULL; class Memory { // -------------------------------------------------------------------------------------------- - friend class Buffer; - friend class MemRef; + friend class Buffer; // Allow the buffer type to access the memory categories. + friend class MemRef; // Allow the memory manager reference to create new instances. private: @@ -316,7 +298,7 @@ private: */ ~Memory() { - for (MemCat::Node * node = MemCat::s_Nodes, * next = NULL; node; node = next) + for (MemCat::Node * node = MemCat::s_Nodes, * next = nullptr; node; node = next) { // Save the next node next = node->mNext; @@ -324,13 +306,15 @@ private: delete node; } // Explicitly set the head node to null - MemCat::s_Nodes = NULL; + MemCat::s_Nodes = nullptr; } private: // -------------------------------------------------------------------------------------------- - MemCat m_Small, m_Medium, m_Large; + MemCat m_Small; // Small memory allocations of <= 1024 bytes. + MemCat m_Medium; // Medium memory allocations of <= 4096 bytes. + MemCat m_Large; // Large memory allocations of <= 4096 bytes. }; // ------------------------------------------------------------------------------------------------ @@ -340,9 +324,7 @@ MemRef MemRef::s_Mem; void MemRef::Grab() { if (m_Ptr) - { ++(*m_Ref); - } } // ------------------------------------------------------------------------------------------------ @@ -352,8 +334,8 @@ void MemRef::Drop() { delete m_Ptr; delete m_Ref; - m_Ptr = NULL; - m_Ref = NULL; + m_Ptr = nullptr; + m_Ref = nullptr; } } @@ -369,13 +351,9 @@ const MemRef & MemRef::Get() return s_Mem; } -// ------------------------------------------------------------------------------------------------ -Buffer::Pointer Buffer::s_Ptr = NULL; -Buffer::SzType Buffer::s_Cap = 0; - // ------------------------------------------------------------------------------------------------ Buffer::Buffer(const Buffer & o) - : m_Ptr(NULL) + : m_Ptr(nullptr) , m_Cap(0) , m_Mem(o.m_Mem) { @@ -389,10 +367,9 @@ Buffer::Buffer(const Buffer & o) // ------------------------------------------------------------------------------------------------ Buffer::~Buffer() { + // Do we have a buffer? if (m_Ptr) - { - Release(); - } + Release(); // Release it! } // ------------------------------------------------------------------------------------------------ @@ -400,24 +377,25 @@ Buffer & Buffer::operator = (const Buffer & o) { if (m_Ptr != o.m_Ptr) { + // Can we work in the current buffer? if (m_Cap && o.m_Cap <= m_Cap) - { + // It's safe to copy the data memcpy(m_Ptr, o.m_Ptr, m_Cap); - } + // Do we even have data to copy? else if (!o.m_Cap) { + // Do we have a buffer? if (m_Ptr) - { - Release(); - } + Release(); // Release it! } else { + // Do we have a buffer? if (m_Ptr) - { - Release(); - } + Release(); // Release it! + // Request a larger buffer Request(o.m_Cap); + // Now it's safe to copy the data memcpy(m_Ptr, o.m_Ptr, o.m_Cap); } } @@ -433,67 +411,51 @@ void Buffer::Request(SzType n) if (!m_Mem) { // Round up the size to a power of two number - n = (n & (n - 1)) ? NPow2(n) : n; + n = (n & (n - 1)) ? NextPow2(n) : n; // Allocate the memory directly m_Ptr = AllocMem(n); } // Find out in which category does this buffer reside else if (n <= 1024) - { m_Mem->m_Small.Grab(m_Ptr, n); - } else if (n <= 4096) - { m_Mem->m_Medium.Grab(m_Ptr, n); - } else - { m_Mem->m_Large.Grab(m_Ptr, n); - } - // If no errors occured then we can set the size - m_Cap= n; + // If no errors occurred then we can set the size + m_Cap = n; } // ------------------------------------------------------------------------------------------------ void Buffer::Release() { + // TODO: Implement a limit on how much memory can actually be pooled. // Is there a memory manager available? if (!m_Mem) - { - // Deallocate the memory directly - free(m_Ptr); - } + free(m_Ptr); // Deallocate the memory directly // Find out to which category does this buffer belong else if (m_Cap <= 1024) - { m_Mem->m_Small.Drop(m_Ptr, m_Cap); - } else if (m_Cap <= 4096) - { m_Mem->m_Medium.Drop(m_Ptr, m_Cap); - } else - { m_Mem->m_Large.Drop(m_Ptr, m_Cap); - } // Explicitly reset the buffer - m_Ptr = NULL; + m_Ptr = nullptr; m_Cap = 0; } // ------------------------------------------------------------------------------------------------ Buffer::SzType Buffer::Write(SzType pos, ConstPtr data, SzType size) { - // Make sure the pos is not out of bounds + // Make sure the position is not out of bounds if (pos > m_Cap || !data || !size) - { return 0; - } // See if the buffer size must be adjusted else if ((pos + size) >= m_Cap) { - // Backup current data - Buffer bkp = Adjust< Value >(pos + size); + // Allocate a larger memory chunk and backup old data + Buffer bkp(Adjust< Value >(NextPow2(pos + size))); // Copy data back from the old buffer memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap); } @@ -506,48 +468,44 @@ Buffer::SzType Buffer::Write(SzType pos, ConstPtr data, SzType size) // ------------------------------------------------------------------------------------------------ Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, ...) { - // Make sure the pos is not out of bounds - if (pos > m_Cap) - { - return 0; - } - // Initialize the arguments list + // Initialize the variable argument list va_list args; va_start(args, fmt); - // Initial attempt to write to the current buffer - // (if empty, it should tell us the necessary size) - int ret = vsnprintf(m_Ptr + pos, m_Cap - pos, fmt, args); - // Do we need a bigger buffer? - if ((pos + ret) >= m_Cap) - { - // Backup current data - Buffer bkp = Adjust< Value >(pos + ret); - // Copy data back from the old buffer - memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap); - // Argument list was modified during the initial format - va_end(args); - va_start(args, fmt); - // Resume writting the requested information - ret = vsnprintf(m_Ptr + pos, m_Cap - pos, fmt, args); - } - // Finalize the arguments list + // Call the function that takes the variable argument list + SzType ret = WriteF(pos, fmt, args); + // Finalize the variable argument list va_end(args); - // Return the size of the written data in bytes - return (ret < 0) ? 0 : (SzType)ret; + // Return the result + return ret; } // ------------------------------------------------------------------------------------------------ Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, va_list args) { - // Make sure the pos is not out of bounds + // Make sure the position is not out of bounds if (pos > m_Cap) - { return 0; - } + // Backup the variable argument list + va_list args_cpy; + va_copy(args_cpy, args); // Attempt to write to the current buffer - int ret = vsnprintf(m_Ptr + pos, m_Cap - pos, fmt, args); - // Return the size of the written data in bytes - return (ret < 0) ? 0 : (SzType)ret; + // (if empty, it should tell us the necessary size) + int ret = vsnprintf(m_Ptr + pos, m_Cap, fmt, args); + // Do we need a bigger buffer? + if ((pos + ret) >= m_Cap) + { + // Allocate a larger memory chunk and backup old data + Buffer bkp(Adjust< Value >(NextPow2(pos + ret))); + // Copy data back from the old buffer + memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap); + // Retry writing the requested information + ret = vsnprintf(m_Ptr + pos, m_Cap, fmt, args_cpy); + } + // Return the value 0 if data could not be written + if (ret < 0) + return 0; + // Return the number of written characters + return static_cast< SzType >(ret); } -} // Namespace:: SQMod +} // Namespace:: SqMod diff --git a/source/Base/Buffer.hpp b/source/Base/Buffer.hpp index 1ce719c1..f719f93e 100644 --- a/source/Base/Buffer.hpp +++ b/source/Base/Buffer.hpp @@ -2,7 +2,10 @@ #define _BASE_BUFFER_HPP_ // ------------------------------------------------------------------------------------------------ -#include +#include + +// ------------------------------------------------------------------------------------------------ +#include // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -64,6 +67,17 @@ public: Grab(); } + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + MemRef(MemRef && o) + : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref) + + { + o.m_Ptr = nullptr; + o.m_Ref = nullptr; + } + /* -------------------------------------------------------------------------------------------- * Destructor. */ @@ -87,6 +101,22 @@ public: return *this; } + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + MemRef & operator = (MemRef && o) + { + if (m_Ptr != o.m_Ptr) + { + Drop(); + m_Ptr = o.m_Ptr; + m_Ref = o.m_Ref; + o.m_Ptr = nullptr; + o.m_Ref = nullptr; + } + return *this; + } + /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two memory managers. */ @@ -116,7 +146,7 @@ public: */ Memory * operator -> () const { - assert(m_Ptr != NULL); + assert(m_Ptr); return m_Ptr; } @@ -125,7 +155,7 @@ public: */ Memory & operator * () const { - assert(m_Ptr != NULL); + assert(m_Ptr); return *m_Ptr; } }; @@ -134,43 +164,58 @@ public: void ThrowMemExcept(const char * msg, ...); /* ------------------------------------------------------------------------------------------------ - * Reusable buffer memory for quick allocations. + * Reusable and re-scalable buffer memory for quick memory allocations. */ class Buffer { public: // -------------------------------------------------------------------------------------------- - typedef char Value; /* The type of value used to represent a byte. */ + typedef char Value; // The type of value used to represent a byte. // -------------------------------------------------------------------------------------------- - typedef Value & Reference; /* A reference to the stored value type. */ - typedef const Value & ConstRef; /* A const reference to the stored value type. */ + typedef Value & Reference; // A reference to the stored value type. + typedef const Value & ConstRef; // A const reference to the stored value type. // -------------------------------------------------------------------------------------------- - typedef Value * Pointer; /* A pointer to the stored value type. */ - typedef const Value * ConstPtr; /* A const pointer to the stored value type. */ + typedef Value * Pointer; // A pointer to the stored value type. + typedef const Value * ConstPtr; // A const pointer to the stored value type. // -------------------------------------------------------------------------------------------- - typedef unsigned int SzType; /* The type used to represent size in general. */ + typedef unsigned int SzType; // The type used to represent size in general. + +private: + + /* -------------------------------------------------------------------------------------------- + * Construct and take ownership of the specified buffer. + */ + Buffer(Pointer & ptr, SzType & cap, const MemRef & mem) + : m_Ptr(ptr) + , m_Cap(cap) + , m_Mem(mem) + { + ptr = nullptr; + cap = 0; + } + +public: /* -------------------------------------------------------------------------------------------- * Default constructor (null). Not null of a previous buffer was marked as movable. */ Buffer() - : m_Ptr(s_Ptr) - , m_Cap(s_Cap) + : m_Ptr(nullptr) + , m_Cap(0) , m_Mem(MemRef::Get()) { - s_Ptr = NULL; - s_Cap = 0; + /* ... */ } /* -------------------------------------------------------------------------------------------- * Explicit size constructor. */ Buffer(SzType n) - : m_Ptr(NULL) + : m_Ptr(nullptr) , m_Cap(0) , m_Mem(MemRef::Get()) { @@ -182,6 +227,15 @@ public: */ Buffer(const Buffer & o); + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + Buffer(Buffer && o) + : m_Ptr(o.m_Ptr), m_Cap(o.m_Cap), m_Mem(o.m_Mem) + { + o.m_Ptr = nullptr; + } + /* -------------------------------------------------------------------------------------------- * Destructor. */ @@ -192,6 +246,23 @@ public: */ Buffer & operator = (const Buffer & o); + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Buffer & operator = (Buffer && o) + { + if (m_Ptr != o.m_Ptr) + { + if (m_Ptr) + Release(); + m_Ptr = o.m_Ptr; + m_Cap = o.m_Cap; + m_Mem = o.m_Mem; + o.m_Ptr = nullptr; + } + return *this; + } + /* -------------------------------------------------------------------------------------------- * Equality comparison operator. */ @@ -251,7 +322,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer casted as a different type. */ - template < typename T > T * Get() + template < typename T = Value> T * Get() { return reinterpret_cast< T * >(m_Ptr); } @@ -259,7 +330,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer casted as a different type. */ - template < typename T > const T * Get() const + template < typename T = Value> const T * Get() const { return reinterpret_cast< const T * >(m_Ptr); } @@ -267,7 +338,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the a certain element. */ - template < typename T > T & At(SzType n) + template < typename T = Value> T & At(SzType n) { assert(n < m_Cap); return reinterpret_cast< T * >(m_Ptr)[n]; @@ -276,7 +347,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the a certain element. */ - template < typename T > const T & At(SzType n) const + template < typename T = Value> const T & At(SzType n) const { assert(n < m_Cap); return reinterpret_cast< const T * >(m_Ptr)[n]; @@ -285,7 +356,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer casted as a different type. */ - template < typename T > T * Begin() + template < typename T = Value> T * Begin() { return reinterpret_cast< T * >(m_Ptr); } @@ -293,7 +364,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer casted as a different type. */ - template < typename T > const T * Begin() const + template < typename T = Value> const T * Begin() const { return reinterpret_cast< const T * >(m_Ptr); } @@ -301,7 +372,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer casted as a different type. */ - template < typename T > T * End() + template < typename T = Value> T * End() { return reinterpret_cast< T * >(m_Ptr) + (m_Cap / sizeof(T)); } @@ -309,7 +380,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer casted as a different type. */ - template < typename T > const T * End() const + template < typename T = Value> const T * End() const { return reinterpret_cast< const T * >(m_Ptr) + (m_Cap / sizeof(T)); } @@ -333,7 +404,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve maximum elements it can hold for a certain type. */ - template < typename T > static SzType Max() + template < typename T = Value> static SzType Max() { return (0xFFFFFFFF / sizeof(T)); } @@ -341,7 +412,7 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the current buffer capacity in element count. */ - template < typename T > SzType Size() const + template < typename T = Value> SzType Size() const { return (m_Cap / sizeof(T)); } @@ -357,32 +428,28 @@ public: /* -------------------------------------------------------------------------------------------- * Makes sure there is enough capacity to hold the specified element count. */ - template < typename T > Buffer Adjust(SzType n) + template < typename T = Value> Buffer Adjust(SzType n) { + // Do we meet the minimum size? if (n < 8) - { - n = 8; - } + n = 8; // Adjust to minimum size // See if the requested capacity doesn't exceed the limit if (n > Max< T >()) - { ThrowMemExcept("Requested buffer of (%u) elements exceeds the (%u) limit", n, Max< T >()); - } // Is there an existing buffer? else if (n && !m_Cap) - { - // Request the memory - Request(n * sizeof(T)); - } + Request(n * sizeof(T)); // Request the memory // Should the size be increased? else if (n > m_Cap) { // Backup the current memory - Move(); + Buffer bkp(m_Ptr, m_Cap, m_Mem); // Request the memory Request(n * sizeof(T)); + // Return the backup + return std::move(bkp); } - // Return an empty buffer or the backup (if any) + // Return an empty buffer return Buffer(); } @@ -392,9 +459,7 @@ public: void Reset() { if (m_Ptr) - { Release(); - } } /* -------------------------------------------------------------------------------------------- @@ -437,17 +502,6 @@ protected: */ void Release(); - /* -------------------------------------------------------------------------------------------- - * Moves the internal buffer to the global members to be taken over by the next instance. - */ - void Move() - { - s_Ptr = m_Ptr; - s_Cap = m_Cap; - m_Ptr = NULL; - m_Cap = 0; - } - private: // -------------------------------------------------------------------------------------------- @@ -456,10 +510,6 @@ private: // -------------------------------------------------------------------------------------------- MemRef m_Mem; - - // -------------------------------------------------------------------------------------------- - static Pointer s_Ptr; /* Pointer to a moved memory buffer. */ - static SzType s_Cap; /* The total size of the moved buffer. */ }; } // Namespace:: SqMod diff --git a/source/Base/Circle.cpp b/source/Base/Circle.cpp index 8a173b06..29703254 100644 --- a/source/Base/Circle.cpp +++ b/source/Base/Circle.cpp @@ -14,6 +14,14 @@ const Circle Circle::MAX = Circle(NumLimit< Circle::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Circle::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Circle::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Circle"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Circle::Circle() : pos(0.0, 0.0), rad(0.0) @@ -42,27 +50,6 @@ Circle::Circle(Value xv, Value yv, Value rv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Circle::Circle(const Circle & o) - : pos(o.pos), rad(o.rad) -{ - -} - -// ------------------------------------------------------------------------------------------------ -Circle::~Circle() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Circle & Circle::operator = (const Circle & o) -{ - pos = o.pos; - rad = o.rad; - return *this; -} - // ------------------------------------------------------------------------------------------------ Circle & Circle::operator = (Value r) { @@ -341,7 +328,7 @@ Int32 Circle::Cmp(const Circle & o) const // ------------------------------------------------------------------------------------------------ CSStr Circle::ToString() const { - return ToStringF("%f,%f,%f", pos.x, pos.y, rad); + return ToStrF("%f,%f,%f", pos.x, pos.y, rad); } // ------------------------------------------------------------------------------------------------ @@ -395,35 +382,28 @@ void Circle::Generate() void Circle::Generate(Value min, Value max, bool r) { if (EpsLt(max, min)) - { - SqThrow("max value is lower than min value"); - } + SqThrowF("max value is lower than min value"); else if (r) - { rad = GetRandomFloat32(min, max); - } else - { pos.Generate(min, max); - } } void Circle::Generate(Value xmin, Value xmax, Value ymin, Value ymax) { + if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin)) + SqThrowF("max value is lower than min value"); + pos.Generate(xmin, xmax, ymin, ymax); } void Circle::Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value rmin, Value rmax) { - if (EpsLt(rmax, rmin)) - { - SqThrow("max value is lower than min value"); - } - else - { - pos.Generate(xmin, xmax, ymin, ymax); - rad = GetRandomFloat32(rmin, rmax); - } + if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin) || EpsLt(rmax, rmin)) + SqThrowF("max value is lower than min value"); + + pos.Generate(xmin, xmax, ymin, ymax); + rad = GetRandomFloat32(rmin, rmax); } // ------------------------------------------------------------------------------------------------ @@ -452,6 +432,7 @@ void Register_Circle(HSQUIRRELVM vm) .Prop(_SC("abs"), &Circle::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Circle::ToString) + .SquirrelFunc(_SC("_typename"), &Circle::Typename) .Func(_SC("_cmp"), &Circle::Cmp) /* Metamethods */ .Func(_SC("_add"), &Circle::operator +) diff --git a/source/Base/Circle.hpp b/source/Base/Circle.hpp index 03e28c6d..ffab503c 100644 --- a/source/Base/Circle.hpp +++ b/source/Base/Circle.hpp @@ -9,355 +9,370 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a two-dimensional circle. */ struct Circle { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Circle NIL; static const Circle MIN; static const Circle MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The position and radius components of this type. */ Vector2 pos; Value rad; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Circle(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a circle at position 0,0 using the specified radius. */ Circle(Value rv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a circle at the specified position using the specified radius. */ Circle(const Vector2 & pv, Value rv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a circle at the specified position using the specified radius. */ Circle(Value xv, Value yv, Value rv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Circle(const Circle & o); + Circle(const Circle & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Circle(); + Circle(Circle && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Circle & operator = (const Circle & o); + ~Circle() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Circle & operator = (const Circle & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Circle & operator = (Circle && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Radius assignment operator. */ Circle & operator = (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Position assignment operator. */ Circle & operator = (const Vector2 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Circle & operator += (const Circle & c); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Circle & operator -= (const Circle & c); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Circle & operator *= (const Circle & c); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Circle & operator /= (const Circle & c); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Circle & operator %= (const Circle & c); /* -------------------------------------------------------------------------------------------- - * ... + * Radius addition assignment operator. */ Circle & operator += (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius subtraction assignment operator. */ Circle & operator -= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius multiplication assignment operator. */ Circle & operator *= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius division assignment operator. */ Circle & operator /= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius modulo assignment operator. */ Circle & operator %= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Position addition assignment operator. */ Circle & operator += (const Vector2 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position subtraction assignment operator. */ Circle & operator -= (const Vector2 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position multiplication assignment operator. */ Circle & operator *= (const Vector2 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position division assignment operator. */ Circle & operator /= (const Vector2 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position modulo assignment operator. */ Circle & operator %= (const Vector2 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Circle & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Circle & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Circle operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Circle operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Circle operator + (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Circle operator - (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Circle operator * (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Circle operator / (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Circle operator % (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius addition operator. */ Circle operator + (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius subtraction operator. */ Circle operator - (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius multiplication operator. */ Circle operator * (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius division operator. */ Circle operator / (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius modulo operator. */ Circle operator % (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position addition operator. */ Circle operator + (const Vector2 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position subtraction operator. */ Circle operator - (const Vector2 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position multiplication operator. */ Circle operator * (const Vector2 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position division operator. */ Circle operator / (const Vector2 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position modulo operator. */ Circle operator % (const Vector2 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Circle operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Circle operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Circle & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set the specified radius. */ void Set(Value nr); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the circle from another instance of this type. */ void Set(const Circle & nc); /* -------------------------------------------------------------------------------------------- - * ... + * Set the position from the specified position. */ void Set(const Vector2 & np); /* -------------------------------------------------------------------------------------------- - * ... + * Set the specified position and radius. */ void Set(const Vector2 & np, Value nr); /* -------------------------------------------------------------------------------------------- - * ... + * Set the specified position. */ void Set(Value nx, Value ny); /* -------------------------------------------------------------------------------------------- - * ... + * Set the specified position and radius. */ void Set(Value nx, Value ny, Value nr); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly sized and positioned circle. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly sized or positioned circle within the specified bounds. */ void Generate(Value min, Value max, bool r); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly positioned circle within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly sized and positioned circle within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value rmin, Value rmax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -365,7 +380,7 @@ struct Circle } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Circle Abs() const; }; diff --git a/source/Base/Color3.cpp b/source/Base/Color3.cpp index f370dd7b..262223ca 100644 --- a/source/Base/Color3.cpp +++ b/source/Base/Color3.cpp @@ -15,6 +15,14 @@ const Color3 Color3::MAX = Color3(NumLimit< Color3::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Color3::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Color3::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Color3"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Color3::Color3() : r(0), g(0), b(0) @@ -36,28 +44,6 @@ Color3::Color3(Value rv, Value gv, Value bv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Color3::Color3(const Color3 & o) - : r(o.r), g(o.g), b(o.b) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Color3::~Color3() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Color3 & Color3::operator = (const Color3 & o) -{ - r = o.r; - g = o.g; - b = o.b; - return *this; -} - // ------------------------------------------------------------------------------------------------ Color3 & Color3::operator = (Value s) { @@ -449,7 +435,7 @@ Int32 Color3::Cmp(const Color3 & o) const // ------------------------------------------------------------------------------------------------ CSStr Color3::ToString() const { - return ToStringF("%u,%u,%u", r, g, b); + return ToStrF("%u,%u,%u", r, g, b); } // ------------------------------------------------------------------------------------------------ @@ -502,9 +488,9 @@ Uint32 Color3::GetRGB() const void Color3::SetRGB(Uint32 p) { - r = Value((p >> 16) & 0xFF); - g = Value((p >> 8) & 0xFF); - b = Value((p) & 0xFF); + r = static_cast< Value >((p >> 16) & 0xFF); + g = static_cast< Value >((p >> 8) & 0xFF); + b = static_cast< Value >((p) & 0xFF); } // ------------------------------------------------------------------------------------------------ @@ -515,9 +501,9 @@ Uint32 Color3::GetRGBA() const void Color3::SetRGBA(Uint32 p) { - r = Value((p >> 24) & 0xFF); - g = Value((p >> 16) & 0xFF); - b = Value((p >> 8) & 0xFF); + r = static_cast< Value >((p >> 24) & 0xFF); + g = static_cast< Value >((p >> 16) & 0xFF); + b = static_cast< Value >((p >> 8) & 0xFF); } // ------------------------------------------------------------------------------------------------ @@ -528,9 +514,9 @@ Uint32 Color3::GetARGB() const void Color3::SetARGB(Uint32 p) { - r = Value((p >> 16) & 0xFF); - g = Value((p >> 8) & 0xFF); - b = Value((p) & 0xFF); + r = static_cast< Value >((p >> 16) & 0xFF); + g = static_cast< Value >((p >> 8) & 0xFF); + b = static_cast< Value >((p) & 0xFF); } // ------------------------------------------------------------------------------------------------ @@ -544,29 +530,21 @@ void Color3::Generate() void Color3::Generate(Value min, Value max) { if (max < min) - { - SqThrow("max value is lower than min value"); - } - else - { - r = GetRandomUint8(min, max); - g = GetRandomUint8(min, max); - b = GetRandomUint8(min, max); - } + SqThrowF("max value is lower than min value"); + + r = GetRandomUint8(min, max); + g = GetRandomUint8(min, max); + b = GetRandomUint8(min, max); } void Color3::Generate(Value rmin, Value rmax, Value gmin, Value gmax, Value bmin, Value bmax) { if (rmax < rmin || gmax < gmin || bmax < bmin) - { - SqThrow("max value is lower than min value"); - } - else - { - r = GetRandomUint8(rmin, rmax); - g = GetRandomUint8(gmin, gmax); - b = GetRandomUint8(bmin, bmax); - } + SqThrowF("max value is lower than min value"); + + r = GetRandomUint8(rmin, rmax); + g = GetRandomUint8(gmin, gmax); + b = GetRandomUint8(bmin, bmax); } // ------------------------------------------------------------------------------------------------ @@ -578,9 +556,9 @@ void Color3::Random() // ------------------------------------------------------------------------------------------------ void Color3::Inverse() { - r = Value(~r); - g = Value(~g); - b = Value(~b); + r = static_cast< Value >(~r); + g = static_cast< Value >(~g); + b = static_cast< Value >(~b); } // ================================================================================================ @@ -606,6 +584,7 @@ void Register_Color3(HSQUIRRELVM vm) .Prop(_SC("str"), &Color3::SetCol) /* Core Metamethods */ .Func(_SC("_tostring"), &Color3::ToString) + .SquirrelFunc(_SC("_typename"), &Color3::Typename) .Func(_SC("_cmp"), &Color3::Cmp) /* Metamethods */ .Func(_SC("_add"), &Color3::operator +) diff --git a/source/Base/Color3.hpp b/source/Base/Color3.hpp index 38452c27..420f4d86 100644 --- a/source/Base/Color3.hpp +++ b/source/Base/Color3.hpp @@ -8,434 +8,449 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent an opaque RGB color. */ struct Color3 { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef unsigned char Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Color3 NIL; static const Color3 MIN; static const Color3 MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The red, green and blue components of this type. */ Value r, g, b; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Color3(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a color with all components with the same specified color. */ Color3(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct with individually specified red, green and blue colors. */ Color3(Value rv, Value gv, Value bv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Color3(const Color3 & o); + Color3(const Color3 & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Color3(); + Color3(Color3 && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Color3 & operator = (const Color3 & o); + ~Color3() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Color3 & operator = (const Color3 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Color3 & operator = (Color3 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Color3 & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Named color assignment operator. */ Color3 & operator = (CSStr name); /* -------------------------------------------------------------------------------------------- - * ... + * Transparent color assignment operator. */ Color3 & operator = (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Color3 & operator += (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Color3 & operator -= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Color3 & operator *= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Color3 & operator /= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Color3 & operator %= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise AND assignment operator. */ Color3 & operator &= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise OR assignment operator. */ Color3 & operator |= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise XOR assignment operator. */ Color3 & operator ^= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise left shift assignment operator. */ Color3 & operator <<= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise right shift assignment operator. */ Color3 & operator >>= (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Color3 & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Color3 & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Color3 & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Color3 & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Color3 & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise AND assignment operator. */ Color3 & operator &= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise OR assignment operator. */ Color3 & operator |= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise XOR assignment operator. */ Color3 & operator ^= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise left shift assignment operator. */ Color3 & operator <<= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise right shift assignment operator. */ Color3 & operator >>= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Color3 & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Color3 & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Color3 operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Color3 operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Color3 operator + (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Color3 operator - (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Color3 operator * (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Color3 operator / (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Color3 operator % (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise AND operator. */ Color3 operator & (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise OR operator. */ Color3 operator | (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise XOR operator. */ Color3 operator ^ (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise shift left operator. */ Color3 operator << (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise shift right operator. */ Color3 operator >> (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Color3 operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Color3 operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Color3 operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Color3 operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Color3 operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise AND operator. */ Color3 operator & (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise OR operator. */ Color3 operator | (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise XOR operator. */ Color3 operator ^ (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise shift left operator. */ Color3 operator << (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise shift right operator. */ Color3 operator >> (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Color3 operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Color3 operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise NOT operator. */ Color3 operator ~ () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Implicit conversion to transparent color. */ operator Color4 () const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Color3 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nr, Value ng, Value nb); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from an opaque color. */ void Set(const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr str, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values from the identified color. */ void SetCol(CSStr name); /* -------------------------------------------------------------------------------------------- - * ... + * Get the component values packed inside an integer value. */ Uint32 GetRGB() const; /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values wxtracted from an integer value. */ void SetRGB(Uint32 p); /* -------------------------------------------------------------------------------------------- - * ... + * Get the component values packed inside an integer value. */ Uint32 GetRGBA() const; /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values wxtracted from an integer value. */ void SetRGBA(Uint32 p); /* -------------------------------------------------------------------------------------------- - * ... + * Get the component values packed inside an integer value. */ Uint32 GetARGB() const; /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values wxtracted from an integer value. */ void SetARGB(Uint32 p); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value rmin, Value rmax, Value gmin, Value gmax, Value bmin, Value bmax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -443,12 +458,12 @@ struct Color3 } /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values to a randomly chosen color. */ void Random(); /* -------------------------------------------------------------------------------------------- - * ... + * Inverse the color. */ void Inverse(); }; diff --git a/source/Base/Color4.cpp b/source/Base/Color4.cpp index c2fa6f97..40213f01 100644 --- a/source/Base/Color4.cpp +++ b/source/Base/Color4.cpp @@ -15,6 +15,14 @@ const Color4 Color4::MAX = Color4(NumLimit< Color4::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Color4::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Color4::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Color4"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Color4::Color4() : r(0), g(0), b(0), a(0) @@ -24,7 +32,7 @@ Color4::Color4() // ------------------------------------------------------------------------------------------------ Color4::Color4(Value sv) - : r(sv), g(sv), b(sv), a(sv) + : r(sv), g(sv), b(sv), a(0) { /* ... */ } @@ -43,29 +51,6 @@ Color4::Color4(Value rv, Value gv, Value bv, Value av) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Color4::Color4(const Color4 & o) - : r(o.r), g(o.g), b(o.b), a(o.a) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Color4::~Color4() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Color4 & Color4::operator = (const Color4 & o) -{ - r = o.r; - g = o.g; - b = o.b; - a = o.a; - return *this; -} - // ------------------------------------------------------------------------------------------------ Color4 & Color4::operator = (Value s) { @@ -482,7 +467,7 @@ Int32 Color4::Cmp(const Color4 & o) const // ------------------------------------------------------------------------------------------------ CSStr Color4::ToString() const { - return ToStringF("%u,%u,%u,%u", r, g, b, a); + return ToStrF("%u,%u,%u,%u", r, g, b, a); } // ------------------------------------------------------------------------------------------------ @@ -546,9 +531,9 @@ Uint32 Color4::GetRGB() const void Color4::SetRGB(Uint32 p) { - r = Value((p >> 16) & 0xFF); - g = Value((p >> 8) & 0xFF); - b = Value((p) & 0xFF); + r = static_cast< Value >((p >> 16) & 0xFF); + g = static_cast< Value >((p >> 8) & 0xFF); + b = static_cast< Value >((p) & 0xFF); } // ------------------------------------------------------------------------------------------------ @@ -559,10 +544,10 @@ Uint32 Color4::GetRGBA() const void Color4::SetRGBA(Uint32 p) { - r = Value((p >> 24) & 0xFF); - g = Value((p >> 16) & 0xFF); - b = Value((p >> 8) & 0xFF); - a = Value((p) & 0xFF); + r = static_cast< Value >((p >> 24) & 0xFF); + g = static_cast< Value >((p >> 16) & 0xFF); + b = static_cast< Value >((p >> 8) & 0xFF); + a = static_cast< Value >((p) & 0xFF); } // ------------------------------------------------------------------------------------------------ @@ -573,10 +558,10 @@ Uint32 Color4::GetARGB() const void Color4::SetARGB(Uint32 p) { - a = Value((p >> 24) & 0xFF); - r = Value((p >> 16) & 0xFF); - g = Value((p >> 8) & 0xFF); - b = Value((p) & 0xFF); + a = static_cast< Value >((p >> 24) & 0xFF); + r = static_cast< Value >((p >> 16) & 0xFF); + g = static_cast< Value >((p >> 8) & 0xFF); + b = static_cast< Value >((p) & 0xFF); } // ------------------------------------------------------------------------------------------------ @@ -591,31 +576,23 @@ void Color4::Generate() void Color4::Generate(Value min, Value max) { if (max < min) - { - SqThrow("max value is lower than min value"); - } - else - { - r = GetRandomUint8(min, max); - g = GetRandomUint8(min, max); - b = GetRandomUint8(min, max); - a = GetRandomUint8(min, max); - } + SqThrowF("max value is lower than min value"); + + r = GetRandomUint8(min, max); + g = GetRandomUint8(min, max); + b = GetRandomUint8(min, max); + a = GetRandomUint8(min, max); } void Color4::Generate(Value rmin, Value rmax, Value gmin, Value gmax, Value bmin, Value bmax, Value amin, Value amax) { if (rmax < rmin || gmax < gmin || bmax < bmin || amax < amin) - { - SqThrow("max value is lower than min value"); - } - else - { - r = GetRandomUint8(rmin, rmax); - g = GetRandomUint8(gmin, gmax); - b = GetRandomUint8(bmin, bmax); - a = GetRandomUint8(bmin, bmax); - } + SqThrowF("max value is lower than min value"); + + r = GetRandomUint8(rmin, rmax); + g = GetRandomUint8(gmin, gmax); + b = GetRandomUint8(bmin, bmax); + a = GetRandomUint8(bmin, bmax); } // ------------------------------------------------------------------------------------------------ @@ -627,10 +604,10 @@ void Color4::Random() // ------------------------------------------------------------------------------------------------ void Color4::Inverse() { - r = Value(~r); - g = Value(~g); - b = Value(~b); - a = Value(~a); + r = static_cast< Value >(~r); + g = static_cast< Value >(~g); + b = static_cast< Value >(~b); + a = static_cast< Value >(~a); } // ================================================================================================ @@ -658,6 +635,7 @@ void Register_Color4(HSQUIRRELVM vm) .Prop(_SC("str"), &Color4::SetCol) /* Core Metamethods */ .Func(_SC("_tostring"), &Color4::ToString) + .SquirrelFunc(_SC("_typename"), &Color4::Typename) .Func(_SC("_cmp"), &Color4::Cmp) /* Metamethods */ .Func(_SC("_add"), &Color4::operator +) diff --git a/source/Base/Color4.hpp b/source/Base/Color4.hpp index 6ce86acf..b9b43313 100644 --- a/source/Base/Color4.hpp +++ b/source/Base/Color4.hpp @@ -8,444 +8,459 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a transparent RGBA color. */ struct Color4 { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef unsigned char Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Color4 NIL; static const Color4 MIN; static const Color4 MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The red, green and blue components of this type. */ Value r, g, b, a; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Color4(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a color with all components with the same specified color. */ Color4(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct with individually specified red, green and blue colors. */ Color4(Value rv, Value gv, Value bv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct with individually specified red, green, blue and alpha colors. */ Color4(Value rv, Value gv, Value bv, Value av); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Color4(const Color4 & o); + Color4(const Color4 & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Color4(); + Color4(Color4 && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Color4 & operator = (const Color4 & o); + ~Color4() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Color4 & operator = (const Color4 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Color4 & operator = (Color4 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Color4 & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Named color assignment operator. */ Color4 & operator = (CSStr name); /* -------------------------------------------------------------------------------------------- - * ... + * Opaque color assignment operator. */ Color4 & operator = (const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Color4 & operator += (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Color4 & operator -= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Color4 & operator *= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Color4 & operator /= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Color4 & operator %= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise AND assignment operator. */ Color4 & operator &= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise OR assignment operator. */ Color4 & operator |= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise XOR assignment operator. */ Color4 & operator ^= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise left shift assignment operator. */ Color4 & operator <<= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise right shift assignment operator. */ Color4 & operator >>= (const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Color4 & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Color4 & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Color4 & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Color4 & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Color4 & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise AND assignment operator. */ Color4 & operator &= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise OR assignment operator. */ Color4 & operator |= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise XOR assignment operator. */ Color4 & operator ^= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise left shift assignment operator. */ Color4 & operator <<= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise right shift assignment operator. */ Color4 & operator >>= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Color4 & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Color4 & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Color4 operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Color4 operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Color4 operator + (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Color4 operator - (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Color4 operator * (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Color4 operator / (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Color4 operator % (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise AND operator. */ Color4 operator & (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise OR operator. */ Color4 operator | (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise XOR operator. */ Color4 operator ^ (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise shift left operator. */ Color4 operator << (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise shift right operator. */ Color4 operator >> (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Color4 operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Color4 operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Color4 operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Color4 operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Color4 operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise AND operator. */ Color4 operator & (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise OR operator. */ Color4 operator | (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise XOR operator. */ Color4 operator ^ (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise shift left operator. */ Color4 operator << (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise shift right operator. */ Color4 operator >> (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Color4 operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Color4 operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise NOT operator. */ Color4 operator ~ () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Implicit conversion to opaque color. */ operator Color3 () const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Color4 & c) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nr, Value ng, Value nb); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nr, Value ng, Value nb, Value na); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Color4 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from an opaque color. */ void Set(const Color3 & c); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr name, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values from the identified color. */ void SetCol(CSStr name); /* -------------------------------------------------------------------------------------------- - * ... + * Get the component values packed inside an integer value. */ Uint32 GetRGB() const; /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values wxtracted from an integer value. */ void SetRGB(Uint32 p); /* -------------------------------------------------------------------------------------------- - * ... + * Get the component values packed inside an integer value. */ Uint32 GetRGBA() const; /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values wxtracted from an integer value. */ void SetRGBA(Uint32 p); /* -------------------------------------------------------------------------------------------- - * ... + * Get the component values packed inside an integer value. */ Uint32 GetARGB() const; /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values wxtracted from an integer value. */ void SetARGB(Uint32 p); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value rmin, Value rmax, Value gmin, Value gmax, Value bmin, Value bmax, Value amin, Value amax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -453,12 +468,12 @@ struct Color4 } /* -------------------------------------------------------------------------------------------- - * ... + * Set the component values to a randomly chosen color. */ void Random(); /* -------------------------------------------------------------------------------------------- - * ... + * Inverse the color. */ void Inverse(); }; diff --git a/source/Base/Quaternion.cpp b/source/Base/Quaternion.cpp index a02b5a31..4609f79c 100644 --- a/source/Base/Quaternion.cpp +++ b/source/Base/Quaternion.cpp @@ -16,6 +16,14 @@ const Quaternion Quaternion::MAX = Quaternion(NumLimit< Quaternion::Value >::Max // ------------------------------------------------------------------------------------------------ SQChar Quaternion::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Quaternion::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Quaternion"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Quaternion::Quaternion() : x(0.0), y(0.0), z(0.0), w(0.0) @@ -44,29 +52,6 @@ Quaternion::Quaternion(Value xv, Value yv, Value zv, Value wv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Quaternion::Quaternion(const Quaternion & o) - : x(o.x), y(o.y), z(o.z), w(o.w) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Quaternion::~Quaternion() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Quaternion & Quaternion::operator = (const Quaternion & o) -{ - x = o.x; - y = o.y; - z = o.z; - w = o.w; - return *this; -} - // ------------------------------------------------------------------------------------------------ Quaternion & Quaternion::operator = (Value s) { @@ -338,7 +323,7 @@ Int32 Quaternion::Cmp(const Quaternion & o) const // ------------------------------------------------------------------------------------------------ CSStr Quaternion::ToString() const { - return ToStringF("%f,%f,%f,%f", x, y, z, w); + return ToStrF("%f,%f,%f,%f", x, y, z, w); } // ------------------------------------------------------------------------------------------------ @@ -408,31 +393,23 @@ void Quaternion::Generate() void Quaternion::Generate(Value min, Value max) { if (EpsLt(max, min)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(min, max); - y = GetRandomFloat32(min, max); - z = GetRandomFloat32(min, max); - y = GetRandomFloat32(min, max); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(min, max); + y = GetRandomFloat32(min, max); + z = GetRandomFloat32(min, max); + y = GetRandomFloat32(min, max); } void Quaternion::Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax, Value wmin, Value wmax) { if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin) || EpsLt(zmax, zmin) || EpsLt(wmax, wmin)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(xmin, xmax); - y = GetRandomFloat32(ymin, ymax); - z = GetRandomFloat32(zmin, zmax); - y = GetRandomFloat32(ymin, ymax); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(xmin, xmax); + y = GetRandomFloat32(ymin, ymax); + z = GetRandomFloat32(zmin, zmax); + y = GetRandomFloat32(ymin, ymax); } // ------------------------------------------------------------------------------------------------ @@ -463,6 +440,7 @@ void Register_Quaternion(HSQUIRRELVM vm) .Prop(_SC("abs"), &Quaternion::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Quaternion::ToString) + .SquirrelFunc(_SC("_typename"), &Quaternion::Typename) .Func(_SC("_cmp"), &Quaternion::Cmp) /* Metamethods */ .Func(_SC("_add"), &Quaternion::operator +) diff --git a/source/Base/Quaternion.hpp b/source/Base/Quaternion.hpp index 2eef092c..dc86b3d4 100644 --- a/source/Base/Quaternion.hpp +++ b/source/Base/Quaternion.hpp @@ -8,34 +8,34 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Quaternion class for representing rotations. */ struct Quaternion { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Quaternion NIL; static const Quaternion MIN; static const Quaternion MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The x, y, z and w components of this type. */ Value x, y, z, w; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Quaternion(); @@ -55,257 +55,272 @@ struct Quaternion Quaternion(Value xv, Value yv, Value zv, Value wv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Quaternion(const Quaternion & o); + Quaternion(const Quaternion & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Quaternion(); + Quaternion(Quaternion && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Quaternion & operator = (const Quaternion & o); + ~Quaternion() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Quaternion & operator = (const Quaternion & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Quaternion & operator = (Quaternion && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Quaternion & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Euler assignment operator. */ Quaternion & operator = (const Vector3 & q); /* -------------------------------------------------------------------------------------------- - * ... + * Four-dimensional vector assignment operator threated as a three-dimensional vector. */ Quaternion & operator = (const Vector4 & q); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Quaternion & operator += (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Quaternion & operator -= (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Quaternion & operator *= (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Quaternion & operator /= (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Quaternion & operator %= (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Quaternion & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Quaternion & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Quaternion & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Quaternion & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Quaternion & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Quaternion & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Quaternion & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Quaternion operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Quaternion operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Quaternion operator + (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Quaternion operator - (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Quaternion operator * (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Quaternion operator / (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Quaternion operator % (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Quaternion operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Quaternion operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Quaternion operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Quaternion operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Quaternion operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Quaternion operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Quaternion operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Quaternion & q) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny, Value nz); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny, Value nz, Value nw); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a three-dimensional vector as euler rotation. */ void Set(const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a four-dimensional vector. */ void Set(const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax, Value wmin, Value wmax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -313,7 +328,7 @@ struct Quaternion } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Quaternion Abs() const; }; diff --git a/source/Base/Shared.cpp b/source/Base/Shared.cpp index 45040f26..cd0590ae 100644 --- a/source/Base/Shared.cpp +++ b/source/Base/Shared.cpp @@ -35,6 +35,11 @@ PluginFuncs* _Func = NULL; PluginCallbacks* _Clbk = NULL; PluginInfo* _Info = NULL; +/* ------------------------------------------------------------------------------------------------ + * Common buffer to reduce memory allocations. To be immediately copied uppon return! +*/ +static SQChar g_Buffer[4096]; + // ------------------------------------------------------------------------------------------------ const char NumLimit< char >::Min = CHAR_MIN; const signed char NumLimit< signed char >::Min = SCHAR_MIN; @@ -99,30 +104,52 @@ bool SToB(CSStr str) } // ------------------------------------------------------------------------------------------------ -CSStr ToStrF(CCStr fmt, ...) +void SqThrowF(CCStr fmt, ...) { - static char buf[128]; + // Initialize the argument list va_list args; va_start (args, fmt); - int ret = vsnprintf(buf, sizeof(buf), fmt, args); - if (ret < 0) - { - SqThrow("Failed to run the specified string format"); - buf[0] = 0; - } + // Write the requested contents + if (snprintf(g_Buffer, sizeof(g_Buffer), fmt, args) < 0) + strcpy(g_Buffer, "Unknown error has occurred"); + // Release the argument list va_end(args); - return buf; + // Throw the exception with the resulted message + throw Sqrat::Exception(g_Buffer); +} + +// ------------------------------------------------------------------------------------------------ +CSStr ToStrF(CCStr fmt, ...) +{ + // Prepare the arguments list + va_list args; + va_start (args, fmt); + // Attempt to run the specified format + int ret = vsnprintf(g_Buffer, sizeof(g_Buffer), fmt, args); + // See if the format function failed + if (ret < 0) + SqThrowF("Failed to run the specified string format"); + // Finalized the arguments list + va_end(args); + // Return the resulted string + return g_Buffer; } // ------------------------------------------------------------------------------------------------ CSStr ToStringF(CCStr fmt, ...) { + // Acquire a moderately sized buffer Buffer b(128); + // Prepare the arguments list va_list args; va_start (args, fmt); + // Attempt to run the specified format if (b.WriteF(0, fmt, args) == 0) - b.At< SQChar >(0) = 0; + // Make sure the string is null terminated + b.At(0) = 0; + // Finalized the arguments list va_end(args); + // Return the resulted string return b.Get< SQChar >(); } @@ -280,22 +307,17 @@ const Color3 & GetRandomColor() // ------------------------------------------------------------------------------------------------ Color3 GetColor(CSStr name) { - Uint32 len = 0; // See if we actually have something to search for - if(!name || (len = (Uint32)strlen(name)) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return Color3::NIL; - } + if(!name || *name == 0) + SqThrowF("Cannot extract values from an empty string"); // Clone the string into an editable version CCStr str = StrJustAlphaNum(name); str = StrToLowercase(str); // See if we still have a valid name after the cleanup - if((len = (Uint32)strlen(name)) <= 0) - { - SqThrow("Cannot extract values from an invalid string: %s", name); - return Color3::NIL; - } + if(!str || *str == 0) + SqThrowF("Cannot extract values from an invalid string: %s", name); + // Calculate the name length + const Uint32 len = strlen(str); // Get the most significant characters used to identify a weapon SQChar a = str[0], b = 0, c = 0, d = str[len-1]; // Look for deeper specifiers @@ -885,19 +907,17 @@ Color3 GetColor(CSStr name) } // ------------------------------------------------------------------------------------------------ -AABB GetAABB(CSStr str, SQChar delim) +const AABB & GetAABB(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f , %f , %f , %f , %f "); static AABB box; + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); + box.Clear(); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return box; - } - else if (delim != AABB::Delim) + if (delim != AABB::Delim) { fs[4] = delim; fs[9] = delim; @@ -920,19 +940,17 @@ AABB GetAABB(CSStr str, SQChar delim) } // ------------------------------------------------------------------------------------------------ -Circle GetCircle(CSStr str, SQChar delim) +const Circle & GetCircle(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f , %f "); static Circle circle; - //circle.Clear(); + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return circle; - } - else if (delim != Circle::Delim) + circle.Clear(); + + if (delim != Circle::Delim) { fs[4] = delim; fs[9] = delim; @@ -949,16 +967,15 @@ Circle GetCircle(CSStr str, SQChar delim) } // ------------------------------------------------------------------------------------------------ -Color3 GetColor3(CSStr str, SQChar delim) +const Color3 & GetColor3(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %u , %u , %u "); + static Color3 col; + Uint32 r = 0, g = 0, b = 0; - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return Color3(); - } + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); else if (delim != Color3::Delim) { fs[4] = delim; @@ -972,19 +989,23 @@ Color3 GetColor3(CSStr str, SQChar delim) sscanf(str, &fs[0], &r, &g, &b); - return Color3(Color3::Value(r), Color3::Value(g), Color3::Value(b)); + col.r = static_cast< Color4::Value >(r); + col.g = static_cast< Color4::Value >(g); + col.b = static_cast< Color4::Value >(b); + + return col; } -Color4 GetColor4(CSStr str, SQChar delim) +// ------------------------------------------------------------------------------------------------ +const Color4 & GetColor4(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %u , %u , %u , %u "); + static Color4 col; + Uint32 r = 0, g = 0, b = 0, a = 0; - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return Color4(); - } + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); else if (delim != Color4::Delim) { fs[4] = delim; @@ -1000,23 +1021,26 @@ Color4 GetColor4(CSStr str, SQChar delim) sscanf(str, &fs[0], &r, &g, &b, &a); - return Color4(Color4::Value(r), Color4::Value(g), Color4::Value(b), Color4::Value(a)); + col.r = static_cast< Color4::Value >(r); + col.g = static_cast< Color4::Value >(g); + col.b = static_cast< Color4::Value >(b); + col.a = static_cast< Color4::Value >(a); + + return col; } // ------------------------------------------------------------------------------------------------ -Quaternion GetQuaternion(CSStr str, SQChar delim) +const Quaternion & GetQuaternion(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f , %f , %f "); static Quaternion quat; - //quat.Clear(); + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return quat; - } - else if (delim != Quaternion::Delim) + quat.Clear(); + + if (delim != Quaternion::Delim) { fs[4] = delim; fs[9] = delim; @@ -1034,19 +1058,18 @@ Quaternion GetQuaternion(CSStr str, SQChar delim) return quat; } -Sphere GetSphere(CSStr str, SQChar delim) +// ------------------------------------------------------------------------------------------------ +const Sphere & GetSphere(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f , %f , %f "); static Sphere sphere; - //sphere.Clear(); + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return sphere; - } - else if (delim != Sphere::Delim) + sphere.Clear(); + + if (delim != Sphere::Delim) { fs[4] = delim; fs[9] = delim; @@ -1065,52 +1088,40 @@ Sphere GetSphere(CSStr str, SQChar delim) } // ------------------------------------------------------------------------------------------------ -Vector2 GetVector2(CSStr str, SQChar delim) +const Vector2 & GetVector2(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f "); static Vector2 vec; - //vec.Clear(); + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return vec; - } - else if (delim != Vector2::Delim) - { + vec.Clear(); + + if (delim != Vector2::Delim) fs[4] = delim; - } else - { fs[4] = Vector2::Delim; - } sscanf(str, &fs[0], &vec.x, &vec.y); return vec; } -Vector2i GetVector2i(CSStr str, SQChar delim) +const Vector2i & GetVector2i(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %d , %d "); static Vector2i vec; - //vec.Clear(); + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return vec; - } - else if (delim != Vector2i::Delim) - { + vec.Clear(); + + if (delim != Vector2i::Delim) fs[4] = delim; - } else - { fs[4] = Vector2i::Delim; - } sscanf(str, &fs[0], &vec.x, &vec.y); @@ -1118,19 +1129,17 @@ Vector2i GetVector2i(CSStr str, SQChar delim) } // ------------------------------------------------------------------------------------------------ -Vector3 GetVector3(CSStr str, SQChar delim) +const Vector3 & GetVector3(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f , %f "); static Vector3 vec; + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); + vec.Clear(); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return vec; - } - else if (delim != Vector3::Delim) + if (delim != Vector3::Delim) { fs[4] = delim; fs[9] = delim; @@ -1146,19 +1155,17 @@ Vector3 GetVector3(CSStr str, SQChar delim) return vec; } -Vector4 GetVector4(CSStr str, SQChar delim) +const Vector4 & GetVector4(CSStr str, SQChar delim) { static SQChar fs[] = _SC(" %f , %f , %f , %f "); static Vector4 vec; + if (!str || *str == 0) + SqThrowF("Cannot extract values from an empty string"); + vec.Clear(); - if (strlen(str) <= 0) - { - SqThrow("Cannot extract values from an empty string"); - return vec; - } - else if (delim != Vector4::Delim) + if (delim != Vector4::Delim) { fs[4] = delim; fs[9] = delim; diff --git a/source/Base/Shared.hpp b/source/Base/Shared.hpp index 3233f3d7..9a06f9a5 100644 --- a/source/Base/Shared.hpp +++ b/source/Base/Shared.hpp @@ -5,8 +5,8 @@ #include "SqBase.hpp" // ------------------------------------------------------------------------------------------------ -#include -#include +#include +#include // ------------------------------------------------------------------------------------------------ #include @@ -19,7 +19,7 @@ namespace SqMod { extern const SQChar * g_EmptyStr; /* ------------------------------------------------------------------------------------------------ - * Proxies to comunicate with the server. + * Proxies to communicate with the server. */ extern PluginFuncs* _Func; extern PluginCallbacks* _Clbk; @@ -28,7 +28,9 @@ extern PluginInfo* _Info; // ------------------------------------------------------------------------------------------------ template < typename T > struct NumLimit; -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Basic minimum and maximum values for primitive numeric types. +*/ template <> struct NumLimit< char > { static const char Min, Max; }; template <> struct NumLimit< signed char > { static const signed char Min, Max; }; template <> struct NumLimit< unsigned char > { static const unsigned char Min, Max; }; @@ -44,7 +46,58 @@ template <> struct NumLimit< float > { static const float Min, Max; }; template <> struct NumLimit< double > { static const double Min, Max; }; template <> struct NumLimit< long double > { static const long double Min, Max; }; -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Implements RAII to restore the VM stack to it's initial size on function exit. +*/ +struct StackGuard +{ + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + StackGuard(HSQUIRRELVM vm) + : m_Top(sq_gettop(vm)), m_VM(vm) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + StackGuard(const StackGuard &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. (disabled) + */ + StackGuard(StackGuard &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~StackGuard() + { + sq_pop(m_VM, sq_gettop(m_VM) - m_Top); + } + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + StackGuard & operator = (const StackGuard &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + StackGuard & operator = (StackGuard &&) = delete; + +private: + + // -------------------------------------------------------------------------------------------- + Int32 m_Top; /* The top of the stack when this instance was created. */ + HSQUIRRELVM m_VM; /* The VM where the stack should be restored. */ +}; + +/* ------------------------------------------------------------------------------------------------ + * Perform an equality comparison between two values taking into account floating point issues. +*/ template< typename T > inline bool EpsEq(const T a, const T b) { return abs(a - b) <= 0; @@ -60,7 +113,9 @@ template <> inline bool EpsEq(const Float64 a, const Float64 b) return fabs(a - b) <= 0.000000001d; } -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Perform a less than comparison between two values taking into account floating point issues. +*/ template< typename T > inline bool EpsLt(const T a, const T b) { return !EpsEq(a, b) && (a < b); @@ -76,7 +131,9 @@ template <> inline bool EpsLt(const Float64 a, const Float64 b) return !EpsEq(a, b) && (a - b) < 0.000000001d; } -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Perform a greater than comparison between two values taking into account floating point issues. +*/ template< typename T > inline bool EpsGt(const T a, const T b) { return !EpsEq(a, b) && (a > b); @@ -92,7 +149,10 @@ template <> inline bool EpsGt(const Float64 a, const Float64 b) return !EpsEq(a, b) && (a - b) > 0.000000001d; } -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Perform a less than or equal comparison between two values taking into account + * floating point issues. +*/ template< typename T > inline bool EpsLtEq(const T a, const T b) { return !EpsEq(a, b) || (a < b); @@ -108,7 +168,10 @@ template <> inline bool EpsLtEq(const Float64 a, const Float64 b) return !EpsEq(a, b) || (a - b) < 0.000000001d; } -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Perform a greater than or equal comparison between two values taking into account + * floating point issues. +*/ template< typename T > inline bool EpsGtEq(const T a, const T b) { return !EpsEq(a, b) || (a > b); @@ -124,7 +187,9 @@ template <> inline bool EpsGtEq(const Float64 a, const Float64 b) return !EpsEq(a, b) || (a - b) > 0.000000001d; } -// ------------------------------------------------------------------------------------------------ +/* ------------------------------------------------------------------------------------------------ + * Force a value to be within a certain range. +*/ template< typename T > inline T Clamp(T val, T min, T max) { return val < min ? min : (val > max ? max : val); @@ -144,6 +209,142 @@ inline Uint32 NextPow2(Uint32 num) return ++num; } +/* ------------------------------------------------------------------------------------------------ + * Output a message only if the _DEBUG was defined. +*/ +void OutputDebug(const char * msg, ...); + +/* ------------------------------------------------------------------------------------------------ + * Output a formatted user message to the console. +*/ +void OutputMessage(const char * msg, ...); + +/* ------------------------------------------------------------------------------------------------ + * Output a formatted error message to the console. +*/ +void OutputError(const char * msg, ...); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve a reference to a null script object. +*/ +Object & NullObject(); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve a reference to a null/empty script array. +*/ +Array & NullArray(); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve a reference to a null script function. +*/ +Function & NullFunction(); + +/* ------------------------------------------------------------------------------------------------ + * Create a script object from the specified value on the default VM. +*/ +template < typename T > Object MakeObject(const T & v) +{ + PushVar< T >(DefaultVM::Get(), v); + Var< Object > var(DefaultVM::Get(), -1); + sq_pop(DefaultVM::Get(), 1); + return var.value; +} + +/* ------------------------------------------------------------------------------------------------ + * Create a script object from the specified value on the specified VM. +*/ +template < typename T > Object MakeObject(HSQUIRRELVM vm, const T & v) +{ + PushVar< T >(vm, v); + Var< Object > var(vm, -1); + sq_pop(vm, 1); + return var.value; +} + +/* ------------------------------------------------------------------------------------------------ + * Simple function to check whether the specified string can be considered as a boolean value +*/ +bool SToB(CSStr str); + +/* ------------------------------------------------------------------------------------------------ + * Generate a formatted string and throw it as a sqrat exception. +*/ +void SqThrowF(CCStr fmt, ...); + +/* ------------------------------------------------------------------------------------------------ + * Quickly generate a formatted string on a small static buffer without any memory allocations. +*/ +CSStr ToStrF(CCStr fmt, ...); + +/* ------------------------------------------------------------------------------------------------ + * Generate a formatted string on a temporary buffer and return the string but not the buffer. +*/ +CSStr ToStringF(CCStr fmt, ...); + +/* ------------------------------------------------------------------------------------------------ + * Obtain a randomly chosen color from a list of known colors. +*/ +const Color3 & GetRandomColor(); + +/* ------------------------------------------------------------------------------------------------ + * Attempt to identify the color in the specified name and return it. +*/ +Color3 GetColor(CSStr name); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the AABB type from a string. +*/ +const AABB & GetAABB(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Circle type from a string. +*/ +const Circle & GetCircle(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Color3 type from a string. +*/ +const Color3 & GetColor3(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Color4 type from a string. +*/ +const Color4 & GetColor4(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Quaternion type from a string. +*/ +const Quaternion & GetQuaternion(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Sphere type from a string. +*/ +const Sphere & GetSphere(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Vector2 type from a string. +*/ +const Vector2 & GetVector2(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Vector2i type from a string. +*/ +const Vector2i & GetVector2i(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Vector3 type from a string. +*/ +const Vector3 & GetVector3(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Extract the values for components of the Vector4 type from a string. +*/ +const Vector4 & GetVector4(CSStr str, SQChar delim); + +/* ------------------------------------------------------------------------------------------------ + * Forward declarations of the logging functions to avoid including the logger everywhere. +*/ + // ------------------------------------------------------------------------------------------------ void LogDbg(CCStr fmt, ...); void LogUsr(CCStr fmt, ...); @@ -180,84 +381,6 @@ bool cLogSWrn(bool cond, CCStr fmt, ...); bool cLogSErr(bool cond, CCStr fmt, ...); bool cLogSFtl(bool cond, CCStr fmt, ...); -// ------------------------------------------------------------------------------------------------ -void SqThrow(CCStr fmt, ...); - -/* ------------------------------------------------------------------------------------------------ - * Output a message only if the _DEBUG was defined. -*/ -void OutputDebug(const char * msg, ...); - -/* ------------------------------------------------------------------------------------------------ - * Output a formatted user message to the console. -*/ -void OutputMessage(const char * msg, ...); - -/* ------------------------------------------------------------------------------------------------ - * Output a formatted error message to the console. -*/ -void OutputError(const char * msg, ...); - -// ------------------------------------------------------------------------------------------------ -Object & NullObject(); - -// ------------------------------------------------------------------------------------------------ -Array & NullArray(); - -// ------------------------------------------------------------------------------------------------ -Function & NullFunction(); - -// ------------------------------------------------------------------------------------------------ -template < typename T > Object MakeObject(const T & v) -{ - PushVar< T >(DefaultVM::Get(), v); - Var< Object > var(DefaultVM::Get(), -1); - sq_pop(DefaultVM::Get(), 1); - return var.value; -} - -// ------------------------------------------------------------------------------------------------ -template < typename T > Object MakeObject(HSQUIRRELVM vm, const T & v) -{ - PushVar< T >(vm, v); - Var< Object > var(vm, -1); - sq_pop(vm, 1); - return var.value; -} - -/* ------------------------------------------------------------------------------------------------ - * Simple function to check whether the specified string can be considered as a boolean value -*/ -bool SToB(CSStr str); - -/* ------------------------------------------------------------------------------------------------ - * -*/ -CSStr ToStrF(CCStr fmt, ...); - -/* ------------------------------------------------------------------------------------------------ - * -*/ -CSStr ToStringF(CCStr fmt, ...); - -// ------------------------------------------------------------------------------------------------ -const Color3 & GetRandomColor(); - -/* ------------------------------------------------------------------------------------------------ - * Value extractors. -*/ -Color3 GetColor(CSStr name); -AABB GetAABB(CSStr str, SQChar delim); -Circle GetCircle(CSStr str, SQChar delim); -Color3 GetColor3(CSStr str, SQChar delim); -Color4 GetColor4(CSStr str, SQChar delim); -Quaternion GetQuaternion(CSStr str, SQChar delim); -Sphere GetSphere(CSStr str, SQChar delim); -Vector2 GetVector2(CSStr str, SQChar delim); -Vector2i GetVector2i(CSStr str, SQChar delim); -Vector3 GetVector3(CSStr str, SQChar delim); -Vector4 GetVector4(CSStr str, SQChar delim); - } // Namespace:: SqMod #endif // _BASE_SHARED_HPP_ diff --git a/source/Base/Sphere.cpp b/source/Base/Sphere.cpp index 232e482d..fafaff1f 100644 --- a/source/Base/Sphere.cpp +++ b/source/Base/Sphere.cpp @@ -14,6 +14,14 @@ const Sphere Sphere::MAX = Sphere(NumLimit< Sphere::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Sphere::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Sphere::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Sphere"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Sphere::Sphere() : pos(0.0), rad(0.0) @@ -42,27 +50,6 @@ Sphere::Sphere(Value xv, Value yv, Value zv, Value rv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Sphere::Sphere(const Sphere & o) - : pos(o.pos), rad(o.rad) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Sphere::~Sphere() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Sphere & Sphere::operator = (const Sphere & o) -{ - pos = o.pos; - rad = o.rad; - return *this; -} - // ------------------------------------------------------------------------------------------------ Sphere & Sphere::operator = (Value r) { @@ -341,7 +328,7 @@ Int32 Sphere::Cmp(const Sphere & o) const // ------------------------------------------------------------------------------------------------ CSStr Sphere::ToString() const { - return ToStringF("%f,%f,%f,%f", pos.x, pos.y, pos.z, rad); + return ToStrF("%f,%f,%f,%f", pos.x, pos.y, pos.z, rad); } // ------------------------------------------------------------------------------------------------ @@ -395,35 +382,28 @@ void Sphere::Generate() void Sphere::Generate(Value min, Value max, bool r) { if (EpsLt(max, min)) - { - SqThrow("max value is lower than min value"); - } + SqThrowF("max value is lower than min value"); else if (r) - { rad = GetRandomFloat32(min, max); - } else - { pos.Generate(min, max); - } } void Sphere::Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax) { + if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin) || EpsLt(zmax, zmin)) + SqThrowF("max value is lower than min value"); + pos.Generate(xmin, xmax, ymin, ymax, zmin, zmax); } void Sphere::Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax, Value rmin, Value rmax) { - if (EpsLt(rmax, rmin)) - { - SqThrow("max value is lower than min value"); - } - else - { - pos.Generate(xmin, xmax, ymin, ymax, zmin, zmax); - rad = GetRandomFloat32(rmin, rmax); - } + if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin) || EpsLt(zmax, zmin) || EpsLt(rmax, rmin)) + SqThrowF("max value is lower than min value"); + + pos.Generate(xmin, xmax, ymin, ymax, zmin, zmax); + rad = GetRandomFloat32(rmin, rmax); } // ------------------------------------------------------------------------------------------------ @@ -452,6 +432,7 @@ void Register_Sphere(HSQUIRRELVM vm) .Prop(_SC("abs"), &Sphere::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Sphere::ToString) + .SquirrelFunc(_SC("_typename"), &Sphere::Typename) .Func(_SC("_cmp"), &Sphere::Cmp) /* Metamethods */ .Func(_SC("_add"), &Sphere::operator +) diff --git a/source/Base/Sphere.hpp b/source/Base/Sphere.hpp index 6f5e0307..203ed890 100644 --- a/source/Base/Sphere.hpp +++ b/source/Base/Sphere.hpp @@ -9,355 +9,370 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a three-dimensional sphere. */ struct Sphere { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Sphere NIL; static const Sphere MIN; static const Sphere MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The position and radius components of this type. */ Vector3 pos; Value rad; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Sphere(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a sphere at position 0,0,0 using the specified radius. */ Sphere(Value rv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a sphere at the specified position using the specified radius. */ Sphere(const Vector3 & pv, Value rv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a sphere at the specified position using the specified radius. */ Sphere(Value xv, Value yv, Value zv, Value rv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Sphere(const Sphere & o); + Sphere(const Sphere & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Sphere(); + Sphere(Sphere && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Sphere & operator = (const Sphere & o); + ~Sphere() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Sphere & operator = (const Sphere & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Sphere & operator = (Sphere && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Radius assignment operator. */ Sphere & operator = (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Position assignment operator. */ Sphere & operator = (const Vector3 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Sphere & operator += (const Sphere & s); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Sphere & operator -= (const Sphere & s); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Sphere & operator *= (const Sphere & s); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Sphere & operator /= (const Sphere & s); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Sphere & operator %= (const Sphere & s); /* -------------------------------------------------------------------------------------------- - * ... + * Radius addition assignment operator. */ Sphere & operator += (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius subtraction assignment operator. */ Sphere & operator -= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius multiplication assignment operator. */ Sphere & operator *= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius division assignment operator. */ Sphere & operator /= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Radius modulo assignment operator. */ Sphere & operator %= (Value r); /* -------------------------------------------------------------------------------------------- - * ... + * Position addition assignment operator. */ Sphere & operator += (const Vector3 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position subtraction assignment operator. */ Sphere & operator -= (const Vector3 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position multiplication assignment operator. */ Sphere & operator *= (const Vector3 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position division assignment operator. */ Sphere & operator /= (const Vector3 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Position modulo assignment operator. */ Sphere & operator %= (const Vector3 & p); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Sphere & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Sphere & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Sphere operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Sphere operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Sphere operator + (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Sphere operator - (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Sphere operator * (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Sphere operator / (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Sphere operator % (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius addition operator. */ Sphere operator + (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius subtraction operator. */ Sphere operator - (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius multiplication operator. */ Sphere operator * (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius division operator. */ Sphere operator / (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Radius modulo operator. */ Sphere operator % (Value r) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position addition operator. */ Sphere operator + (const Vector3 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position subtraction operator. */ Sphere operator - (const Vector3 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position multiplication operator. */ Sphere operator * (const Vector3 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position division operator. */ Sphere operator / (const Vector3 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Position modulo operator. */ Sphere operator % (const Vector3 & p) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Sphere operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Sphere operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Sphere & s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set the specified radius. */ void Set(Value nr); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the sphere from another instance of this type. */ void Set(const Sphere & ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set the position from the specified position. */ void Set(const Vector3 & np); /* -------------------------------------------------------------------------------------------- - * ... + * Set the specified position and radius. */ void Set(const Vector3 & np, Value nr); /* -------------------------------------------------------------------------------------------- - * ... + * Set the specified position. */ void Set(Value nx, Value ny, Value nz); /* -------------------------------------------------------------------------------------------- - * ... + * Set the specified position and radius. */ void Set(Value nx, Value ny, Value nz, Value nr); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly sized and positioned sphere. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly sized or positioned sphere within the specified bounds. */ void Generate(Value min, Value max, bool r); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly positioned sphere within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax); /* -------------------------------------------------------------------------------------------- - * ... + * Generate a randomly sized and positioned sphere within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax, Value rmin, Value rmax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -365,7 +380,7 @@ struct Sphere } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Sphere Abs() const; }; diff --git a/source/Base/Vector2.cpp b/source/Base/Vector2.cpp index d2213d7a..0ba9694a 100644 --- a/source/Base/Vector2.cpp +++ b/source/Base/Vector2.cpp @@ -15,6 +15,14 @@ const Vector2 Vector2::MAX = Vector2(NumLimit< Vector2::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Vector2::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Vector2::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Vector2"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Vector2::Vector2() : x(0.0), y(0.0) @@ -36,27 +44,6 @@ Vector2::Vector2(Value xv, Value yv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Vector2::Vector2(const Vector2 & o) - : x(o.x), y(o.y) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector2::~Vector2() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector2 & Vector2::operator = (const Vector2 & o) -{ - x = o.x; - y = o.y; - return *this; -} - // ------------------------------------------------------------------------------------------------ Vector2 & Vector2::operator = (Value s) { @@ -290,7 +277,7 @@ Int32 Vector2::Cmp(const Vector2 & o) const // ------------------------------------------------------------------------------------------------ CSStr Vector2::ToString() const { - return ToStringF("%f,%f", x, y); + return ToStrF("%f,%f", x, y); } // ------------------------------------------------------------------------------------------------ @@ -335,27 +322,19 @@ void Vector2::Generate() void Vector2::Generate(Value min, Value max) { if (EpsLt(max, min)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(min, max); - y = GetRandomFloat32(min, max); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(min, max); + y = GetRandomFloat32(min, max); } void Vector2::Generate(Value xmin, Value xmax, Value ymin, Value ymax) { if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(ymin, ymax); - y = GetRandomFloat32(xmin, xmax); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(ymin, ymax); + y = GetRandomFloat32(xmin, xmax); } // ------------------------------------------------------------------------------------------------ @@ -383,6 +362,7 @@ void Register_Vector2(HSQUIRRELVM vm) .Prop(_SC("abs"), &Vector2::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Vector2::ToString) + .SquirrelFunc(_SC("_typename"), &Vector2::Typename) .Func(_SC("_cmp"), &Vector2::Cmp) /* Metamethods */ .Func(_SC("_add"), &Vector2::operator +) diff --git a/source/Base/Vector2.hpp b/source/Base/Vector2.hpp index c0dc7054..d52657f6 100644 --- a/source/Base/Vector2.hpp +++ b/source/Base/Vector2.hpp @@ -8,289 +8,304 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a two-dimensional vector. */ struct Vector2 { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Vector2 NIL; static const Vector2 MIN; static const Vector2 MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The x and y components of this type. */ Value x, y; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Vector2(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the same scalar value for all components. */ Vector2(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the specified component values. */ Vector2(Value xv, Value yv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Vector2(const Vector2 & o); + Vector2(const Vector2 & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Vector2(); + Vector2(Vector2 && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Vector2 & operator = (const Vector2 & o); + ~Vector2() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Vector2 & operator = (const Vector2 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Vector2 & operator = (Vector2 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Vector2 & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * String assignment operator. */ Vector2 & operator = (CSStr values); /* -------------------------------------------------------------------------------------------- - * ... + * Integral two-dimensional vector assignment. */ Vector2 & operator = (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Vector2 & operator += (const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Vector2 & operator -= (const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Vector2 & operator *= (const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Vector2 & operator /= (const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Vector2 & operator %= (const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Vector2 & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Vector2 & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Vector2 & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Vector2 & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Vector2 & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Vector2 & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Vector2 & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Vector2 operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Vector2 operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Vector2 operator + (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Vector2 operator - (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Vector2 operator * (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Vector2 operator / (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Vector2 operator % (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Vector2 operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Vector2 operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Vector2 operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Vector2 operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Vector2 operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Vector2 operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Vector2 operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Vector2 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from an integral two-dimensional vector. */ void Set(const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -298,7 +313,7 @@ struct Vector2 } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Vector2 Abs() const; }; diff --git a/source/Base/Vector2i.cpp b/source/Base/Vector2i.cpp index ebbae282..eb8f6562 100644 --- a/source/Base/Vector2i.cpp +++ b/source/Base/Vector2i.cpp @@ -15,6 +15,14 @@ const Vector2i Vector2i::MAX = Vector2i(NumLimit< Vector2i::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Vector2i::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Vector2i::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Vector2i"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Vector2i::Vector2i() : x(0), y(0) @@ -36,27 +44,6 @@ Vector2i::Vector2i(Value xv, Value yv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Vector2i::Vector2i(const Vector2i & o) - : x(o.x), y(o.y) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector2i::~Vector2i() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector2i & Vector2i::operator = (const Vector2i & o) -{ - x = o.x; - y = o.y; - return *this; -} - // ------------------------------------------------------------------------------------------------ Vector2i & Vector2i::operator = (Value s) { @@ -416,7 +403,7 @@ Int32 Vector2i::Cmp(const Vector2i & o) const // ------------------------------------------------------------------------------------------------ CSStr Vector2i::ToString() const { - return ToStringF("%d,%d", x, y); + return ToStrF("%d,%d", x, y); } // ------------------------------------------------------------------------------------------------ @@ -461,27 +448,19 @@ void Vector2i::Generate() void Vector2i::Generate(Value min, Value max) { if (max < min) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomInt32(min, max); - y = GetRandomInt32(min, max); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomInt32(min, max); + y = GetRandomInt32(min, max); } void Vector2i::Generate(Value xmin, Value xmax, Value ymin, Value ymax) { if (xmax < xmin || ymax < ymin) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomInt32(ymin, ymax); - y = GetRandomInt32(xmin, xmax); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomInt32(ymin, ymax); + y = GetRandomInt32(xmin, xmax); } // ------------------------------------------------------------------------------------------------ @@ -509,6 +488,7 @@ void Register_Vector2i(HSQUIRRELVM vm) .Prop(_SC("abs"), &Vector2i::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Vector2i::ToString) + .SquirrelFunc(_SC("_typename"), &Vector2i::Typename) .Func(_SC("_cmp"), &Vector2i::Cmp) /* Metamethods */ .Func(_SC("_add"), &Vector2i::operator +) diff --git a/source/Base/Vector2i.hpp b/source/Base/Vector2i.hpp index cd17e84b..ae2ebcd7 100644 --- a/source/Base/Vector2i.hpp +++ b/source/Base/Vector2i.hpp @@ -8,394 +8,409 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a two-dimensional vector using integral values. */ struct Vector2i { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef int Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Vector2i NIL; static const Vector2i MIN; static const Vector2i MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The x and y components of this type. */ Value x, y; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Vector2i(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the same scalar value for all components. */ Vector2i(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the specified component values. */ Vector2i(Value xv, Value yv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Vector2i(const Vector2i & o); + Vector2i(const Vector2i & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - ~Vector2i(); + Vector2i(Vector2i && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Vector2i & operator = (const Vector2i & o); + ~Vector2i() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Vector2i & operator = (const Vector2i & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Vector2i & operator = (Vector2i && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Vector2i & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * String assignment operator. */ Vector2i & operator = (CSStr values); /* -------------------------------------------------------------------------------------------- - * ... + * Real two-dimensional vector assignment. */ Vector2i & operator = (const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Vector2i & operator += (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Vector2i & operator -= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Vector2i & operator *= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Vector2i & operator /= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Vector2i & operator %= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise AND assignment operator. */ Vector2i & operator &= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise OR assignment operator. */ Vector2i & operator |= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise XOR assignment operator. */ Vector2i & operator ^= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise left shift assignment operator. */ Vector2i & operator <<= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise right shift assignment operator. */ Vector2i & operator >>= (const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Vector2i & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Vector2i & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Vector2i & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Vector2i & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Vector2i & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise AND assignment operator. */ Vector2i & operator &= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise OR assignment operator. */ Vector2i & operator |= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise XOR assignment operator. */ Vector2i & operator ^= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise left shift assignment operator. */ Vector2i & operator <<= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise right shift assignment operator. */ Vector2i & operator >>= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Vector2i & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Vector2i & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Vector2i operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Vector2i operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Vector2i operator + (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Vector2i operator - (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Vector2i operator * (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Vector2i operator / (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Vector2i operator % (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise AND operator. */ Vector2i operator & (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise OR operator. */ Vector2i operator | (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise XOR operator. */ Vector2i operator ^ (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise shift left operator. */ Vector2i operator << (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise shift right operator. */ Vector2i operator >> (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Vector2i operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Vector2i operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Vector2i operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Vector2i operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Vector2i operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise AND operator. */ Vector2i operator & (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise OR operator. */ Vector2i operator | (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise XOR operator. */ Vector2i operator ^ (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise shift left operator. */ Vector2i operator << (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value bitwise shift right operator. */ Vector2i operator >> (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Vector2i operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Vector2i operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Bitwise NOT operator. */ Vector2i operator ~ () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Vector2i & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Vector2i & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a real two-dimensional vector. */ void Set(const Vector2 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -403,7 +418,7 @@ struct Vector2i } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Vector2i Abs() const; }; diff --git a/source/Base/Vector3.cpp b/source/Base/Vector3.cpp index 6d6f891d..649af30d 100644 --- a/source/Base/Vector3.cpp +++ b/source/Base/Vector3.cpp @@ -16,6 +16,14 @@ const Vector3 Vector3::MAX = Vector3(NumLimit< Vector3::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Vector3::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Vector3::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Vector3"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Vector3::Vector3() : x(0.0), y(0.0), z(0.0) @@ -37,28 +45,6 @@ Vector3::Vector3(Value xv, Value yv, Value zv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Vector3::Vector3(const Vector3 & o) - : x(o.x), y(o.y), z(o.z) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector3::~Vector3() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector3 & Vector3::operator = (const Vector3 & o) -{ - x = o.x; - y = o.y; - z = o.z; - return *this; -} - // ------------------------------------------------------------------------------------------------ Vector3 & Vector3::operator = (Value s) { @@ -310,7 +296,7 @@ Int32 Vector3::Cmp(const Vector3 & o) const // ------------------------------------------------------------------------------------------------ CSStr Vector3::ToString() const { - return ToStringF("%f,%f,%f", x, y, z); + return ToStrF("%f,%f,%f", x, y, z); } // ------------------------------------------------------------------------------------------------ @@ -367,29 +353,21 @@ void Vector3::Generate() void Vector3::Generate(Value min, Value max) { if (EpsLt(max, min)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(min, max); - y = GetRandomFloat32(min, max); - z = GetRandomFloat32(min, max); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(min, max); + y = GetRandomFloat32(min, max); + z = GetRandomFloat32(min, max); } void Vector3::Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax) { if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin) || EpsLt(zmax, zmin)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(xmin, xmax); - y = GetRandomFloat32(ymin, ymax); - z = GetRandomFloat32(zmin, zmax); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(xmin, xmax); + y = GetRandomFloat32(ymin, ymax); + z = GetRandomFloat32(zmin, zmax); } // ------------------------------------------------------------------------------------------------ @@ -418,6 +396,7 @@ void Register_Vector3(HSQUIRRELVM vm) .Prop(_SC("abs"), &Vector3::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Vector3::ToString) + .SquirrelFunc(_SC("_typename"), &Vector3::Typename) .Func(_SC("_cmp"), &Vector3::Cmp) /* Metamethods */ .Func(_SC("_add"), &Vector3::operator +) diff --git a/source/Base/Vector3.hpp b/source/Base/Vector3.hpp index 04156dfa..158d5e7f 100644 --- a/source/Base/Vector3.hpp +++ b/source/Base/Vector3.hpp @@ -8,294 +8,309 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a three-dimensional vector. */ struct Vector3 { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Vector3 NIL; static const Vector3 MIN; static const Vector3 MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The x, y and z components of this type. */ Value x, y, z; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Vector3(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the same scalar value for all components. */ Vector3(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the specified component values. */ Vector3(Value xv, Value yv, Value zv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Vector3(const Vector3 & o); + Vector3(const Vector3 & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - ~Vector3(); + Vector3(Vector3 && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Vector3 & operator = (const Vector3 & o); + ~Vector3() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Vector3 & operator = (const Vector3 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Vector3 & operator = (Vector3 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Vector3 & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Four-dimensional vector assignment. */ Vector3 & operator = (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Quaternion rotation assignment. */ Vector3 & operator = (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Vector3 & operator += (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Vector3 & operator -= (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Vector3 & operator *= (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Vector3 & operator /= (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Vector3 & operator %= (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Vector3 & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Vector3 & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Vector3 & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Vector3 & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Vector3 & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Vector3 & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Vector3 & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Vector3 operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Vector3 operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Vector3 operator + (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Vector3 operator - (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Vector3 operator * (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Vector3 operator / (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Vector3 operator % (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Vector3 operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Vector3 operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Vector3 operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Vector3 operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Vector3 operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Vector3 operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Vector3 operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Vector3 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny, Value nz); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a four-dimensional vector. */ void Set(const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a quaternion rotation. */ void Set(const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -303,7 +318,7 @@ struct Vector3 } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Vector3 Abs() const; }; diff --git a/source/Base/Vector4.cpp b/source/Base/Vector4.cpp index 417252f6..c1fa4c4d 100644 --- a/source/Base/Vector4.cpp +++ b/source/Base/Vector4.cpp @@ -16,6 +16,14 @@ const Vector4 Vector4::MAX = Vector4(NumLimit< Vector4::Value >::Max); // ------------------------------------------------------------------------------------------------ SQChar Vector4::Delim = ','; +// ------------------------------------------------------------------------------------------------ +SQInteger Vector4::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("Vector4"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + // ------------------------------------------------------------------------------------------------ Vector4::Vector4() : x(0.0), y(0.0), z(0.0), w(0.0) @@ -44,29 +52,6 @@ Vector4::Vector4(Value xv, Value yv, Value zv, Value wv) /* ... */ } -// ------------------------------------------------------------------------------------------------ -Vector4::Vector4(const Vector4 & o) - : x(o.x), y(o.y), z(o.z), w(o.w) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector4::~Vector4() -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Vector4 & Vector4::operator = (const Vector4 & o) -{ - x = o.x; - y = o.y; - z = o.z; - w = o.w; - return *this; -} - // ------------------------------------------------------------------------------------------------ Vector4 & Vector4::operator = (Value s) { @@ -335,7 +320,7 @@ Int32 Vector4::Cmp(const Vector4 & o) const // ------------------------------------------------------------------------------------------------ CSStr Vector4::ToString() const { - return ToStringF("%f,%f,%f,%f", x, y, z, w); + return ToStrF("%f,%f,%f,%f", x, y, z, w); } // ------------------------------------------------------------------------------------------------ @@ -405,31 +390,23 @@ void Vector4::Generate() void Vector4::Generate(Value min, Value max) { if (max < min) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(min, max); - y = GetRandomFloat32(min, max); - z = GetRandomFloat32(min, max); - y = GetRandomFloat32(min, max); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(min, max); + y = GetRandomFloat32(min, max); + z = GetRandomFloat32(min, max); + y = GetRandomFloat32(min, max); } void Vector4::Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax, Value wmin, Value wmax) { if (EpsLt(xmax, xmin) || EpsLt(ymax, ymin) || EpsLt(zmax, zmin) || EpsLt(wmax, wmin)) - { - SqThrow("max value is lower than min value"); - } - else - { - x = GetRandomFloat32(xmin, xmax); - y = GetRandomFloat32(ymin, ymax); - z = GetRandomFloat32(zmin, zmax); - y = GetRandomFloat32(ymin, ymax); - } + SqThrowF("max value is lower than min value"); + + x = GetRandomFloat32(xmin, xmax); + y = GetRandomFloat32(ymin, ymax); + z = GetRandomFloat32(zmin, zmax); + y = GetRandomFloat32(ymin, ymax); } // ------------------------------------------------------------------------------------------------ @@ -460,6 +437,7 @@ void Register_Vector4(HSQUIRRELVM vm) .Prop(_SC("abs"), &Vector4::Abs) /* Core Metamethods */ .Func(_SC("_tostring"), &Vector4::ToString) + .SquirrelFunc(_SC("_typename"), &Vector4::Typename) .Func(_SC("_cmp"), &Vector4::Cmp) /* Metamethods */ .Func(_SC("_add"), &Vector4::operator +) diff --git a/source/Base/Vector4.hpp b/source/Base/Vector4.hpp index b75123c7..7128989e 100644 --- a/source/Base/Vector4.hpp +++ b/source/Base/Vector4.hpp @@ -8,304 +8,319 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * + * Class used to represent a four-dimensional vector. */ struct Vector4 { /* -------------------------------------------------------------------------------------------- - * ... + * The type of value used by components of type. */ typedef float Value; /* -------------------------------------------------------------------------------------------- - * ... + * Helper instances for common values mostly used as return types or comparison. */ static const Vector4 NIL; static const Vector4 MIN; static const Vector4 MAX; /* -------------------------------------------------------------------------------------------- - * ... + * The delimiter character to be used when extracting values from strings. */ static SQChar Delim; /* -------------------------------------------------------------------------------------------- - * ... + * The x, y, z and w components of this type. */ Value x, y, z, w; /* -------------------------------------------------------------------------------------------- - * + * Default constructor. */ Vector4(); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the same scalar value for all components. */ Vector4(Value sv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the specified component values. */ Vector4(Value xv, Value yv, Value zv); /* -------------------------------------------------------------------------------------------- - * ... + * Construct a vector with the specified component values. */ Vector4(Value xv, Value yv, Value zv, Value wv); /* -------------------------------------------------------------------------------------------- - * + * Copy constructor. */ - Vector4(const Vector4 & o); + Vector4(const Vector4 & o) = default; /* -------------------------------------------------------------------------------------------- - * + * Move constructor. */ - ~Vector4(); + Vector4(Vector4 && o) = default; /* -------------------------------------------------------------------------------------------- - * + * Destructor. */ - Vector4 & operator = (const Vector4 & o); + ~Vector4() = default; /* -------------------------------------------------------------------------------------------- - * ... + * Copy assignment operator. + */ + Vector4 & operator = (const Vector4 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Vector4 & operator = (Vector4 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Scalar value assignment operator. */ Vector4 & operator = (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Three-dimensional vector assignment operator. */ Vector4 & operator = (const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Quaternion rotation assignment operator. */ Vector4 & operator = (const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Addition assignment operator. */ Vector4 & operator += (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction assignment operator. */ Vector4 & operator -= (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication assignment operator. */ Vector4 & operator *= (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Division assignment operator. */ Vector4 & operator /= (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Modulo assignment operator. */ Vector4 & operator %= (const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition assignment operator. */ Vector4 & operator += (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction assignment operator. */ Vector4 & operator -= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication assignment operator. */ Vector4 & operator *= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division assignment operator. */ Vector4 & operator /= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo assignment operator. */ Vector4 & operator %= (Value s); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-increment operator. */ Vector4 & operator ++ (); /* -------------------------------------------------------------------------------------------- - * ... + * Pre-decrement operator. */ Vector4 & operator -- (); /* -------------------------------------------------------------------------------------------- - * ... + * Post-increment operator. */ Vector4 operator ++ (int); /* -------------------------------------------------------------------------------------------- - * ... + * Post-decrement operator. */ Vector4 operator -- (int); /* -------------------------------------------------------------------------------------------- - * ... + * Addition operator. */ Vector4 operator + (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Subtraction operator. */ Vector4 operator - (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Multiplication operator. */ Vector4 operator * (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Division operator. */ Vector4 operator / (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Modulo operator. */ Vector4 operator % (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value addition operator. */ Vector4 operator + (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value subtraction operator. */ Vector4 operator - (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value multiplication operator. */ Vector4 operator * (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value division operator. */ Vector4 operator / (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Scalar value modulo operator. */ Vector4 operator % (Value s) const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary plus operator. */ Vector4 operator + () const; /* -------------------------------------------------------------------------------------------- - * ... + * Unary minus operator. */ Vector4 operator - () const; /* -------------------------------------------------------------------------------------------- - * ... + * Equality comparison operator. */ bool operator == (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Inequality comparison operator. */ bool operator != (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than comparison operator. */ bool operator < (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than comparison operator. */ bool operator > (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Less than or equal comparison operator. */ bool operator <= (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Greater than or equal comparison operator. */ bool operator >= (const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to compare two instances of this type. */ Int32 Cmp(const Vector4 & v) const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to convert an instance of this type to a string. */ CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * ... + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Set all components to the specified scalar value. */ void Set(Value ns); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny, Value nz); /* -------------------------------------------------------------------------------------------- - * ... + * Set all components to the specified values. */ void Set(Value nx, Value ny, Value nz, Value nw); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from another instance of this type. */ void Set(const Vector4 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a three-dimensional vector. */ void Set(const Vector3 & v); /* -------------------------------------------------------------------------------------------- - * ... + * Copy the values from a quaternion rotation. */ void Set(const Quaternion & q); /* -------------------------------------------------------------------------------------------- - * ... + * Set the values extracted from the specified string using the specified delimiter. */ void Set(CSStr values, SQChar delim); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance. */ void Generate(); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value min, Value max); /* -------------------------------------------------------------------------------------------- - * ... + * Generate random values for all components of this instance within the specified bounds. */ void Generate(Value xmin, Value xmax, Value ymin, Value ymax, Value zmin, Value zmax, Value wmin, Value wmax); /* -------------------------------------------------------------------------------------------- - * ... + * Clear the component values to default. */ void Clear() { @@ -313,7 +328,7 @@ struct Vector4 } /* -------------------------------------------------------------------------------------------- - * ... + * Retrieve a new instance of this type with absolute component values. */ Vector4 Abs() const; }; diff --git a/source/Command.cpp b/source/Command.cpp index 27fbca03..5eef9f13 100644 --- a/source/Command.cpp +++ b/source/Command.cpp @@ -60,6 +60,7 @@ void CmdManager::Terminate() { if (itr->second) { + // Release the local command callbacks itr->second->m_OnExec.ReleaseGently(); itr->second->m_OnAuth.ReleaseGently(); itr->second->m_OnPost.ReleaseGently(); @@ -68,6 +69,7 @@ void CmdManager::Terminate() } // Release the script resources from this class m_Argv.clear(); + // Release the global callbacks m_OnError.ReleaseGently(); m_OnAuth.ReleaseGently(); } @@ -76,15 +78,17 @@ void CmdManager::Terminate() Int32 CmdManager::Run(Int32 invoker, CCStr command) { // Validate the string command - if (!command || strlen(command) <= 0) + if (!command || *command == 0) { + // Tell the script callback to deal with the error SqError(CMDERR_EMPTY_COMMAND, _SC("Invalid or empty command name"), invoker); + // Execution failed! return -1; } // Save the invoker identifier m_Invoker = invoker; - // Skip whitespace until the command name - while (*command == ' ') ++command; + // Skip white-space until the command name + while (isspace(*command)) ++command; // Find where the command name ends CCStr split = strchr(command, ' '); // Are there any arguments specified? @@ -93,7 +97,7 @@ Int32 CmdManager::Run(Int32 invoker, CCStr command) // Save the command name m_Command.assign(command, (split - command)); // Skip white space after command name - while (*split == ' ') ++split; + while (isspace(*split)) ++split; // Save the command argument m_Argument.assign(split); } @@ -106,7 +110,9 @@ Int32 CmdManager::Run(Int32 invoker, CCStr command) // Did anything remain after cleaning? if (m_Command.empty()) { + // Tell the script callback to deal with the error SqError(CMDERR_INVALID_COMMAND, _SC("Cannot execute invalid command name"), invoker); + // Execution failed! return -1; } // Attempt to find the specified command @@ -114,14 +120,19 @@ Int32 CmdManager::Run(Int32 invoker, CCStr command) // Have we found anything? if (itr == m_Commands.end()) { - SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command.c_str()); + // Tell the script callback to deal with the error + SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command); + // Execution failed! return -1; } // Is the command instance valid? (just in case) else if (!itr->second) { + // There's no point in keeping this command anymore m_Commands.erase(itr); + // Tell the script callback to deal with the error SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command.c_str()); + // Execution failed! return -1; } // Save the command instance @@ -137,10 +148,11 @@ Int32 CmdManager::Run(Int32 invoker, CCStr command) } catch (...) { + // Tell the script callback to deal with the error SqError(CMDERR_EXECUTION_FAILED, _SC("Exceptions occurred during execution"), m_Invoker); } // Remove the lock from the command - m_Instance->m_Protected = false; + m_Instance->m_Locked = false; // Release the command instance m_Instance = NULL; // Return the result @@ -157,15 +169,17 @@ Int32 CmdManager::Exec() // Make sure the invoker has enough authority to execute this command if (!m_Instance->AuthCheckID(m_Invoker)) { + // Tell the script callback to deal with the error SqError(CMDERR_INSUFFICIENT_AUTH, _SC("Insufficient authority to execute command"), m_Invoker); - // Command failed + // Execution failed! return -1; } // Make sure an executer was specified else if (m_Instance->GetOnExec().IsNull()) { + // Tell the script callback to deal with the error SqError(CMDERR_MISSING_EXECUTER, _SC("No executer was specified for this command"), m_Invoker); - // Command failed + // Execution failed! return -1; } // See if there are any arguments to parse @@ -177,15 +191,17 @@ Int32 CmdManager::Exec() // Make sure we have enough arguments specified else if (m_Instance->GetMinArgC() > m_Argc) { + // Tell the script callback to deal with the error SqError(CMDERR_INCOMPLETE_ARGS, _SC("Incomplete command arguments"), m_Instance->GetMinArgC()); - // Command failed + // Execution failed! return -1; } // The check during the parsing may omit the last argument else if (m_Instance->GetMaxArgC() < m_Argc) { + // Tell the script callback to deal with the error SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), m_Instance->GetMaxArgC()); - // Command failed + // Execution failed! return -1; } // Check argument types against the command specifiers @@ -193,13 +209,18 @@ Int32 CmdManager::Exec() { if (!m_Instance->ArgCheck(arg, m_Argv[arg].first)) { + // Tell the script callback to deal with the error SqError(CMDERR_UNSUPPORTED_ARG, _SC("Unsupported command argument"), arg); - // Command failed + // Execution failed! return -1; } } // Result of the command execution SQInteger result = -1; + // Clear any data from the buffer to make room for the error message + m_Buffer.At(0) = 0; + // Whether the command execution failed + bool failed = false; // Do we have to call the command with an associative container? if (m_Instance->m_Associate) { @@ -210,17 +231,23 @@ Int32 CmdManager::Exec() { // Do we have use the argument index as the key? if (m_Instance->m_ArgTags[arg].empty()) - { args.SetValue(SQInteger(arg), m_Argv[arg].second); - } // Nope, we have a name for this argument! else - { args.SetValue(m_Instance->m_ArgTags[arg].c_str(), m_Argv[arg].second); - } } // Attempt to execute the command with the specified arguments - result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args); + try + { + result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args); + } + catch (const Sqrat::Exception & e) + { + // Let's store the exception message + m_Buffer.Write(0, e.Message().c_str(), e.Message().size()); + // Specify that the command execution failed + failed = true; + } } else { @@ -228,40 +255,78 @@ Int32 CmdManager::Exec() Array args(DefaultVM::Get(), m_Argc); // Copy the arguments into the array for (Uint32 arg = 0; arg < m_Argc; ++arg) - { args.Bind(SQInteger(arg), m_Argv[arg].second); - } // Attempt to execute the command with the specified arguments - result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args); + try + { + result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args); + } + catch (const Sqrat::Exception & e) + { + // Let's store the exception message + m_Buffer.Write(0, e.Message().c_str(), e.Message().size()); + // Specify that the command execution failed + failed = true; + } } - // See if an error occurred or an exception was thrown - if (Error::Occurred(DefaultVM::Get())) + // Was there a runtime exception during the execution? + if (failed) { - SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"), - Error::Message(DefaultVM::Get()).c_str()); + // Tell the script callback to deal with the error + SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"), m_Buffer.Data()); + // Is there a script callback that handles failures? if (!m_Instance->m_OnFail.IsNull()) { - m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result); + // Then attempt to relay the result to that function + try + { + m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result); + } + catch (const Sqrat::Exception & e) + { + // Tell the script callback to deal with the error + SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.Message()); + } } // Result is invalid at this point result = -1; } - // See if the command failed explicitly + // Was the command aborted explicitly? else if (!result) { - SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"), - _SC("executor evaluated to false")); + // Tell the script callback to deal with the error + SqError(CMDERR_EXECUTION_ABORTED, _SC("Command execution aborted"), result); + // Is there a script callback that handles failures? if (!m_Instance->m_OnFail.IsNull()) { - m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result); + // Then attempt to relay the result to that function + try + { + m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result); + } + catch (const Sqrat::Exception & e) + { + // Tell the script callback to deal with the error + SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.Message()); + } } } + // Is there a callback that must be executed after a successful execution? else if (!m_Instance->m_OnPost.IsNull()) { - m_Instance->m_OnPost.Execute(_Core->GetPlayer(m_Invoker).mObj, result); + // Then attempt to relay the result to that function + try + { + m_Instance->m_OnPost.Execute(_Core->GetPlayer(m_Invoker).mObj, result); + } + catch (const Sqrat::Exception & e) + { + // Tell the script callback to deal with the error + SqError(CMDERR_POST_PROCESSING_FAILED, _SC("Unable to complete command post processing"), e.Message()); + } } // Return the result - return Int32(result); + return static_cast< Int32 >(result); } // ------------------------------------------------------------------------------------------------ @@ -270,7 +335,7 @@ bool CmdManager::Parse() // Is there anything to parse? if (m_Argument.empty()) { - return true; /* Done parsing */ + return true; // Done parsing! } // Obtain the flags of the currently processed argument Uint8 arg_flags = m_Instance->m_ArgSpec[m_Argc]; @@ -291,12 +356,11 @@ bool CmdManager::Parse() prev = elem, elem = *itr; // See if there's anything left to parse if (elem == 0) - { break; - } // Early check to prevent parsing extraneous arguments else if (m_Argc >= max_arg) { + // Tell the script callback to deal with the error SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), max_arg); // Parsing aborted good = false; @@ -306,28 +370,19 @@ bool CmdManager::Parse() // Is this a greedy argument? else if (arg_flags & CMDARG_GREEDY) { - // Skip whitespace - while (*itr == ' ' && itr != m_Argument.end()) ++itr; - // Anything left to copy? + // Skip white-space characters + while (itr != m_Argument.end() && isspace(*itr)) ++itr; + // Anything left to copy to the argument? if (itr != m_Argument.end()) - { // Transform it into a script object sq_pushstring(DefaultVM::Get(), &(*itr), std::distance(itr, m_Argument.end())); - } // Just push an empty string else - { sq_pushstring(DefaultVM::Get(), _SC(""), 0); - } - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value)); + sq_pop(DefaultVM::Get(), 1); // Include this argument into the count ++m_Argc; // Nothing left to parse @@ -338,7 +393,7 @@ bool CmdManager::Parse() { // Obtain the beginning and ending of the internal buffer SStr str = m_Buffer.Begin< SQChar >(); - CSStr end = (m_Buffer.End< SQChar >()-1); /* + null */ + CSStr end = (m_Buffer.End< SQChar >()-1); // + null terminator // Save the closing quote type SQChar close = elem; // Skip the opening quote @@ -351,6 +406,7 @@ bool CmdManager::Parse() // See if there's anything left to parse if (elem == 0) { + // Tell the script callback to deal with the error SqError(CMDERR_SYNTAX_ERROR, _SC("String argument not closed properly"), m_Argc); // Parsing aborted good = false; @@ -370,9 +426,7 @@ bool CmdManager::Parse() } // Overwrite last character when replicating else - { --str; - } } // See if the internal buffer needs to scale else if (str >= end) @@ -391,44 +445,33 @@ bool CmdManager::Parse() } // See if the argument was valid if (!good) - { // Propagate failure break; - } // Do we have to make the string lowercase? else if (arg_flags & CMDARG_LOWER) { for (SStr chr = m_Buffer.Begin< SQChar >(); chr <= str; ++chr) - { - *chr = (SQChar)tolower(*chr); - } + *chr = static_cast< SQChar >(tolower(*chr)); } // Do we have to make the string uppercase? else if (arg_flags & CMDARG_UPPER) { for (SStr chr = m_Buffer.Begin< SQChar >(); chr <= str; ++chr) - { - *chr = (SQChar)toupper(*chr); - } + *chr = static_cast< SQChar >(toupper(*chr)); } // Transform it into a script object sq_pushstring(DefaultVM::Get(), m_Buffer.Get< SQChar >(), str - m_Buffer.Begin< SQChar >()); - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value)); + sq_pop(DefaultVM::Get(), 1); // Advance to the next argument and obtain its flags arg_flags = m_Instance->m_ArgSpec[++m_Argc]; } - // Ignore space characters until another valid character is found - else if (elem != ' ' && (prev == ' ' || prev == 0)) + // Ignore white-space characters until another valid character is found + else if (!isspace(elem) && (isspace(prev) || prev == 0)) { - // Find the first character that marks the end of the argument + // Find the first space character that marks the end of the argument String::iterator pos = std::find(String::iterator(itr), m_Argument.end(), ' '); // Copy all characters within range into the internal buffer const Uint32 sz = m_Buffer.Write(0, &(*itr), std::distance(itr, pos)); @@ -446,21 +489,16 @@ bool CmdManager::Parse() // Let's us know if the whole argument was part of the resulted value CStr next = NULL; // Attempt to extract the integer value from the string - Int64 value = strtol(m_Buffer.Data(), &next, 10); + LongI value = strtol(m_Buffer.Data(), &next, 10); // See if this whole string was indeed an integer if (next == &m_Buffer.At< SQChar >(sz)) { // Transform it into a script object - Var< SQInteger >::push(DefaultVM::Get(), SQInteger(value)); - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + sq_pushinteger(DefaultVM::Get(), static_cast< SQInteger >(value)); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_INTEGER, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_INTEGER, var.value)); + sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } @@ -471,21 +509,20 @@ bool CmdManager::Parse() // Let's us know if the whole argument was part of the resulted value CStr next = NULL; // Attempt to extract the floating point value from the string +#ifdef SQUSEDOUBLE Float64 value = strtod(m_Buffer.Data(), &next); +#else + Float32 value = strtof(m_Buffer.Data(), &next); +#endif // SQUSEDOUBLE // See if this whole string was indeed an floating point if (next == &m_Buffer.At< SQChar >(sz)) { // Transform it into a script object - Var< SQFloat >::push(DefaultVM::Get(), SQFloat(value)); - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + sq_pushfloat(DefaultVM::Get(), static_cast< SQFloat >(value)); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_FLOAT, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_FLOAT, var.value)); + sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } @@ -499,23 +536,16 @@ bool CmdManager::Parse() snprintf (lc, 6, "%.5s", m_Buffer.Data()); // Convert all characters to lowercase for (Uint32 i = 0; i < 5; ++i) - { lc[i] = tolower(lc[i]); - } // Is this a boolean true value? if (strcmp(m_Buffer.Data(), "true") == 0 || strcmp(m_Buffer.Data(), "on") == 0) { // Transform it into a script object - Var< bool >::push(DefaultVM::Get(), true); - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + sq_pushbool(DefaultVM::Get(), true); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_BOOLEAN, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_BOOLEAN, var.value)); + sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } @@ -523,16 +553,11 @@ bool CmdManager::Parse() else if (strcmp(m_Buffer.Data(), "false") == 0 || strcmp(m_Buffer.Data(), "off") == 0) { // Transform it into a script object - Var< bool >::push(DefaultVM::Get(), false); - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + sq_pushbool(DefaultVM::Get(), false); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_BOOLEAN, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_BOOLEAN, var.value)); + sq_pop(DefaultVM::Get(), 1); // We identified the correct value identified = true; } @@ -544,38 +569,27 @@ bool CmdManager::Parse() if (arg_flags & CMDARG_LOWER) { for (Uint32 n = 0; n < sz; ++n) - { - m_Buffer.At< SQChar >(n) = (SQChar)tolower(m_Buffer.At< SQChar >(n)); - } + m_Buffer.At< SQChar >(n) = static_cast< SQChar >(tolower(m_Buffer.At< SQChar >(n))); } // Do we have to make the string uppercase? else if (arg_flags & CMDARG_UPPER) { for (Uint32 n = 0; n < sz; ++n) - { - m_Buffer.At< SQChar >(n) = (SQChar)toupper(m_Buffer.At< SQChar >(n)); - } + m_Buffer.At< SQChar >(n) = static_cast< SQChar >(toupper(m_Buffer.At< SQChar >(n))); } // Transform it into a script object sq_pushstring(DefaultVM::Get(), m_Buffer.Get< SQChar >(), sz); - // Get the object from the stack - Var< Object & > var(DefaultVM::Get(), -1); + // Get the object from the stack and add it to the argument list along with it's type + m_Argv.emplace_back(CMDARG_STRING, Var< Object >(DefaultVM::Get(), -1).value); // Pop the created object from the stack - if (!var.value.IsNull()) - { - sq_pop(DefaultVM::Get(), 1); - } - // Add it to the argument list along with it's type - m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value)); + sq_pop(DefaultVM::Get(), 1); } // Advance to the next argument and obtain its flags arg_flags = m_Instance->m_ArgSpec[++m_Argc]; } // Is there anything left to parse? if (itr >= m_Argument.end()) - { break; - } // Advance to the next character ++itr; } @@ -593,18 +607,26 @@ void CmdListener::Init(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 ma m_ArgSpec[n] = CMDARG_ANY; m_ArgTags[n].assign(""); } + // Default to minimum and maximum arguments m_MinArgc = 0; m_MaxArgc = (SQMOD_MAX_CMD_ARGS - 1); + // Default to no specifiers, help or informational message m_Spec.assign(""); m_Help.assign(""); m_Info.assign(""); + // Use the global authentication inspector m_OnAuth = _Cmd->GetOnAuth(); + // Default to no authority check m_Authority = -1; + // Default to unprotected command m_Protected = false; + // Default to unsuspended command m_Suspended = false; + // Default to non-associative arguments m_Associate = false; + // The command is unlocked to further changes m_Locked = false; - // Set the minimum and maximum allowed arguments + // Set the specified minimum and maximum allowed arguments SetMinArgC(min); SetMaxArgC(max); // Extract the specified argument tags @@ -688,20 +710,19 @@ CSStr CmdListener::GetName() const // ------------------------------------------------------------------------------------------------ void CmdListener::SetName(CSStr name) { + // Is this command locked because it's being executed now? if (m_Locked) - SqThrow("Cannot change locked command: %s", m_Name.c_str()); - else if (!name || strlen(name) <= 0) - SqThrow("Invalid command name: null"); - else - { - // Detach from the current name if necessary - if (!m_Name.empty()) - _Cmd->Detach(name); - // Now it's safe to assign the new name - m_Name.assign(name); - // We know the new name is valid - _Cmd->Attach(m_Name, this); - } + SqThrowF("Cannot rename locked command: %s", m_Name.c_str()); + // Is the command name even valid? + else if (!name || *name == 0) + SqThrowF("Invalid command name: null/empty"); + // Detach from the current name if necessary + if (!m_Name.empty()) + _Cmd->Detach(name); + // Now it's safe to assign the new name + m_Name.assign(name); + // We know the new name is valid + _Cmd->Attach(m_Name, this); } // ------------------------------------------------------------------------------------------------ @@ -713,8 +734,10 @@ CSStr CmdListener::GetSpec() const // ------------------------------------------------------------------------------------------------ void CmdListener::SetSpec(CSStr spec) { - if (ProcSpec(spec)) - m_Spec.assign(spec); + // Attempt to process the specified string + ProcSpec(spec); + // At this point there were no errors + m_Spec.assign(spec); } // ------------------------------------------------------------------------------------------------ @@ -738,16 +761,14 @@ void CmdListener::SetArgTags(Array & tags) if (tags.IsNull() || max == 0) { for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n) - { m_ArgTags[n].assign(""); - } } // See if we're in range else if (max < SQMOD_MAX_CMD_ARGS) // Attempt to get all arguments in one go tags.GetArray(m_ArgTags, max); else - SqThrow("Argument tag (%u) is out of range (%u)", max, SQMOD_MAX_CMD_ARGS); + SqThrowF("Argument tag (%u) is out of range (%u)", max, SQMOD_MAX_CMD_ARGS); } // ------------------------------------------------------------------------------------------------ @@ -831,11 +852,13 @@ Uint8 CmdListener::GetMinArgC() const // ------------------------------------------------------------------------------------------------ void CmdListener::SetMinArgC(Uint8 val) { - // Assuming (m_MaxArgc < SQMOD_MAX_CMD_ARGS) is always true - if (val <= m_MaxArgc) - m_MinArgc = val; - else - SqThrow("Minimum argument (%u) exceeds maximum (%u)", val, m_MaxArgc); + // Perform a range check on the specified argument index + if (val >= SQMOD_MAX_CMD_ARGS) + SqThrowF("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS); + else if (val > m_MaxArgc) + SqThrowF("Minimum argument (%u) exceeds maximum (%u)", val, m_MaxArgc); + // Apply the specified value + m_MinArgc = val; } // ------------------------------------------------------------------------------------------------ @@ -847,12 +870,13 @@ Uint8 CmdListener::GetMaxArgC() const // ------------------------------------------------------------------------------------------------ void CmdListener::SetMaxArgC(Uint8 val) { - if (val < SQMOD_MAX_CMD_ARGS && val >= m_MinArgc) - m_MaxArgc = val; + // Perform a range check on the specified argument index + if (val >= SQMOD_MAX_CMD_ARGS) + SqThrowF("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS); else if (val < m_MinArgc) - SqThrow("Minimum argument (%u) exceeds maximum (%u)", m_MinArgc, val); - else - SqThrow("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS); + SqThrowF("Minimum argument (%u) exceeds maximum (%u)", m_MinArgc, val); + // Apply the specified value + m_MaxArgc = val; } // ------------------------------------------------------------------------------------------------ @@ -870,10 +894,11 @@ Function & CmdListener::GetOnExec() // ------------------------------------------------------------------------------------------------ void CmdListener::SetOnExec(Object & env, Function & func) { - if (!m_Name.empty()) - m_OnExec = Function(env.GetVM(), env.GetObject(), func.GetFunc()); - else - SqThrow("Invalid commands cannot store script resources"); + // Make sure that we are allowed to store script resources + if (m_Name.empty()) + SqThrowF("Invalid commands cannot store script resources"); + // Apply the specified information + m_OnExec = Function(env.GetVM(), env.GetObject(), func.GetFunc()); } // ------------------------------------------------------------------------------------------------ @@ -885,10 +910,11 @@ Function & CmdListener::GetOnAuth() // ------------------------------------------------------------------------------------------------ void CmdListener::SetOnAuth(Object & env, Function & func) { - if (!m_Name.empty()) - m_OnAuth = Function(env.GetVM(), env.GetObject(), func.GetFunc()); - else - SqThrow("Invalid commands cannot store script resources"); + // Make sure that we are allowed to store script resources + if (m_Name.empty()) + SqThrowF("Invalid commands cannot store script resources"); + // Apply the specified information + m_OnAuth = Function(env.GetVM(), env.GetObject(), func.GetFunc()); } // ------------------------------------------------------------------------------------------------ @@ -900,10 +926,11 @@ Function & CmdListener::GetOnPost() // ------------------------------------------------------------------------------------------------ void CmdListener::SetOnPost(Object & env, Function & func) { - if (!m_Name.empty()) - m_OnPost = Function(env.GetVM(), env.GetObject(), func.GetFunc()); - else - SqThrow("Invalid commands cannot store script resources"); + // Make sure that we are allowed to store script resources + if (m_Name.empty()) + SqThrowF("Invalid commands cannot store script resources"); + // Apply the specified information + m_OnPost = Function(env.GetVM(), env.GetObject(), func.GetFunc()); } // ------------------------------------------------------------------------------------------------ @@ -915,28 +942,35 @@ Function & CmdListener::GetOnFail() // ------------------------------------------------------------------------------------------------ void CmdListener::SetOnFail(Object & env, Function & func) { - if (!m_Name.empty()) - m_OnFail = Function(env.GetVM(), env.GetObject(), func.GetFunc()); - else - SqThrow("Invalid commands cannot store script resources"); + // Make sure that we are allowed to store script resources + if (m_Name.empty()) + SqThrowF("Invalid commands cannot store script resources"); + // Apply the specified information + m_OnFail = Function(env.GetVM(), env.GetObject(), func.GetFunc()); } // ------------------------------------------------------------------------------------------------ CSStr CmdListener::GetArgTag(Uint32 arg) const { - if (arg < SQMOD_MAX_CMD_ARGS) - return m_ArgTags[arg].c_str(); - SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS); - return g_EmptyStr; + // Perform a range check on the specified argument index + if (arg >= SQMOD_MAX_CMD_ARGS) + SqThrowF("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS); + // Return the requested information + return m_ArgTags[arg].c_str(); } // ------------------------------------------------------------------------------------------------ void CmdListener::SetArgTag(Uint32 arg, CSStr name) { - if (arg < SQMOD_MAX_CMD_ARGS) + // Perform a range check on the specified argument index + if (arg >= SQMOD_MAX_CMD_ARGS) + SqThrowF("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS); + // The string type doesn't appreciate null values + else if (name) m_ArgTags[arg].assign(name); + // Clear previous name in this case else - SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS); + m_ArgTags[arg].clear(); } // ------------------------------------------------------------------------------------------------ @@ -970,85 +1004,83 @@ void CmdListener::GenerateInfo(bool full) break; } // Begin the argument block - m_Info += '<'; + m_Info.push_back('<'); // If the current argument is beyond minimum then mark it as optional if (arg >= m_MinArgc) - m_Info += '*'; + m_Info.push_back('*'); // If the argument has a tag/name associated then add it as well if (!m_ArgTags[arg].empty()) { // Add the name first - m_Info += m_ArgTags[arg]; + m_Info.append(m_ArgTags[arg]); // Separate the name from the specifiers - m_Info += ':'; + m_Info.push_back(':'); } + // Obtain the argument specifier + const Uint8 spec = m_ArgSpec[arg]; // Is this a greedy argument? - if (m_ArgSpec[arg] & CMDARG_GREEDY) - { - m_Info += _SC("..."); - } + if (spec & CMDARG_GREEDY) + m_Info.append("..."); // If the argument has any explicit types specified - else if (m_ArgSpec[arg] != CMDARG_ANY) + else if (spec != CMDARG_ANY) { // Does it support integers? - if (m_ArgSpec[arg] & CMDARG_INTEGER) - m_Info += _SC("integer"); + if (spec & CMDARG_INTEGER) + m_Info.append("integer"); // Does it support floats? - if (m_ArgSpec[arg] & CMDARG_FLOAT) + if (spec & CMDARG_FLOAT) { - // Add a separator if this is not the first enabled type? - if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<') - m_Info += ','; + // Add a separator if this is not the first enabled type! + if (m_Info.back() != ':' && m_Info.back() != '<') + m_Info.push_back(','); // Now add the type name - m_Info += _SC("float"); + m_Info.append("float"); } // Does it support booleans? - if (m_ArgSpec[arg] & CMDARG_BOOLEAN) + if (spec & CMDARG_BOOLEAN) { - // Add a separator if this is not the first enabled type? - if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<') - m_Info += ','; + // Add a separator if this is not the first enabled type! + if (m_Info.back() != ':' && m_Info.back() != '<') + m_Info.push_back(','); // Now add the type name - m_Info += _SC("boolean"); + m_Info.append("boolean"); } // Does it support strings? - if (m_ArgSpec[arg] & CMDARG_STRING) + if (spec & CMDARG_STRING) { // Add a separator if this is not the first enabled type? - if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<') - m_Info += ','; + if (m_Info.back() != ':' && m_Info.back() != '<') + m_Info.push_back(','); // Now add the type name - m_Info += _SC("string"); + m_Info.append("string"); } } // Any kind of value is supported by this argument else - m_Info += _SC("any"); - // Stop the argument block - m_Info += '>'; + m_Info.append("any"); + // Terminate the argument block + m_Info.push_back('>'); // Don't process anything after greedy arguments - if (m_ArgSpec[arg] & CMDARG_GREEDY) - { + if (spec & CMDARG_GREEDY) break; - } // If this is not the last argument then add a separator else if (arg+1 != m_MaxArgc) - m_Info += ' '; + m_Info.push_back(' '); } } // ------------------------------------------------------------------------------------------------ bool CmdListener::ArgCheck(Uint32 arg, Uint8 flag) const { - if (arg < SQMOD_MAX_CMD_ARGS) - { - const Uint8 f = m_ArgSpec[arg]; - return (f == CMDARG_ANY) || /* Requires check? */ - (f & flag) || /* Exact match? */ - (f & CMDARG_GREEDY && flag & CMDARG_STRING); - } - SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS); - return false; + // Perform a range check on the specified argument index + if (arg >= SQMOD_MAX_CMD_ARGS) + SqThrowF("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS); + // Retrieve the argument flags + const Uint8 f = m_ArgSpec[arg]; + // Perform the requested check + return (f == CMDARG_ANY) || /* Requires check? */ + (f & flag) || /* Exact match? */ + (f & CMDARG_GREEDY && flag & CMDARG_STRING); } // ------------------------------------------------------------------------------------------------ @@ -1099,131 +1131,112 @@ SQInteger CmdListener::Execute(Object & invoker, Table & args) } // ------------------------------------------------------------------------------------------------ -bool CmdListener::ProcSpec(CSStr str) +void CmdListener::ProcSpec(CSStr str) { // Reset current argument specifiers memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec)); - // Currently processed character - SQChar ch = 0; - // When parsing may continue - bool good = true; + // Make sure we have anything to parse + if (!str || *str == 0) + return; // Currently processed argument Uint32 idx = 0; - // Process each character in the specified command - while (good) + // Try to apply the specified type specifiers + try { - // Extract the current character before advancing - ch = *(str++); - // See if there are still things left to parse - if (ch == 0) - // Finished parsing successfully - break; - // See if we need to move to the next argument - else if (ch == '|') + // Process until null terminator or an error occurs + while (*str != 0) { - if (idx >= SQMOD_MAX_CMD_ARGS) + // See if we need to move to the next argument + if (*str == '|') { - SqThrow("Extraneous type specifiers: %d >= %d", idx, SQMOD_MAX_CMD_ARGS); - // Parsing failed - good = false; - // Stop parsing - break; + if (idx >= SQMOD_MAX_CMD_ARGS) + SqThrowF("Extraneous type specifiers: %d >= %d", idx, SQMOD_MAX_CMD_ARGS); + // Move to the next character + ++str; + // Advance to the next argument + ++idx; } - // Advance to the next argument - ++idx; - } - // Simply ignore a type specifier delimiter - else if (ch != ',') - { - // Consume space when found - if (ch == ' ') - while (good) - { - ch = *(str++); - // Stop when the text ends or on the first non-space character - if (ch == 0 || ch != ' ') - break; - } - // See if there is a specifier left - if (!good) - // Propagate the stop - break; - // Apply the type specifier - switch(ch) + // Simply ignore a type specifier delimiter + else if (*str != ',') { - // Is this a greedy argument? - case 'g': + // Ignore non-alphabetic characters + while (*str != 0 && !isalpha(*str)) ++str; + // Apply the type specifier + switch(*str) { - m_ArgSpec[idx] = CMDARG_GREEDY; - } break; - // Is this a integer type - case 'i': - { - m_ArgSpec[idx] |= CMDARG_INTEGER; - // Disable greedy argument flag if set - if (m_ArgSpec[idx] & CMDARG_GREEDY) - m_ArgSpec[idx] ^= CMDARG_GREEDY; - } break; - // Is this a float type - case 'f': - { - m_ArgSpec[idx] |= CMDARG_FLOAT; - // Disable greedy argument flag if set - if (m_ArgSpec[idx] & CMDARG_GREEDY) - m_ArgSpec[idx] ^= CMDARG_GREEDY; - } break; - // Is this a boolean type - case 'b': - { - m_ArgSpec[idx] |= CMDARG_BOOLEAN; - // Disable greedy argument flag if set - if (m_ArgSpec[idx] & CMDARG_GREEDY) - m_ArgSpec[idx] ^= CMDARG_GREEDY; - } break; - // Is this a string type - case 's': - { - m_ArgSpec[idx] |= CMDARG_STRING; - // Disable greedy argument flag if set - if (m_ArgSpec[idx] & CMDARG_GREEDY) - m_ArgSpec[idx] ^= CMDARG_GREEDY; - } break; - // Is this a lowercase string? - case 'l': - { - m_ArgSpec[idx] |= CMDARG_STRING; - m_ArgSpec[idx] |= CMDARG_LOWER; - // Disable greedy argument flag if set - if (m_ArgSpec[idx] & CMDARG_GREEDY) - m_ArgSpec[idx] ^= CMDARG_GREEDY; - } break; - // Is this a uppercase string? - case 'u': - { - m_ArgSpec[idx] |= CMDARG_STRING; - m_ArgSpec[idx] |= CMDARG_UPPER; - // Disable greedy argument flag if set - if (m_ArgSpec[idx] & CMDARG_GREEDY) - m_ArgSpec[idx] ^= CMDARG_GREEDY; - } break; - // Unknown type! - default: + // Did we reached the end of the string? + case '\0': + break; + // Is this a greedy argument? + case 'g': { - SqThrow("Unknown type specifier (%c) at argument: %u", ch, idx); - // Parsing failed - good = false; - } - break; + m_ArgSpec[idx] = CMDARG_GREEDY; + } break; + // Is this a integer type + case 'i': + { + m_ArgSpec[idx] |= CMDARG_INTEGER; + // Disable greedy argument flag if set + if (m_ArgSpec[idx] & CMDARG_GREEDY) + m_ArgSpec[idx] ^= CMDARG_GREEDY; + } break; + // Is this a float type + case 'f': + { + m_ArgSpec[idx] |= CMDARG_FLOAT; + // Disable greedy argument flag if set + if (m_ArgSpec[idx] & CMDARG_GREEDY) + m_ArgSpec[idx] ^= CMDARG_GREEDY; + } break; + // Is this a boolean type + case 'b': + { + m_ArgSpec[idx] |= CMDARG_BOOLEAN; + // Disable greedy argument flag if set + if (m_ArgSpec[idx] & CMDARG_GREEDY) + m_ArgSpec[idx] ^= CMDARG_GREEDY; + } break; + // Is this a string type + case 's': + { + m_ArgSpec[idx] |= CMDARG_STRING; + // Disable greedy argument flag if set + if (m_ArgSpec[idx] & CMDARG_GREEDY) + m_ArgSpec[idx] ^= CMDARG_GREEDY; + } break; + // Is this a lowercase string? + case 'l': + { + m_ArgSpec[idx] |= CMDARG_STRING; + m_ArgSpec[idx] |= CMDARG_LOWER; + // Disable greedy argument flag if set + if (m_ArgSpec[idx] & CMDARG_GREEDY) + m_ArgSpec[idx] ^= CMDARG_GREEDY; + } break; + // Is this a uppercase string? + case 'u': + { + m_ArgSpec[idx] |= CMDARG_STRING; + m_ArgSpec[idx] |= CMDARG_UPPER; + // Disable greedy argument flag if set + if (m_ArgSpec[idx] & CMDARG_GREEDY) + m_ArgSpec[idx] ^= CMDARG_GREEDY; + } break; + // Unknown type! + default: SqThrowF("Unknown type specifier (%c) at argument: %u", *str, idx); + } } } } - // Reset all argument specifiers if failed - if (!good) + catch (const Sqrat::Exception & e) + { + // Reset all argument specifiers if failed memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec)); + // Propagate the exception back to the caller + throw e; + } // Attempt to generate an informational message GenerateInfo(false); - // Return whether the parsing was successful - return good; } /* ------------------------------------------------------------------------------------------------ @@ -1369,8 +1382,11 @@ void Register_Command(HSQUIRRELVM vm) .Const(_SC("IncompleteArgs"), CMDERR_INCOMPLETE_ARGS) .Const(_SC("ExtraneousArgs"), CMDERR_EXTRANEOUS_ARGS) .Const(_SC("UnsupportedArg"), CMDERR_UNSUPPORTED_ARG) - .Const(_SC("ExecutionFailed"), CMDERR_EXECUTION_FAILED) .Const(_SC("BufferOverflow"), CMDERR_BUFFER_OVERFLOW) + .Const(_SC("ExecutionFailed"), CMDERR_EXECUTION_FAILED) + .Const(_SC("ExecutionAborted"), CMDERR_EXECUTION_ABORTED) + .Const(_SC("PostProcessingFailed"), CMDERR_POST_PROCESSING_FAILED) + .Const(_SC("UnresolvedFailure"), CMDERR_UNRESOLVED_FAILURE) .Const(_SC("Max"), CMDERR_MAX) ); } diff --git a/source/Command.hpp b/source/Command.hpp index 1339e53c..0ddbf21c 100644 --- a/source/Command.hpp +++ b/source/Command.hpp @@ -165,10 +165,19 @@ protected: */ template < typename T > void SqError(Int32 type, CSStr msg, T data) { - if (!m_OnError.IsNull()) + // Is there a callback that deals with errors? + if (m_OnError.IsNull()) + return; + // Attempt to forward the error to that callback + try { m_OnError.Execute< Int32, CSStr, T >(type, msg, data); } + catch (const Sqrat::Exception & e) + { + // We can only log this incident and in the future maybe also include the location + LogErr("Command error callback failed [%s]", e.Message().c_str()); + } } /* -------------------------------------------------------------------------------------------- @@ -350,7 +359,7 @@ protected: /* -------------------------------------------------------------------------------------------- * */ - bool ProcSpec(CSStr spec); + void ProcSpec(CSStr spec); private: diff --git a/source/Core.cpp b/source/Core.cpp index 12f5b49c..7dc235f8 100644 --- a/source/Core.cpp +++ b/source/Core.cpp @@ -48,13 +48,6 @@ extern void TerminateCommand(); // ------------------------------------------------------------------------------------------------ Core * _Core = NULL; -// ------------------------------------------------------------------------------------------------ -static void CalculateStringIDs(SQChar arr[][8], Uint32 num) -{ - for (Uint32 n = 0; n < num; n++) - snprintf(arr[n], 8, "%d", n); -} - // ------------------------------------------------------------------------------------------------ Core::Core() : m_State(0) @@ -100,19 +93,6 @@ bool Core::Init() m_Textdraws.resize(SQMOD_TEXTDRAW_POOL); m_Vehicles.resize(SQMOD_VEHICLE_POOL); - LogDbg("Pre-calculating entity string identifiers"); - // Pre-calculate all possible entity IDs for fast string conversion - CalculateStringIDs(CBlip::s_StrID, SQMOD_BLIP_POOL); - CalculateStringIDs(CCheckpoint::s_StrID, SQMOD_CHECKPOINT_POOL); - CalculateStringIDs(CForcefield::s_StrID, SQMOD_FORCEFIELD_POOL); - CalculateStringIDs(CKeybind::s_StrID, SQMOD_KEYBIND_POOL); - CalculateStringIDs(CObject::s_StrID, SQMOD_OBJECT_POOL); - CalculateStringIDs(CPickup::s_StrID, SQMOD_PICKUP_POOL); - CalculateStringIDs(CPlayer::s_StrID, SQMOD_PLAYER_POOL); - CalculateStringIDs(CSprite::s_StrID, SQMOD_SPRITE_POOL); - CalculateStringIDs(CTextdraw::s_StrID, SQMOD_TEXTDRAW_POOL); - CalculateStringIDs(CVehicle::s_StrID, SQMOD_VEHICLE_POOL); - LogDbg("Initializing entity options to defaults"); // Initialize player messaging options to default values for (Players::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) @@ -154,148 +134,130 @@ bool Core::Init() // Attempt to read the database port number try { - Ulong num = strtoul(conf.GetValue("Config", "StackSize", "0"), NULL, 10); - // Make sure that the retrieved number is in range + Ulong num = conf.GetLongValue("Config", "StackSize", SQMOD_STACK_SIZE); + // Make sure that the retrieved number is within range if (!num) - { throw std::out_of_range("stack size too small"); - } - else if (num >= NumLimit< Uint16 >::Max) - { + else if (num >= std::numeric_limits< Uint16 >::max()) throw std::out_of_range("stack size too big"); - } // Save the port number - stack_size = (Uint16)num; + stack_size = static_cast< Uint16 >(num); } catch (const std::exception & e) { - LogWrn("Unable to obtain the stack size [%s]", e.what()); + LogWrn("Unable to obtain a valid stack size [%s]", e.what()); } - LogDbg("Creating virtual machine with a stack size (%d)", stack_size); + LogDbg("Creating a virtual machine with a stack size of (%d)", stack_size); // Attempt to create the VM m_VM = sq_open(stack_size); - + // See if the virtual machine could be created if (cLogFtl(!m_VM, "Unable to create the virtual machine")) { - m_VM = NULL; + // Explicitly prevent further use of this pointer + m_VM = nullptr; + // Unable to load the plugin properly return false; } - - // Set this as the default VM and enable error handling + // Set this as the default VM DefaultVM::Set(m_VM); + // Enable error handling ErrorHandling::Enable(true); LogDbg("Registering the standard libraries"); - // Register the standard library on the root table + // Push the root table on the stack sq_pushroottable(m_VM); + // Register the standard library on the pushed table sqstd_register_iolib(m_VM); sqstd_register_bloblib(m_VM); sqstd_register_mathlib(m_VM); sqstd_register_systemlib(m_VM); sqstd_register_stringlib(m_VM); + // Pop the root table from the stack sq_pop(m_VM, 1); LogDbg("Setting the base output function"); + // Tell the VM to use these functions to output user on error messages sq_setprintfunc(m_VM, PrintFunc, ErrorFunc); LogDbg("Setting the base error handlers"); + // Tell the VM to trigger this function on compile time errors sq_setcompilererrorhandler(m_VM, CompilerErrorHandler); + // Push the runtime error handler on the stack and create a closure sq_newclosure(m_VM, RuntimeErrorHandler, 0); + // Tell the VM to trigger this function on runtime errors sq_seterrorhandler(m_VM); LogDbg("Registering the plug-in API"); + // Attempt to register the plugin API if (cLogFtl(!RegisterAPI(m_VM), "Unable to register the plug-in API")) - return false; + return false; // Can't execute scripts without a valid API! // Attempt to retrieve the list of strings specified in the config CSimpleIniA::TNamesDepend scripts; conf.GetAllValues("Scripts", "Source", scripts); // See if any script was specified - if (scripts.size() <= 0) + if (scripts.size() <= 0 && !conf.GetBoolValue("Config", "EmptyInit", false)) { LogWrn("No scripts specified in the configuration file"); // No point in loading the plug-in return false; } - // Sort the list in it's original order - scripts.sort(CSimpleIniA::Entry::LoadOrder()); - // Process each specified script path - for (CSimpleIniA::TNamesDepend::iterator itr = scripts.begin(); itr != scripts.end(); ++itr) + else { - // Get the file path as a string - String path(itr->pItem); - // See if the specified script path is valid - if (path.empty()) - { - // Simply ignore it - continue; - } - // See if it wasn't already loaded - else if (m_Scripts.find(path) != m_Scripts.end()) - { - LogWrn("Script was specified before: %s", path.c_str()); - // No point in loading it again - continue; - } - // Create a new script container and insert it into the script pool - std::pair< Scripts::iterator, bool > res = m_Scripts.insert(Scripts::value_type(path, Script(m_VM))); - // We don't compile the scripts yet. We just store their path and prepare the objects. - if (!res.second) - { - LogErr("Unable to queue script: %s", path.c_str()); - // Drop all previous scripts - m_Scripts.clear(); - // Failed to compile the specified script - return false; - } + // Sort the list in it's original order + scripts.sort(CSimpleIniA::Entry::LoadOrder()); + // Process each specified script paths + for (const auto & script : scripts) + // Attempt to queue the specified script path for loading + LoadScript(script.pItem); } - // See if any script could be compiled + // See if any script could be queued for loading if (m_Scripts.empty() && !conf.GetBoolValue("Config", "EmptyInit", false)) { - LogErr("No scripts compiled. No reason to load the plug-in"); + LogErr("No scripts loaded. No reason to load the plug-in"); // No point in loading the plug-in return false; } - LogDbg("Reading the options from the general section"); - // Read options only after compilation was successful + // Read options only after loading was successful CSimpleIniA::TNamesDepend options; - // Are there any options to load? + // Are there any options to read? if (conf.GetAllKeys("Options", options) || options.size() > 0) { // Process all the specified keys under the [Options] section - for (CSimpleIniA::TNamesDepend::iterator itr = options.begin(); itr != options.end(); ++itr) + for (const auto & option : options) { - CSimpleIniA::TNamesDepend optlist; - // Get all keys with the same name - if (!conf.GetAllValues("Options", itr->pItem, optlist)) - { + CSimpleIniA::TNamesDepend values; + // Get the values of all keys with the same name + if (!conf.GetAllValues("Options", option.pItem, values)) continue; - } // Sort the keys in their original order - optlist.sort(CSimpleIniA::Entry::LoadOrder()); - // Process each option and overwrite existing values - for (CSimpleIniA::TNamesDepend::iterator opt = optlist.begin(); opt != optlist.end(); ++opt) - { - m_Options[itr->pItem] = opt->pItem; - } + values.sort(CSimpleIniA::Entry::LoadOrder()); + // Save each option option and overwrite existing value + for (const auto & value : values) + m_Options[option.pItem] = value.pItem; } } else - { LogInf("No options specified in the configuration file"); - } LogDbg("Applying the specified logging filters"); // Apply the specified logging filters only after initialization was completed - if (!SToB(conf.GetValue("Log", "Debug", "true"))) _Log->DisableLevel(LL_DBG); - if (!SToB(conf.GetValue("Log", "User", "true"))) _Log->DisableLevel(LL_USR); - if (!SToB(conf.GetValue("Log", "Success", "true"))) _Log->DisableLevel(LL_SCS); - if (!SToB(conf.GetValue("Log", "Info", "true"))) _Log->DisableLevel(LL_INF); - if (!SToB(conf.GetValue("Log", "Warning", "true"))) _Log->DisableLevel(LL_WRN); - if (!SToB(conf.GetValue("Log", "Error", "true"))) _Log->DisableLevel(LL_ERR); - if (!SToB(conf.GetValue("Log", "Fatal", "true"))) _Log->DisableLevel(LL_FTL); + if (!conf.GetBoolValue("Log", "Debug", true)) + _Log->DisableLevel(LL_DBG); + if (!conf.GetBoolValue("Log", "User", true)) + _Log->DisableLevel(LL_USR); + if (!conf.GetBoolValue("Log", "Success", true)) + _Log->DisableLevel(LL_SCS); + if (!conf.GetBoolValue("Log", "Info", true)) + _Log->DisableLevel(LL_INF); + if (!conf.GetBoolValue("Log", "Warning", true)) + _Log->DisableLevel(LL_WRN); + if (!conf.GetBoolValue("Log", "Error", true)) + _Log->DisableLevel(LL_ERR); + if (!conf.GetBoolValue("Log", "Fatal", true)) + _Log->DisableLevel(LL_FTL); // Initialization successful return true; @@ -306,7 +268,8 @@ bool Core::Load() { // Are there any scripts to execute? if (cLogErr(m_Scripts.empty(), "No scripts to execute. Plug-in has no purpose")) - return false; + return false; // No reason to load the plug-in + LogDbg("Signaling outside plugins to register their API"); // Signal outside plugins to do their monkey business _Func->SendCustomCommand(0xDEADBABE, ""); @@ -316,18 +279,29 @@ bool Core::Load() for (Scripts::iterator itr = m_Scripts.begin(); itr != m_Scripts.end(); ++itr) { // Attempt to load and compile the script file - itr->second.CompileFile(itr->first); - // See if any compile time error occurred during compilation - if (Error::Occurred(m_VM)) - return false; /* Failed to load properly */ - // Attempt to execute the script - itr->second.Run(); - // See if the executed script had any errors - if (Error::Occurred(m_VM)) - // Failed to execute scripts - return false; /* Failed to load properly */ - else - LogScs("Successfully executed script: %s", itr->first.c_str()); + try + { + itr->second.CompileFile(itr->first); + } + catch (const Sqrat::Exception & e) + { + LogFtl("Unable to compile: %s", itr->first.c_str()); + // Failed to load properly + return false; + } + // Attempt to execute the compiled script code + try + { + itr->second.Run(); + } + catch (const Sqrat::Exception & e) + { + LogFtl("Unable to execute: %s", itr->first.c_str()); + // Failed to load properly + return false; + } + // At this point the script should be completely loaded + LogScs("Successfully executed script: %s", itr->first.c_str()); } // Successfully loaded return true; @@ -382,6 +356,25 @@ void Core::SetOption(const String & name, const String & value) m_Options[name] = value; } +// ------------------------------------------------------------------------------------------------ +bool Core::LoadScript(CSStr filepath) +{ + // Is the specified path empty? + if (!filepath || *filepath == 0) + return false; // Simply ignore it + // Get the file path as a string + String path(filepath); + // See if it wasn't already loaded + if (m_Scripts.find(path) != m_Scripts.end()) + LogWrn("Script was specified before: %s", path.c_str()); + // We don't compile the scripts yet. We just store their path and prepare the objects. + else + // Create a new script container and insert it into the script pool + m_Scripts.emplace(std::move(path), Script(m_VM)); + // At this point the script exists in the pool + return true; +} + // ------------------------------------------------------------------------------------------------ void Core::PrintFunc(HSQUIRRELVM vm, CSStr msg, ...) { @@ -1720,8 +1713,8 @@ void Core::ResetInst(BlipInst & inst) inst.mWorld = -1; inst.mScale = -1; inst.mSprID = -1; - //inst.mPosition.Clear(); - //inst.mColor.Clear(); + inst.mPosition.Clear(); + inst.mColor.Clear(); } void Core::ResetInst(CheckpointInst & inst) @@ -1740,9 +1733,9 @@ void Core::ResetInst(KeybindInst & inst) { inst.mID = -1; inst.mFlags = ENF_DEFAULT; - inst.mPrimary = -1; - inst.mSecondary = -1; - inst.mAlternative = -1; + inst.mFirst = -1; + inst.mSecond = -1; + inst.mThird = -1; inst.mRelease = -1; } diff --git a/source/Core.hpp b/source/Core.hpp index fb0af1ee..52fd94d1 100644 --- a/source/Core.hpp +++ b/source/Core.hpp @@ -155,9 +155,9 @@ protected: Object mObj; // ---------------------------------------------------------------------------------------- - Int32 mPrimary; - Int32 mSecondary; - Int32 mAlternative; + Int32 mFirst; + Int32 mSecond; + Int32 mThird; Int32 mRelease; // ---------------------------------------------------------------------------------------- @@ -392,6 +392,8 @@ protected: Function mOnDisembark; }; +public: + // -------------------------------------------------------------------------------------------- typedef std::vector< BlipInst > Blips; typedef std::vector< CheckpointInst > Checkpoints; @@ -483,8 +485,15 @@ public: /* -------------------------------------------------------------------------------------------- * State mutators. */ - void SetState(Int32 val) { m_State = val; } - Int32 GetState() const { return m_State; } + void SetState(Int32 val) + { + m_State = val; + } + + Int32 GetState() const + { + return m_State; + } /* -------------------------------------------------------------------------------------------- * Option mutators. @@ -495,7 +504,15 @@ public: /* -------------------------------------------------------------------------------------------- * Retrieve the virtual machine. */ - HSQUIRRELVM GetVM() const { return m_VM; } + HSQUIRRELVM GetVM() const + { + return m_VM; + } + + /* -------------------------------------------------------------------------------------------- + * Adds a script to the load queue. + */ + bool LoadScript(CSStr filepath); protected: @@ -578,6 +595,20 @@ public: TextdrawInst & GetTextdraw(Int32 id) { return m_Textdraws.at(id); } VehicleInst & GetVehicle(Int32 id) { return m_Vehicles.at(id); } + /* -------------------------------------------------------------------------------------------- + * Pool retrievers. + */ + const Blips & GetBlips() const { return m_Blips; } + const Checkpoints & GetCheckpoints() const { return m_Checkpoints; } + const Forcefields & GetForcefields() const { return m_Forcefields; } + const Keybinds & GetKeybinds() const { return m_Keybinds; } + const Objects & GetObjects() const { return m_Objects; } + const Pickups & GetPickups() const { return m_Pickups; } + const Players & GetPlayers() const { return m_Players; } + const Sprites & GetSprites() const { return m_Sprites; } + const Textdraws & GetTextdraws() const { return m_Textdraws; } + const Vehicles & GetVehicles() const { return m_Vehicles; } + protected: /* -------------------------------------------------------------------------------------------- diff --git a/source/Entity/Blip.cpp b/source/Entity/Blip.cpp index 858265da..cc90ac98 100644 --- a/source/Entity/Blip.cpp +++ b/source/Entity/Blip.cpp @@ -6,15 +6,20 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ -SQChar CBlip::s_StrID[SQMOD_BLIP_POOL][8]; +const Int32 CBlip::Max = SQMOD_BLIP_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CBlip::Max = SQMOD_BLIP_POOL; +SQInteger CBlip::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqBlip"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CBlip::CBlip(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_BLIP_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -36,153 +41,183 @@ Int32 CBlip::Cmp(const CBlip & o) const return -1; } -CSStr CBlip::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CBlip::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_BLIP_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CBlip::GetTag() const +const String & CBlip::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CBlip::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CBlip::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CBlip::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CBlip::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelBlip(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CBlip::BindEvent(Int32 evid, Object & env, Function & func) const +void CBlip::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetBlipEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ Int32 CBlip::GetWorld() const { - if (Validate()) - return _Core->GetBlip(m_ID).mWorld; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mWorld; } +// ------------------------------------------------------------------------------------------------ Int32 CBlip::GetScale() const { - if (Validate()) - return _Core->GetBlip(m_ID).mScale; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mScale; } +// ------------------------------------------------------------------------------------------------ const Vector3 & CBlip::GetPosition() const { - if (Validate()) - return _Core->GetBlip(m_ID).mPosition; - return Vector3::NIL; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mPosition; } +// ------------------------------------------------------------------------------------------------ const Color4 & CBlip::GetColor() const { - if (Validate()) - return _Core->GetBlip(m_ID).mColor; - return Color4::NIL; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mColor; } +// ------------------------------------------------------------------------------------------------ Int32 CBlip::GetSprID() const { - if (Validate()) - return _Core->GetBlip(m_ID).mSprID; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mSprID; } // ------------------------------------------------------------------------------------------------ Float32 CBlip::GetPosX() const { - if (Validate()) - return _Core->GetBlip(m_ID).mPosition.x; - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mPosition.x; } +// ------------------------------------------------------------------------------------------------ Float32 CBlip::GetPosY() const { - if (Validate()) - return _Core->GetBlip(m_ID).mPosition.y; - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mPosition.y; } +// ------------------------------------------------------------------------------------------------ Float32 CBlip::GetPosZ() const { - if (Validate()) - return _Core->GetBlip(m_ID).mPosition.z; - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mPosition.z; } // ------------------------------------------------------------------------------------------------ Int32 CBlip::GetColorR() const { - if (Validate()) - return _Core->GetBlip(m_ID).mColor.r; - return 0; -} - -Int32 CBlip::GetColorG() const -{ - if (Validate()) - return _Core->GetBlip(m_ID).mColor.g; - return 0; -} - -Int32 CBlip::GetColorB() const -{ - if (Validate()) - return _Core->GetBlip(m_ID).mColor.b; - return 0; -} - -Int32 CBlip::GetColorA() const -{ - if (Validate()) - return _Core->GetBlip(m_ID).mColor.a; - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mColor.r; } // ------------------------------------------------------------------------------------------------ -static Object & CreateBlipEx(Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, +Int32 CBlip::GetColorG() const +{ + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mColor.g; +} + +// ------------------------------------------------------------------------------------------------ +Int32 CBlip::GetColorB() const +{ + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mColor.b; +} + +// ------------------------------------------------------------------------------------------------ +Int32 CBlip::GetColorA() const +{ + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetBlip(m_ID).mColor.a; +} + +// ------------------------------------------------------------------------------------------------ +static Object & Blip_CreateEx(Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Int32 sprid) { return _Core->NewBlip(-1, world, x, y, z, scale, SQMOD_PACK_RGBA(r, g, b, a), sprid, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateBlipEx(Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, +static Object & Blip_CreateEx(Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Int32 sprid, Int32 header, Object & payload) { @@ -191,14 +226,14 @@ static Object & CreateBlipEx(Int32 world, Float32 x, Float32 y, Float32 z, Int32 } // ------------------------------------------------------------------------------------------------ -static Object & CreateBlipEx(Int32 index, Int32 world, Float32 x, Float32 y, Float32 z, +static Object & Blip_CreateEx(Int32 index, Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Int32 sprid) { return _Core->NewBlip(index, world, x, y, z, scale, SQMOD_PACK_RGBA(r, g, b, a), sprid, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateBlipEx(Int32 index, Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, +static Object & Blip_CreateEx(Int32 index, Int32 world, Float32 x, Float32 y, Float32 z, Int32 scale, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Int32 sprid, Int32 header, Object & payload) { @@ -207,14 +242,14 @@ static Object & CreateBlipEx(Int32 index, Int32 world, Float32 x, Float32 y, Flo } // ------------------------------------------------------------------------------------------------ -static Object & CreateBlip(Int32 world, const Vector3 & pos, Int32 scale, const Color4 & color, +static Object & Blip_Create(Int32 world, const Vector3 & pos, Int32 scale, const Color4 & color, Int32 sprid) { return _Core->NewBlip(-1, world, pos.x, pos.y, pos.z, scale, color.GetRGBA(), sprid, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateBlip(Int32 world, const Vector3 & pos, Int32 scale, const Color4 & color, +static Object & Blip_Create(Int32 world, const Vector3 & pos, Int32 scale, const Color4 & color, Int32 sprid, Int32 header, Object & payload) { return _Core->NewBlip(-1, world, pos.x, pos.y, pos.z, scale, color.GetRGBA(), sprid, @@ -222,41 +257,82 @@ static Object & CreateBlip(Int32 world, const Vector3 & pos, Int32 scale, const } // ------------------------------------------------------------------------------------------------ -static Object & CreateBlip(Int32 index, Int32 world, const Vector3 & pos, Int32 scale, +static Object & Blip_Create(Int32 index, Int32 world, const Vector3 & pos, Int32 scale, const Color4 & color, Int32 sprid) { return _Core->NewBlip(index, world, pos.x, pos.y, pos.z, scale, color.GetRGBA(), sprid, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateBlip(Int32 index, Int32 world, const Vector3 & pos, Int32 scale, +static Object & Blip_Create(Int32 index, Int32 world, const Vector3 & pos, Int32 scale, const Color4 & color, Int32 sprid, Int32 header, Object & payload) { return _Core->NewBlip(index, world, pos.x, pos.y, pos.z, scale, color.GetRGBA(), sprid, header, payload); } +// ------------------------------------------------------------------------------------------------ +static const Object & Blip_FindByID(Int32 id) +{ + // Perform a range check on the specified identifier + if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL)) + SqThrowF("The specified blip identifier is invalid: %d", id); + // Obtain the ends of the entity pool + Core::Blips::const_iterator itr = _Core->GetBlips().cbegin(); + Core::Blips::const_iterator end = _Core->GetBlips().cend(); + // Process each entity in the pool + for (; itr != end; ++itr) + { + // Does the identifier match the specified one? + if (itr->mID == id) + return itr->mObj; // Stop searching and return this entity + } + // Unable to locate a blip matching the specified identifier + return NullObject(); +} + +static const Object & Blip_FindByTag(CSStr tag) +{ + // Perform a validity check on the specified tag + if (!tag || *tag == 0) + SqThrowF("The specified blip tag is invalid: null/empty"); + // Obtain the ends of the entity pool + Core::Blips::const_iterator itr = _Core->GetBlips().cbegin(); + Core::Blips::const_iterator end = _Core->GetBlips().cend(); + // Process each entity in the pool + for (; itr != end; ++itr) + { + // Does this entity even exist and does the tag match the specified one? + if (itr->mInst != nullptr && itr->mInst->GetTag().compare(tag) == 0) + return itr->mObj; // Stop searching and return this entity + } + // Unable to locate a blip matching the specified tag + return NullObject(); +} + // ================================================================================================ void Register_CBlip(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqBlip"), Class< CBlip, NoConstructor< CBlip > >(vm, _SC("SqBlip")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CBlip::Cmp) + .SquirrelFunc(_SC("_typename"), &CBlip::Typename) .Func(_SC("_tostring"), &CBlip::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CBlip::Max) + // Core Properties .Prop(_SC("ID"), &CBlip::GetID) .Prop(_SC("Tag"), &CBlip::GetTag, &CBlip::SetTag) .Prop(_SC("Data"), &CBlip::GetData, &CBlip::SetData) - .Prop(_SC("MaxID"), &CBlip::GetMaxID) .Prop(_SC("Active"), &CBlip::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CBlip::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CBlip::*)(void) >(_SC("Destroy"), &CBlip::Destroy) .Overload< bool (CBlip::*)(Int32) >(_SC("Destroy"), &CBlip::Destroy) .Overload< bool (CBlip::*)(Int32, Object &) >(_SC("Destroy"), &CBlip::Destroy) - /* Properties */ + // Properties .Prop(_SC("World"), &CBlip::GetWorld) .Prop(_SC("Scale"), &CBlip::GetScale) .Prop(_SC("Pos"), &CBlip::GetPosition) @@ -270,25 +346,24 @@ void Register_CBlip(HSQUIRRELVM vm) .Prop(_SC("G"), &CBlip::GetColorG) .Prop(_SC("B"), &CBlip::GetColorB) .Prop(_SC("A"), &CBlip::GetColorA) + // Static Overloads + .StaticOverload< Object & (*)(Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32) > + (_SC("CreateEx"), &Blip_CreateEx) + .StaticOverload< Object & (*)(Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32, Int32, Object &) > + (_SC("CreateEx"), &Blip_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32) > + (_SC("CreateEx"), &Blip_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32, Int32, Object &) > + (_SC("CreateEx"), &Blip_CreateEx) + .StaticOverload< Object & (*)(Int32, const Vector3 &, Int32, const Color4 &, Int32) > + (_SC("Create"), &Blip_Create) + .StaticOverload< Object & (*)(Int32, const Vector3 &, Int32, const Color4 &, Int32, Int32, Object &) > + (_SC("Create"), &Blip_Create) + .StaticOverload< Object & (*)(Int32, Int32, const Vector3 &, Int32, const Color4 &, Int32) > + (_SC("Create"), &Blip_Create) + .StaticOverload< Object & (*)(Int32, Int32, const Vector3 &, Int32, const Color4 &, Int32, Int32, Object &) > + (_SC("Create"), &Blip_Create) ); - - RootTable(vm) - .Overload< Object & (*)(Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32) > - (_SC("CreateBlipEx"), &CreateBlipEx) - .Overload< Object & (*)(Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32, Int32, Object &) > - (_SC("CreateBlipEx"), &CreateBlipEx) - .Overload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32) > - (_SC("CreateBlipEx"), &CreateBlipEx) - .Overload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32, Uint8, Uint8, Uint8, Uint8, Int32, Int32, Object &) > - (_SC("CreateBlipEx"), &CreateBlipEx) - .Overload< Object & (*)(Int32, const Vector3 &, Int32, const Color4 &, Int32) > - (_SC("CreateBlip"), &CreateBlip) - .Overload< Object & (*)(Int32, const Vector3 &, Int32, const Color4 &, Int32, Int32, Object &) > - (_SC("CreateBlip"), &CreateBlip) - .Overload< Object & (*)(Int32, Int32, const Vector3 &, Int32, const Color4 &, Int32) > - (_SC("CreateBlip"), &CreateBlip) - .Overload< Object & (*)(Int32, Int32, const Vector3 &, Int32, const Color4 &, Int32, Int32, Object &) > - (_SC("CreateBlip"), &CreateBlip); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Blip.hpp b/source/Entity/Blip.hpp index bc43dcf1..fbd4943b 100644 --- a/source/Entity/Blip.hpp +++ b/source/Entity/Blip.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Blip instances. + * Manages a single blip entity. */ class CBlip { @@ -17,20 +17,19 @@ class CBlip private: - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_BLIP_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -38,20 +37,22 @@ private: */ CBlip(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CBlip(const CBlip &); + CBlip(const CBlip &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CBlip & operator = (const CBlip &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CBlip(CBlip &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. @@ -59,14 +60,22 @@ public: ~CBlip(); /* -------------------------------------------------------------------------------------------- - * See whether this instance manages a valid entity. + * Copy assignment operator. (disabled) */ - bool Validate() const + CBlip & operator = (const CBlip &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CBlip & operator = (CBlip &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * See whether this instance manages a valid entity otherwise throw an exception. + */ + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid blip reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid blip reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -77,27 +86,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_BLIP_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -115,29 +130,89 @@ public: void SetData(Object & data); /* -------------------------------------------------------------------------------------------- - * Destroy the managed entity instance. + * Destroy the managed blip entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed blip entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed blip entity. */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the referenced blip entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the scale of the managed blip entity. + */ Int32 GetScale() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed blip entity. + */ const Vector3 & GetPosition() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the color of the managed blip entity. + */ const Color4 & GetColor() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the identifier of the sprite used by the managed blip entity. + */ Int32 GetSprID() const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed blip entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed blip entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed blip entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the red color of the managed blip entity. + */ Int32 GetColorR() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the green color of the managed blip entity. + */ Int32 GetColorG() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the blue color of the managed blip entity. + */ Int32 GetColorB() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the alpha transparency of the managed blip entity. + */ Int32 GetColorA() const; }; diff --git a/source/Entity/Checkpoint.cpp b/source/Entity/Checkpoint.cpp index 6bcad893..18387744 100644 --- a/source/Entity/Checkpoint.cpp +++ b/source/Entity/Checkpoint.cpp @@ -19,15 +19,20 @@ Uint32 CCheckpoint::s_ColorB; Uint32 CCheckpoint::s_ColorA; // ------------------------------------------------------------------------------------------------ -SQChar CCheckpoint::s_StrID[SQMOD_CHECKPOINT_POOL][8]; +const Int32 CCheckpoint::Max = SQMOD_CHECKPOINT_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CCheckpoint::Max = SQMOD_CHECKPOINT_POOL; +SQInteger CCheckpoint::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqCheckpoint"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CCheckpoint::CCheckpoint(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_CHECKPOINT_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -49,282 +54,373 @@ Int32 CCheckpoint::Cmp(const CCheckpoint & o) const return -1; } -CSStr CCheckpoint::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CCheckpoint::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_CHECKPOINT_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CCheckpoint::GetTag() const +const String & CCheckpoint::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CCheckpoint::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CCheckpoint::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelCheckpoint(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CCheckpoint::BindEvent(Int32 evid, Object & env, Function & func) const +void CCheckpoint::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetCheckpointEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ bool CCheckpoint::IsStreamedFor(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - return _Func->IsCheckpointStreamedForPlayer(m_ID, player.GetID()); - return false; + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsCheckpointStreamedForPlayer(m_ID, player.GetID()); } +// ------------------------------------------------------------------------------------------------ Int32 CCheckpoint::GetWorld() const { - if (Validate()) - return _Func->GetCheckpointWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetCheckpointWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetWorld(Int32 world) const { - if (Validate()) - _Func->SetCheckpointWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCheckpointWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ const Color4 & CCheckpoint::GetColor() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_Color4.Clear(); - if (Validate()) - { - _Func->GetCheckpointColor(m_ID, &s_ColorR, &s_ColorG, &s_ColorB, &s_ColorA); - s_Color4.Set(s_ColorR, s_ColorG, s_ColorB, s_ColorA); - } + // Query the server for the color values + _Func->GetCheckpointColor(m_ID, &s_ColorR, &s_ColorG, &s_ColorB, &s_ColorA); + // Convert and assign the retrieved values + s_Color4.Set(s_ColorR, s_ColorG, s_ColorB, s_ColorA); + // Return the requested information return s_Color4; } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetColor(const Color4 & col) const { - if (Validate()) - _Func->SetCheckpointColor(m_ID, col.r, col.g, col.b, col.a); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCheckpointColor(m_ID, col.r, col.g, col.b, col.a); } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetColorEx(Uint8 r, Uint8 g, Uint8 b, Uint8 a) const { - if (Validate()) - _Func->SetCheckpointColor(m_ID, r, g, b, a); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCheckpointColor(m_ID, r, g, b, a); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CCheckpoint::GetPosition() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetCheckpointPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->GetCheckpointPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetPosition(const Vector3 & pos) const { - if (Validate()) - _Func->SetCheckpointPos(m_ID, pos.x, pos.y, pos.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCheckpointPos(m_ID, pos.x, pos.y, pos.z); } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetPositionEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetCheckpointPos(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCheckpointPos(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ Float32 CCheckpoint::GetRadius() const { - if (Validate()) - _Func->GetCheckpointRadius(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetCheckpointRadius(m_ID); } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetRadius(Float32 radius) const { - if (Validate()) - _Func->SetCheckpointRadius(m_ID, radius); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCheckpointRadius(m_ID, radius); } +// ------------------------------------------------------------------------------------------------ Object & CCheckpoint::GetOwner() const { - if (Validate()) - return _Core->GetPlayer(_Func->GetCheckpointOwner(m_ID)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(_Func->GetCheckpointOwner(m_ID)).mObj; } +// ------------------------------------------------------------------------------------------------ Int32 CCheckpoint::GetOwnerID() const { - if (Validate()) - return _Func->GetCheckpointOwner(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetCheckpointOwner(m_ID); } // ------------------------------------------------------------------------------------------------ Float32 CCheckpoint::GetPosX() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetCheckpointPos(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetCheckpointPos(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CCheckpoint::GetPosY() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetCheckpointPos(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetCheckpointPos(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CCheckpoint::GetPosZ() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetCheckpointPos(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetCheckpointPos(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ void CCheckpoint::SetPosX(Float32 x) const { - if (Validate()) - { - _Func->GetCheckpointPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->SetCheckpointPos(m_ID, x, s_Vector3.y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->SetCheckpointPos(m_ID, x, s_Vector3.y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetPosY(Float32 y) const { - if (Validate()) - { - _Func->GetCheckpointPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->SetCheckpointPos(m_ID, s_Vector3.x, y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->SetCheckpointPos(m_ID, s_Vector3.x, y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CCheckpoint::SetPosZ(Float32 z) const { - if (Validate()) - { - _Func->GetCheckpointPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->SetCheckpointPos(m_ID, s_Vector3.z, s_Vector3.y, z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->SetCheckpointPos(m_ID, s_Vector3.z, s_Vector3.y, z); } // ------------------------------------------------------------------------------------------------ Uint32 CCheckpoint::GetColR() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_ColorR = 0; - if (Validate()) - _Func->GetCheckpointColor(m_ID, &s_ColorR, NULL, NULL, NULL); + // Query the server for the requested component value + _Func->GetCheckpointColor(m_ID, &s_ColorR, NULL, NULL, NULL); + // Return the requested information return s_ColorR; } +// ------------------------------------------------------------------------------------------------ Uint32 CCheckpoint::GetColG() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_ColorG = 0; - if (Validate()) - _Func->GetCheckpointColor(m_ID, NULL, &s_ColorG, NULL, NULL); + // Query the server for the requested component value + _Func->GetCheckpointColor(m_ID, NULL, &s_ColorG, NULL, NULL); + // Return the requested information return s_ColorG; } +// ------------------------------------------------------------------------------------------------ Uint32 CCheckpoint::GetColB() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_ColorB = 0; - if (Validate()) - _Func->GetCheckpointColor(m_ID, NULL, NULL, &s_ColorB, NULL); + // Query the server for the requested component value + _Func->GetCheckpointColor(m_ID, NULL, NULL, &s_ColorB, NULL); + // Return the requested information return s_ColorB; } +// ------------------------------------------------------------------------------------------------ Uint32 CCheckpoint::GetColA() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_ColorA = 0; - if (Validate()) - _Func->GetCheckpointColor(m_ID, NULL, NULL, NULL, &s_ColorA); + // Query the server for the requested component value + _Func->GetCheckpointColor(m_ID, NULL, NULL, NULL, &s_ColorA); + // Return the requested information return s_ColorA; } // ------------------------------------------------------------------------------------------------ void CCheckpoint::SetColR(Uint32 r) const { - if (Validate()) - { - _Func->GetCheckpointColor(m_ID, NULL, &s_ColorG, &s_ColorB, &s_ColorA); - _Func->SetCheckpointColor(m_ID, r, s_ColorG, s_ColorB, s_ColorA); - } -} - -void CCheckpoint::SetColG(Uint32 g) const -{ - if (Validate()) - { - _Func->GetCheckpointColor(m_ID, &s_ColorR, NULL, &s_ColorB, &s_ColorA); - _Func->SetCheckpointColor(m_ID, s_ColorR, g, s_ColorB, s_ColorA); - } -} - -void CCheckpoint::SetColB(Uint32 b) const -{ - if (Validate()) - { - _Func->GetCheckpointColor(m_ID, &s_ColorB, &s_ColorG, NULL, &s_ColorA); - _Func->SetCheckpointColor(m_ID, s_ColorB, s_ColorG, b, s_ColorA); - } -} - -void CCheckpoint::SetColA(Uint32 a) const -{ - if (Validate()) - { - _Func->GetCheckpointColor(m_ID, &s_ColorA, &s_ColorG, &s_ColorB, NULL); - _Func->SetCheckpointColor(m_ID, s_ColorA, s_ColorG, s_ColorB, a); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointColor(m_ID, NULL, &s_ColorG, &s_ColorB, &s_ColorA); + // Perform the requested operation + _Func->SetCheckpointColor(m_ID, r, s_ColorG, s_ColorB, s_ColorA); } // ------------------------------------------------------------------------------------------------ -static Object & CreateCheckpointEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, +void CCheckpoint::SetColG(Uint32 g) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointColor(m_ID, &s_ColorR, NULL, &s_ColorB, &s_ColorA); + // Perform the requested operation + _Func->SetCheckpointColor(m_ID, s_ColorR, g, s_ColorB, s_ColorA); +} + +// ------------------------------------------------------------------------------------------------ +void CCheckpoint::SetColB(Uint32 b) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointColor(m_ID, &s_ColorB, &s_ColorG, NULL, &s_ColorA); + // Perform the requested operation + _Func->SetCheckpointColor(m_ID, s_ColorB, s_ColorG, b, s_ColorA); +} + +// ------------------------------------------------------------------------------------------------ +void CCheckpoint::SetColA(Uint32 a) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetCheckpointColor(m_ID, &s_ColorA, &s_ColorG, &s_ColorB, NULL); + // Perform the requested operation + _Func->SetCheckpointColor(m_ID, s_ColorA, s_ColorG, s_ColorB, a); +} + +// ------------------------------------------------------------------------------------------------ +static Object & Checkpoint_CreateEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Float32 radius) { return _Core->NewCheckpoint(player.GetID(), world, x, y, z, r, g, b, a, radius, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateCheckpointEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, +static Object & Checkpoint_CreateEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, Uint8 r, Uint8 g, Uint8 b, Uint8 a, Float32 radius, Int32 header, Object & payload) { @@ -332,7 +428,7 @@ static Object & CreateCheckpointEx(CPlayer & player, Int32 world, Float32 x, Flo } // ------------------------------------------------------------------------------------------------ -static Object & CreateCheckpoint(CPlayer & player, Int32 world, const Vector3 & pos, +static Object & Checkpoint_Create(CPlayer & player, Int32 world, const Vector3 & pos, const Color4 & color, Float32 radius) { return _Core->NewCheckpoint(player.GetID(), world, pos.x, pos.y, pos.z, @@ -340,7 +436,7 @@ static Object & CreateCheckpoint(CPlayer & player, Int32 world, const Vector3 & SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateCheckpoint(CPlayer & player, Int32 world, const Vector3 & pos, +static Object & Checkpoint_Create(CPlayer & player, Int32 world, const Vector3 & pos, const Color4 & color, Float32 radius, Int32 header, Object & payload) { return _Core->NewCheckpoint(player.GetID(), world, pos.x, pos.y, pos.z, @@ -352,22 +448,24 @@ void Register_CCheckpoint(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqCheckpoint"), Class< CCheckpoint, NoConstructor< CCheckpoint > >(vm, _SC("SqCheckpoint")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CCheckpoint::Cmp) + .SquirrelFunc(_SC("_typename"), &CCheckpoint::Typename) .Func(_SC("_tostring"), &CCheckpoint::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CCheckpoint::Max) + // Core Properties .Prop(_SC("ID"), &CCheckpoint::GetID) .Prop(_SC("Tag"), &CCheckpoint::GetTag, &CCheckpoint::SetTag) .Prop(_SC("Data"), &CCheckpoint::GetData, &CCheckpoint::SetData) - .Prop(_SC("MaxID"), &CCheckpoint::GetMaxID) .Prop(_SC("Active"), &CCheckpoint::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CCheckpoint::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CCheckpoint::*)(void) >(_SC("Destroy"), &CCheckpoint::Destroy) .Overload< bool (CCheckpoint::*)(Int32) >(_SC("Destroy"), &CCheckpoint::Destroy) .Overload< bool (CCheckpoint::*)(Int32, Object &) >(_SC("Destroy"), &CCheckpoint::Destroy) - /* Properties */ + // Properties .Prop(_SC("World"), &CCheckpoint::GetWorld, &CCheckpoint::SetWorld) .Prop(_SC("Color"), &CCheckpoint::GetColor, &CCheckpoint::SetColor) .Prop(_SC("Pos"), &CCheckpoint::GetPosition, &CCheckpoint::SetPosition) @@ -382,22 +480,21 @@ void Register_CCheckpoint(HSQUIRRELVM vm) .Prop(_SC("G"), &CCheckpoint::GetColG, &CCheckpoint::SetColG) .Prop(_SC("B"), &CCheckpoint::GetColB, &CCheckpoint::SetColB) .Prop(_SC("A"), &CCheckpoint::GetColA, &CCheckpoint::SetColA) - /* Functions */ + // Functions .Func(_SC("StreamedFor"), &CCheckpoint::IsStreamedFor) .Func(_SC("SetColor"), &CCheckpoint::SetColorEx) .Func(_SC("SetPos"), &CCheckpoint::SetPositionEx) .Func(_SC("SetPosition"), &CCheckpoint::SetPositionEx) + // Static Overloads + .StaticOverload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Uint8, Float32) > + (_SC("CreateEx"), &Checkpoint_CreateEx) + .StaticOverload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Uint8, Float32, Int32, Object &) > + (_SC("CreateEx"), &Checkpoint_CreateEx) + .StaticOverload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color4 &, Float32) > + (_SC("Create"), &Checkpoint_Create) + .StaticOverload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color4 &, Float32, Int32, Object &) > + (_SC("Create"), &Checkpoint_Create) ); - - RootTable(vm) - .Overload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Uint8, Float32) > - (_SC("CreateCheckpointEx"), &CreateCheckpointEx) - .Overload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Uint8, Float32, Int32, Object &) > - (_SC("CreateCheckpointEx"), &CreateCheckpointEx) - .Overload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color4 &, Float32) > - (_SC("CreateCheckpoint"), &CreateCheckpoint) - .Overload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color4 &, Float32, Int32, Object &) > - (_SC("CreateCheckpoint"), &CreateCheckpoint); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Checkpoint.hpp b/source/Entity/Checkpoint.hpp index 51f655dd..09b16efd 100644 --- a/source/Entity/Checkpoint.hpp +++ b/source/Entity/Checkpoint.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Checkpoint instances. + * Manages a single checkpoint entity. */ class CCheckpoint { @@ -24,20 +24,19 @@ private: // -------------------------------------------------------------------------------------------- static Uint32 s_ColorR, s_ColorG, s_ColorB, s_ColorA; - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_CHECKPOINT_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -45,20 +44,22 @@ private: */ CCheckpoint(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CCheckpoint(const CCheckpoint &); + CCheckpoint(const CCheckpoint &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CCheckpoint & operator = (const CCheckpoint &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CCheckpoint(CCheckpoint &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. @@ -66,14 +67,22 @@ public: ~CCheckpoint(); /* -------------------------------------------------------------------------------------------- - * See whether this instance manages a valid entity. + * Copy assignment operator. (disabled) */ - bool Validate() const + CCheckpoint & operator = (const CCheckpoint &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CCheckpoint & operator = (CCheckpoint &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * See whether this instance manages a valid entity otherwise throw an exception. + */ + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid checkpoint reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid checkpoint reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -84,27 +93,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_CHECKPOINT_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -120,45 +135,166 @@ public: * Modify the associated user data. */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed checkpoint entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed checkpoint entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed checkpoint entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * See if the managed checkpoint entity is streamed for the specified player. + */ bool IsStreamedFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the managed checkpoint entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the world in which the managed checkpoint entity exists. + */ void SetWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the color of the managed checkpoint entity. + */ const Color4 & GetColor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the color of the managed checkpoint entity. + */ void SetColor(const Color4 & col) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the color of the managed checkpoint entity. + */ void SetColorEx(Uint8 r, Uint8 g, Uint8 b, Uint8 a) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed checkpoint entity. + */ const Vector3 & GetPosition() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed checkpoint entity. + */ void SetPosition(const Vector3 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed checkpoint entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the radius of the managed checkpoint entity. + */ Float32 GetRadius() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the radius of the managed checkpoint entity. + */ void SetRadius(Float32 radius) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the owner of the managed checkpoint entity. + */ Object & GetOwner() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the owner identifier of the managed checkpoint entity. + */ Int32 GetOwnerID() const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed checkpoint entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed checkpoint entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed checkpoint entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the x axis of the managed checkpoint entity. + */ void SetPosX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the y axis of the managed checkpoint entity. + */ void SetPosY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the z axis of the managed checkpoint entity. + */ void SetPosZ(Float32 z) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the red color of the managed checkpoint entity. + */ Uint32 GetColR() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the green color of the managed checkpoint entity. + */ Uint32 GetColG() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the blue color of the managed checkpoint entity. + */ Uint32 GetColB() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the alpha transparency of the managed checkpoint entity. + */ Uint32 GetColA() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the red color of the managed checkpoint entity. + */ void SetColR(Uint32 r) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the green color of the managed checkpoint entity. + */ void SetColG(Uint32 g) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the blue color of the managed checkpoint entity. + */ void SetColB(Uint32 b) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the alpha transparency of the managed checkpoint entity. + */ void SetColA(Uint32 a) const; }; diff --git a/source/Entity/Forcefield.cpp b/source/Entity/Forcefield.cpp index cd48f23c..864d3c44 100644 --- a/source/Entity/Forcefield.cpp +++ b/source/Entity/Forcefield.cpp @@ -18,15 +18,20 @@ Uint32 CForcefield::s_ColorG; Uint32 CForcefield::s_ColorB; // ------------------------------------------------------------------------------------------------ -SQChar CForcefield::s_StrID[SQMOD_FORCEFIELD_POOL][8]; +const Int32 CForcefield::Max = SQMOD_FORCEFIELD_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CForcefield::Max = SQMOD_FORCEFIELD_POOL; +SQInteger CForcefield::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqForcefield"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CForcefield::CForcefield(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_FORCEFIELD_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -48,265 +53,349 @@ Int32 CForcefield::Cmp(const CForcefield & o) const return -1; } -CSStr CForcefield::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CForcefield::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_FORCEFIELD_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CForcefield::GetTag() const +const String & CForcefield::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CForcefield::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CForcefield::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelForcefield(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CForcefield::BindEvent(Int32 evid, Object & env, Function & func) const +void CForcefield::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetForcefieldEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ bool CForcefield::IsStreamedFor(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - return _Func->IsSphereStreamedForPlayer(m_ID, player.GetID()); - return false; + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsSphereStreamedForPlayer(m_ID, player.GetID()); } +// ------------------------------------------------------------------------------------------------ Int32 CForcefield::GetWorld() const { - if (Validate()) - return _Func->GetSphereWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetSphereWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetWorld(Int32 world) const { - if (Validate()) - _Func->SetSphereWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSphereWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ const Color3 & CForcefield::GetColor() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_Color3.Clear(); - if (Validate()) - { - _Func->GetSphereColor(m_ID, &s_ColorR, &s_ColorG, &s_ColorB); - s_Color3.Set(s_ColorR, s_ColorG, s_ColorB); - } + // Query the server for the color values + _Func->GetSphereColor(m_ID, &s_ColorR, &s_ColorG, &s_ColorB); + // Convert and assign the retrieved values + s_Color3.Set(s_ColorR, s_ColorG, s_ColorB); + // Return the requested information return s_Color3; } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetColor(const Color3 & col) const { - if (Validate()) - _Func->SetSphereColor(m_ID, col.r, col.g, col.b); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSphereColor(m_ID, col.r, col.g, col.b); } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetColorEx(Uint8 r, Uint8 g, Uint8 b) const { - if (Validate()) - _Func->SetSphereColor(m_ID, r, g, b); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSphereColor(m_ID, r, g, b); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CForcefield::GetPosition() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetSpherePos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->GetSpherePos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetPosition(const Vector3 & pos) const { - if (Validate()) - _Func->SetSpherePos(m_ID, pos.x, pos.y, pos.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpherePos(m_ID, pos.x, pos.y, pos.z); } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetPositionEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetSpherePos(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpherePos(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ Float32 CForcefield::GetRadius() const { - if (Validate()) - _Func->GetSphereRadius(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetSphereRadius(m_ID); } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetRadius(Float32 radius) const { - if (Validate()) - _Func->SetSphereRadius(m_ID, radius); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSphereRadius(m_ID, radius); } +// ------------------------------------------------------------------------------------------------ Object & CForcefield::GetOwner() const { - if (Validate()) - return _Core->GetPlayer(_Func->GetSphereOwner(m_ID)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(_Func->GetSphereOwner(m_ID)).mObj; } +// ------------------------------------------------------------------------------------------------ Int32 CForcefield::GetOwnerID() const { - if (Validate()) - _Func->GetSphereOwner(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetSphereOwner(m_ID); } // ------------------------------------------------------------------------------------------------ Float32 CForcefield::GetPosX() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetSpherePos(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetSpherePos(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CForcefield::GetPosY() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetSpherePos(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetSpherePos(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CForcefield::GetPosZ() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetSpherePos(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetSpherePos(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ void CForcefield::SetPosX(Float32 x) const { - if (Validate()) - { - _Func->GetSpherePos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->SetSpherePos(m_ID, x, s_Vector3.y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetSpherePos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->SetSpherePos(m_ID, x, s_Vector3.y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetPosY(Float32 y) const { - if (Validate()) - { - _Func->GetSpherePos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->SetSpherePos(m_ID, s_Vector3.x, y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetSpherePos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->SetSpherePos(m_ID, s_Vector3.x, y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CForcefield::SetPosZ(Float32 z) const { - if (Validate()) - { - _Func->GetSpherePos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->SetSpherePos(m_ID, s_Vector3.z, s_Vector3.y, z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetSpherePos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->SetSpherePos(m_ID, s_Vector3.z, s_Vector3.y, z); } // ------------------------------------------------------------------------------------------------ Uint32 CForcefield::GetColR() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_ColorR = 0; - if (Validate()) - _Func->GetSphereColor(m_ID, &s_ColorR, NULL, NULL); + // Query the server for the requested component value + _Func->GetSphereColor(m_ID, &s_ColorR, NULL, NULL); + // Return the requested information return s_ColorR; } +// ------------------------------------------------------------------------------------------------ Uint32 CForcefield::GetColG() const { + // Validate the managed identifier + Validate(); + // Query the server for the requested component value s_ColorG = 0; - if (Validate()) - _Func->GetSphereColor(m_ID, NULL, &s_ColorG, NULL); + // Query the server for the requested component value + _Func->GetSphereColor(m_ID, NULL, &s_ColorG, NULL); + // Return the requested information return s_ColorG; } +// ------------------------------------------------------------------------------------------------ Uint32 CForcefield::GetColB() const { + // Validate the managed identifier + Validate(); + // Query the server for the requested component value s_ColorB = 0; - if (Validate()) - _Func->GetSphereColor(m_ID, NULL, NULL, &s_ColorB); + // Query the server for the requested component value + _Func->GetSphereColor(m_ID, NULL, NULL, &s_ColorB); + // Return the requested information return s_ColorB; } // ------------------------------------------------------------------------------------------------ void CForcefield::SetColR(Uint32 r) const { - if (Validate()) - { - _Func->GetSphereColor(m_ID, NULL, &s_ColorG, &s_ColorB); - _Func->SetSphereColor(m_ID, r, s_ColorG, s_ColorB); - } -} - -void CForcefield::SetColG(Uint32 g) const -{ - if (Validate()) - { - _Func->GetSphereColor(m_ID, &s_ColorR, NULL, &s_ColorB); - _Func->SetSphereColor(m_ID, s_ColorR, g, s_ColorB); - } -} - -void CForcefield::SetColB(Uint32 b) const -{ - if (Validate()) - { - _Func->GetSphereColor(m_ID, &s_ColorB, &s_ColorG, NULL); - _Func->SetSphereColor(m_ID, s_ColorB, s_ColorG, b); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetSphereColor(m_ID, NULL, &s_ColorG, &s_ColorB); + // Perform the requested operation + _Func->SetSphereColor(m_ID, r, s_ColorG, s_ColorB); } // ------------------------------------------------------------------------------------------------ -static Object & CreateForcefieldEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, +void CForcefield::SetColG(Uint32 g) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetSphereColor(m_ID, &s_ColorR, NULL, &s_ColorB); + // Perform the requested operation + _Func->SetSphereColor(m_ID, s_ColorR, g, s_ColorB); +} + +// ------------------------------------------------------------------------------------------------ +void CForcefield::SetColB(Uint32 b) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetSphereColor(m_ID, &s_ColorB, &s_ColorG, NULL); + // Perform the requested operation + _Func->SetSphereColor(m_ID, s_ColorB, s_ColorG, b); +} + +// ------------------------------------------------------------------------------------------------ +static Object & Forcefield_CreateEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, Uint8 r, Uint8 g, Uint8 b, Float32 radius) { return _Core->NewForcefield(player.GetID(), world, x, y, z, r, g, b, radius, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateForcefieldEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, +static Object & Forcefield_CreateEx(CPlayer & player, Int32 world, Float32 x, Float32 y, Float32 z, Uint8 r, Uint8 g, Uint8 b, Float32 radius, Int32 header, Object & payload) { @@ -314,14 +403,14 @@ static Object & CreateForcefieldEx(CPlayer & player, Int32 world, Float32 x, Flo } // ------------------------------------------------------------------------------------------------ -static Object & CreateForcefield(CPlayer & player, Int32 world, const Vector3 & pos, +static Object & Forcefield_Create(CPlayer & player, Int32 world, const Vector3 & pos, const Color3 & color, Float32 radius) { return _Core->NewForcefield(player.GetID(), world, pos.x, pos.y, pos.z, color.r, color.g, color.b, radius, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateForcefield(CPlayer & player, Int32 world, const Vector3 & pos, +static Object & Forcefield_Create(CPlayer & player, Int32 world, const Vector3 & pos, const Color3 & color, Float32 radius, Int32 header, Object & payload) { return _Core->NewForcefield(player.GetID(), world, pos.x, pos.y, pos.z, color.r, color.g, color.b, radius, @@ -333,22 +422,24 @@ void Register_CForcefield(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqForcefield"), Class< CForcefield, NoConstructor< CForcefield > >(vm, _SC("SqForcefield")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CForcefield::Cmp) + .SquirrelFunc(_SC("_typename"), &CForcefield::Typename) .Func(_SC("_tostring"), &CForcefield::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CForcefield::Max) + // Core Properties .Prop(_SC("ID"), &CForcefield::GetID) .Prop(_SC("Tag"), &CForcefield::GetTag, &CForcefield::SetTag) .Prop(_SC("Data"), &CForcefield::GetData, &CForcefield::SetData) - .Prop(_SC("MaxID"), &CForcefield::GetMaxID) .Prop(_SC("Active"), &CForcefield::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CForcefield::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CForcefield::*)(void) >(_SC("Destroy"), &CForcefield::Destroy) .Overload< bool (CForcefield::*)(Int32) >(_SC("Destroy"), &CForcefield::Destroy) .Overload< bool (CForcefield::*)(Int32, Object &) >(_SC("Destroy"), &CForcefield::Destroy) - /* Properties */ + // Properties .Prop(_SC("World"), &CForcefield::GetWorld, &CForcefield::SetWorld) .Prop(_SC("Color"), &CForcefield::GetColor, &CForcefield::SetColor) .Prop(_SC("Pos"), &CForcefield::GetPosition, &CForcefield::SetPosition) @@ -362,22 +453,21 @@ void Register_CForcefield(HSQUIRRELVM vm) .Prop(_SC("R"), &CForcefield::GetColR, &CForcefield::SetColR) .Prop(_SC("G"), &CForcefield::GetColG, &CForcefield::SetColG) .Prop(_SC("B"), &CForcefield::GetColB, &CForcefield::SetColB) - /* Functions */ + // Functions .Func(_SC("StreamedFor"), &CForcefield::IsStreamedFor) .Func(_SC("SetColor"), &CForcefield::SetColorEx) .Func(_SC("SetPos"), &CForcefield::SetPositionEx) .Func(_SC("SetPosition"), &CForcefield::SetPositionEx) + // Static Overloads + .StaticOverload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Float32) > + (_SC("CreateEx"), &Forcefield_CreateEx) + .StaticOverload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Float32, Int32, Object &) > + (_SC("CreateEx"), &Forcefield_CreateEx) + .StaticOverload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color3 &, Float32) > + (_SC("Create"), &Forcefield_Create) + .StaticOverload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color3 &, Float32, Int32, Object &) > + (_SC("Create"), &Forcefield_Create) ); - - RootTable(vm) - .Overload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Float32) > - (_SC("CreateForcefieldEx"), &CreateForcefieldEx) - .Overload< Object & (*)(CPlayer &, Int32, Float32, Float32, Float32, Uint8, Uint8, Uint8, Float32, Int32, Object &) > - (_SC("CreateForcefieldEx"), &CreateForcefieldEx) - .Overload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color3 &, Float32) > - (_SC("CreateForcefield"), &CreateForcefield) - .Overload< Object & (*)(CPlayer &, Int32, const Vector3 &, const Color3 &, Float32, Int32, Object &) > - (_SC("CreateForcefield"), &CreateForcefield); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Forcefield.hpp b/source/Entity/Forcefield.hpp index 2682c8e2..b5d17ddc 100644 --- a/source/Entity/Forcefield.hpp +++ b/source/Entity/Forcefield.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Forcefield instances. + * Manages a single forcefield entity. */ class CForcefield { @@ -24,20 +24,19 @@ private: // -------------------------------------------------------------------------------------------- static Uint32 s_ColorR, s_ColorG, s_ColorB; - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_FORCEFIELD_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -45,20 +44,22 @@ private: */ CForcefield(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CForcefield(const CForcefield &); + CForcefield(const CForcefield &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CForcefield & operator = (const CForcefield &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CForcefield(CForcefield &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. @@ -66,14 +67,22 @@ public: ~CForcefield(); /* -------------------------------------------------------------------------------------------- - * See whether this instance manages a valid entity. + * Copy assignment operator. (disabled) */ - bool Validate() const + CForcefield & operator = (const CForcefield &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CForcefield & operator = (CForcefield &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * See whether this instance manages a valid entity otherwise throw an exception. + */ + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid forcefield reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid forcefield reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -84,27 +93,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_FORCEFIELD_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -121,43 +136,155 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed forcefield entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed forcefield entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed forcefield entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * See if the managed forcefield entity is streamed for the specified player. + */ bool IsStreamedFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the managed forcefield entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the world in which the managed forcefield entity exists. + */ void SetWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the color of the managed forcefield entity. + */ const Color3 & GetColor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the color of the managed forcefield entity. + */ void SetColor(const Color3 & col) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the color of the managed forcefield entity. + */ void SetColorEx(Uint8 r, Uint8 g, Uint8 b) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed forcefield entity. + */ const Vector3 & GetPosition() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed forcefield entity. + */ void SetPosition(const Vector3 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed forcefield entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the radius of the managed forcefield entity. + */ Float32 GetRadius() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the radius of the managed forcefield entity. + */ void SetRadius(Float32 radius) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the owner of the managed forcefield entity. + */ Object & GetOwner() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the owner identifier of the managed forcefield entity. + */ Int32 GetOwnerID() const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed forcefield entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed forcefield entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed forcefield entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the x axis of the managed forcefield entity. + */ void SetPosX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the y axis of the managed forcefield entity. + */ void SetPosY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the z axis of the managed forcefield entity. + */ void SetPosZ(Float32 z) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the red color of the managed forcefield entity. + */ Uint32 GetColR() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the green color of the managed forcefield entity. + */ Uint32 GetColG() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the blue color of the managed forcefield entity. + */ Uint32 GetColB() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the red color of the managed forcefield entity. + */ void SetColR(Uint32 r) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the green color of the managed forcefield entity. + */ void SetColG(Uint32 g) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the blue color of the managed forcefield entity. + */ void SetColB(Uint32 b) const; }; diff --git a/source/Entity/Keybind.cpp b/source/Entity/Keybind.cpp index c7f77f9e..c3686bd8 100644 --- a/source/Entity/Keybind.cpp +++ b/source/Entity/Keybind.cpp @@ -6,15 +6,20 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ -SQChar CKeybind::s_StrID[SQMOD_KEYBIND_POOL][8]; +const Int32 CKeybind::Max = SQMOD_KEYBIND_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CKeybind::Max = SQMOD_KEYBIND_POOL; +SQInteger CKeybind::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqKeybind"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CKeybind::CKeybind(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_KEYBIND_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -36,108 +41,124 @@ Int32 CKeybind::Cmp(const CKeybind & o) const return -1; } -CSStr CKeybind::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CKeybind::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_KEYBIND_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CKeybind::GetTag() const +const String & CKeybind::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CKeybind::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CKeybind::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CKeybind::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CKeybind::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelKeybind(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CKeybind::BindEvent(Int32 evid, Object & env, Function & func) const +void CKeybind::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetKeybindEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ -Int32 CKeybind::GetPrimary() const +Int32 CKeybind::GetFirst() const { - if (Validate()) - return _Core->GetKeybind(m_ID).mPrimary; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetKeybind(m_ID).mFirst; } -Int32 CKeybind::GetSecondary() const +// ------------------------------------------------------------------------------------------------ +Int32 CKeybind::GetSecond() const { - if (Validate()) - return _Core->GetKeybind(m_ID).mSecondary; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetKeybind(m_ID).mSecond; } -Int32 CKeybind::GetAlternative() const +// ------------------------------------------------------------------------------------------------ +Int32 CKeybind::GetThird() const { - if (Validate()) - return _Core->GetKeybind(m_ID).mAlternative; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetKeybind(m_ID).mThird; } +// ------------------------------------------------------------------------------------------------ bool CKeybind::IsRelease() const { - if (Validate()) - return _Core->GetKeybind(m_ID).mRelease; - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetKeybind(m_ID).mRelease; } // ------------------------------------------------------------------------------------------------ -static Object & CreateKeybindEx(Int32 slot, bool release, Int32 primary, Int32 secondary, +static Object & Keybind_CreateEx(Int32 slot, bool release, Int32 primary, Int32 secondary, Int32 alternative) { return _Core->NewKeybind(slot, release, primary, secondary, alternative, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateKeybindEx(Int32 slot, bool release, Int32 primary, Int32 secondary, +static Object & Keybind_CreateEx(Int32 slot, bool release, Int32 primary, Int32 secondary, Int32 alternative, Int32 header, Object & payload) { return _Core->NewKeybind(slot, release, primary, secondary, alternative, header, payload); } // ------------------------------------------------------------------------------------------------ -static Object & CreateKeybind(bool release, Int32 primary, Int32 secondary, Int32 alternative) +static Object & Keybind_Create(bool release, Int32 primary, Int32 secondary, Int32 alternative) { return _Core->NewKeybind(-1, release, primary, secondary, alternative, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateKeybind(bool release, Int32 primary, Int32 secondary, Int32 alternative, +static Object & Keybind_Create(bool release, Int32 primary, Int32 secondary, Int32 alternative, Int32 header, Object & payload) { return _Core->NewKeybind(-1, release, primary, secondary, alternative, header, payload); @@ -148,37 +169,38 @@ void Register_CKeybind(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqKeybind"), Class< CKeybind, NoConstructor< CKeybind > >(vm, _SC("SqKeybind")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CKeybind::Cmp) + .SquirrelFunc(_SC("_typename"), &CKeybind::Typename) .Func(_SC("_tostring"), &CKeybind::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CKeybind::Max) + // Core Properties .Prop(_SC("ID"), &CKeybind::GetID) .Prop(_SC("Tag"), &CKeybind::GetTag, &CKeybind::SetTag) .Prop(_SC("Data"), &CKeybind::GetData, &CKeybind::SetData) - .Prop(_SC("MaxID"), &CKeybind::GetMaxID) .Prop(_SC("Active"), &CKeybind::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CKeybind::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CKeybind::*)(void) >(_SC("Destroy"), &CKeybind::Destroy) .Overload< bool (CKeybind::*)(Int32) >(_SC("Destroy"), &CKeybind::Destroy) .Overload< bool (CKeybind::*)(Int32, Object &) >(_SC("Destroy"), &CKeybind::Destroy) - /* Properties */ - .Prop(_SC("Primary"), &CKeybind::GetPrimary) - .Prop(_SC("Secondary"), &CKeybind::GetSecondary) - .Prop(_SC("Alternative"), &CKeybind::GetAlternative) + // Properties + .Prop(_SC("First"), &CKeybind::GetFirst) + .Prop(_SC("Second"), &CKeybind::GetSecond) + .Prop(_SC("Third"), &CKeybind::GetThird) .Prop(_SC("Release"), &CKeybind::IsRelease) + // Static Overloads + .StaticOverload< Object & (*)(Int32, bool, Int32, Int32, Int32) > + (_SC("CreateEx"), &Keybind_CreateEx) + .StaticOverload< Object & (*)(Int32, bool, Int32, Int32, Int32, Int32, Object &) > + (_SC("CreateEx"), &Keybind_CreateEx) + .StaticOverload< Object & (*)(bool, Int32, Int32, Int32) > + (_SC("Create"), &Keybind_Create) + .StaticOverload< Object & (*)(bool, Int32, Int32, Int32, Int32, Object &) > + (_SC("Create"), &Keybind_Create) ); - - RootTable(vm) - .Overload< Object & (*)(Int32, bool, Int32, Int32, Int32) > - (_SC("CreateKeybindEx"), &CreateKeybindEx) - .Overload< Object & (*)(Int32, bool, Int32, Int32, Int32, Int32, Object &) > - (_SC("CreateKeybindEx"), &CreateKeybindEx) - .Overload< Object & (*)(bool, Int32, Int32, Int32) > - (_SC("CreateKeybind"), &CreateKeybind) - .Overload< Object & (*)(bool, Int32, Int32, Int32, Int32, Object &) > - (_SC("CreateKeybind"), &CreateKeybind); } } // Namespace:: SqMod \ No newline at end of file diff --git a/source/Entity/Keybind.hpp b/source/Entity/Keybind.hpp index e589b9cb..22603c1f 100644 --- a/source/Entity/Keybind.hpp +++ b/source/Entity/Keybind.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Keybind instances. + * Manages a single keybind entity. */ class CKeybind { @@ -17,20 +17,19 @@ class CKeybind private: - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_KEYBIND_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -38,20 +37,22 @@ private: */ CKeybind(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CKeybind(const CKeybind &); + CKeybind(const CKeybind &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CKeybind & operator = (const CKeybind &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CKeybind(CKeybind &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. @@ -59,14 +60,22 @@ public: ~CKeybind(); /* -------------------------------------------------------------------------------------------- - * See whether this instance manages a valid entity. + * Copy assignment operator. (disabled) */ - bool Validate() const + CKeybind & operator = (const CKeybind &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CKeybind & operator = (CKeybind &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * See whether this instance manages a valid entity instance otherwise throw an exception. + */ + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid keybind reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid keybind reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -77,27 +86,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_KEYBIND_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -114,18 +129,50 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed destroy entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed destroy entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed destroy entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- - Int32 GetPrimary() const; - Int32 GetSecondary() const; - Int32 GetAlternative() const; + /* -------------------------------------------------------------------------------------------- + * Retrieve the first key code of the managed keybind entity. + */ + Int32 GetFirst() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the second key code of the managed keybind entity. + */ + Int32 GetSecond() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the third key code of the managed keybind entity. + */ + Int32 GetThird() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed keybind entity reacts to key release events. + */ bool IsRelease() const; }; diff --git a/source/Entity/Object.cpp b/source/Entity/Object.cpp index 5b21b793..d175be23 100644 --- a/source/Entity/Object.cpp +++ b/source/Entity/Object.cpp @@ -13,15 +13,20 @@ Vector3 CObject::s_Vector3; Quaternion CObject::s_Quaternion; // ------------------------------------------------------------------------------------------------ -SQChar CObject::s_StrID[SQMOD_OBJECT_POOL][8]; +const Int32 CObject::Max = SQMOD_OBJECT_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CObject::Max = SQMOD_OBJECT_POOL; +SQInteger CObject::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqObject"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CObject::CObject(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_OBJECT_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -43,372 +48,517 @@ Int32 CObject::Cmp(const CObject & o) const return -1; } -CSStr CObject::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CObject::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_OBJECT_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CObject::GetTag() const +const String & CObject::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CObject::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CObject::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CObject::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CObject::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelObject(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CObject::BindEvent(Int32 evid, Object & env, Function & func) const +void CObject::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetObjectEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ bool CObject::IsStreamedFor(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - return _Func->IsObjectStreamedForPlayer(m_ID, player.GetID()); - return false; + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsObjectStreamedForPlayer(m_ID, player.GetID()); } +// ------------------------------------------------------------------------------------------------ Int32 CObject::GetModel() const { - if (Validate()) - return _Func->GetObjectModel(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetObjectModel(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CObject::GetWorld() const { - if (Validate()) - return _Func->GetObjectWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetObjectWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CObject::SetWorld(Int32 world) const { - if (Validate()) - _Func->SetObjectWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ Int32 CObject::GetAlpha() const { - if (Validate()) - return _Func->GetObjectAlpha(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetObjectAlpha(m_ID); } +// ------------------------------------------------------------------------------------------------ void CObject::SetAlpha(Int32 alpha) const { - if (Validate()) - _Func->SetObjectAlpha(m_ID, alpha, 0); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectAlpha(m_ID, alpha, 0); } +// ------------------------------------------------------------------------------------------------ void CObject::SetAlphaEx(Int32 alpha, Int32 time) const { - if (Validate()) - _Func->SetObjectAlpha(m_ID, alpha, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectAlpha(m_ID, alpha, time); } +// ------------------------------------------------------------------------------------------------ void CObject::MoveTo(const Vector3 & pos, Int32 time) const { - if (Validate()) - _Func->MoveObjectTo(m_ID, pos.x, pos.y, pos.z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveObjectTo(m_ID, pos.x, pos.y, pos.z, time); } +// ------------------------------------------------------------------------------------------------ void CObject::MoveToEx(Float32 x, Float32 y, Float32 z, Int32 time) const { - if (Validate()) - _Func->MoveObjectTo(m_ID, x, y, z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveObjectTo(m_ID, x, y, z, time); } +// ------------------------------------------------------------------------------------------------ void CObject::MoveBy(const Vector3 & pos, Int32 time) const { - if (Validate()) - _Func->MoveObjectBy(m_ID, pos.x, pos.y, pos.z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveObjectBy(m_ID, pos.x, pos.y, pos.z, time); } +// ------------------------------------------------------------------------------------------------ void CObject::MoveByEx(Float32 x, Float32 y, Float32 z, Int32 time) const { - if (Validate()) - _Func->MoveObjectBy(m_ID, x, y, z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveObjectBy(m_ID, x, y, z, time); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CObject::GetPosition() { + // Validate the managed identifier + Validate(); + // Clear previous position information s_Vector3.Clear(); - if (Validate()) - _Func->GetObjectPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->GetObjectPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CObject::SetPosition(const Vector3 & pos) const { - if (Validate()) - _Func->SetObjectPos(m_ID, pos.x, pos.y, pos.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectPos(m_ID, pos.x, pos.y, pos.z); } +// ------------------------------------------------------------------------------------------------ void CObject::SetPositionEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetObjectPos(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectPos(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateTo(const Quaternion & rot, Int32 time) const { - if (Validate()) - _Func->RotObjectTo(m_ID, rot.x, rot.y, rot.z, rot.w, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectTo(m_ID, rot.x, rot.y, rot.z, rot.w, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateToEx(Float32 x, Float32 y, Float32 z, Float32 w, Int32 time) const { - if (Validate()) - _Func->RotObjectTo(m_ID, x, y, z, w, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectTo(m_ID, x, y, z, w, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateToEuler(const Vector3 & rot, Int32 time) const { - if (Validate()) - _Func->RotObjectToEuler(m_ID, rot.x, rot.y, rot.z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectToEuler(m_ID, rot.x, rot.y, rot.z, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateToEulerEx(Float32 x, Float32 y, Float32 z, Int32 time) const { - if (Validate()) - _Func->RotObjectToEuler(m_ID, x, y, z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectToEuler(m_ID, x, y, z, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateBy(const Quaternion & rot, Int32 time) const { - if (Validate()) - _Func->RotObjectBy(m_ID, rot.x, rot.y, rot.z, rot.w, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectBy(m_ID, rot.x, rot.y, rot.z, rot.w, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateByEx(Float32 x, Float32 y, Float32 z, Float32 w, Int32 time) const { - if (Validate()) - _Func->RotObjectBy(m_ID, x, y, z, w, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectBy(m_ID, x, y, z, w, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateByEuler(const Vector3 & rot, Int32 time) const { - if (Validate()) - _Func->RotObjectByEuler(m_ID, rot.x, rot.y, rot.z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectByEuler(m_ID, rot.x, rot.y, rot.z, time); } +// ------------------------------------------------------------------------------------------------ void CObject::RotateByEulerEx(Float32 x, Float32 y, Float32 z, Int32 time) const { - if (Validate()) - _Func->RotObjectByEuler(m_ID, x, y, z, time); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotObjectByEuler(m_ID, x, y, z, time); } +// ------------------------------------------------------------------------------------------------ const Quaternion & CObject::GetRotation() { + // Validate the managed identifier + Validate(); + // Clear previous rotation information s_Quaternion.Clear(); - if (Validate()) - _Func->GetObjectRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); + // Query the server for the rotation values + _Func->GetObjectRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); + // Return the requested information return s_Quaternion; } +// ------------------------------------------------------------------------------------------------ const Vector3 & CObject::GetRotationEuler() { + // Validate the managed identifier + Validate(); + // Clear previous rotation information s_Vector3.Clear(); - if (Validate()) - _Func->GetObjectRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the rotation values + _Func->GetObjectRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ bool CObject::GetShotReport() const { - if (Validate()) - return _Func->IsObjectShotReport(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsObjectShotReport(m_ID); } +// ------------------------------------------------------------------------------------------------ void CObject::SetShotReport(bool toggle) const { - if (Validate()) - _Func->SetObjectShotReport(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectShotReport(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CObject::GetBumpReport() const { - if (Validate()) - return _Func->IsObjectBumpReport(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsObjectBumpReport(m_ID); } +// ------------------------------------------------------------------------------------------------ void CObject::SetBumpReport(bool toggle) const { - if (Validate()) - _Func->SetObjectBumpReport(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetObjectBumpReport(m_ID, toggle); } // ------------------------------------------------------------------------------------------------ Float32 CObject::GetPosX() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetObjectPos(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetObjectPos(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetPosY() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetObjectPos(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetObjectPos(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetPosZ() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetObjectPos(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetObjectPos(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ void CObject::SetPosX(Float32 x) const { - if (Validate()) - { - _Func->GetObjectPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->SetObjectPos(m_ID, x, s_Vector3.y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetObjectPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->SetObjectPos(m_ID, x, s_Vector3.y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CObject::SetPosY(Float32 y) const { - if (Validate()) - { - _Func->GetObjectPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->SetObjectPos(m_ID, s_Vector3.x, y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetObjectPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->SetObjectPos(m_ID, s_Vector3.x, y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CObject::SetPosZ(Float32 z) const { - if (Validate()) - { - _Func->GetObjectPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->SetObjectPos(m_ID, s_Vector3.z, s_Vector3.y, z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetObjectPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->SetObjectPos(m_ID, s_Vector3.z, s_Vector3.y, z); } // ------------------------------------------------------------------------------------------------ Float32 CObject::GetRotX() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.x = 0; - if (Validate()) - _Func->GetObjectRot(m_ID, &s_Quaternion.x, NULL, NULL, NULL); + // Query the server for the requested component value + _Func->GetObjectRot(m_ID, &s_Quaternion.x, NULL, NULL, NULL); + // Return the requested information return s_Quaternion.x; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetRotY() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.y = 0; - if (Validate()) - _Func->GetObjectRot(m_ID, NULL, &s_Quaternion.y, NULL, NULL); + // Query the server for the requested component value + _Func->GetObjectRot(m_ID, NULL, &s_Quaternion.y, NULL, NULL); + // Return the requested information return s_Quaternion.y; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetRotZ() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.z = 0; - if (Validate()) - _Func->GetObjectRot(m_ID, NULL, NULL, &s_Quaternion.z, NULL); + // Query the server for the requested component value + _Func->GetObjectRot(m_ID, NULL, NULL, &s_Quaternion.z, NULL); + // Return the requested information return s_Quaternion.z; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetRotW() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.w = 0; - if (Validate()) - _Func->GetObjectRot(m_ID, NULL, NULL, NULL, &s_Quaternion.w); + // Query the server for the requested component value + _Func->GetObjectRot(m_ID, NULL, NULL, NULL, &s_Quaternion.w); + // Return the requested information return s_Quaternion.w; } // ------------------------------------------------------------------------------------------------ Float32 CObject::GetERotX() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetObjectRotEuler(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetObjectRotEuler(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetERotY() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetObjectRotEuler(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetObjectRotEuler(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CObject::GetERotZ() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetObjectRotEuler(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetObjectRotEuler(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ -static Object & CreateObjectEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, +static Object & Object_CreateEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Int32 alpha) { return _Core->NewObject(model, world, x, y, z, alpha, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateObjectEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, +static Object & Object_CreateEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Int32 alpha, Int32 header, Object & payload) { return _Core->NewObject(model, world, x, y, z, alpha, header, payload); } // ------------------------------------------------------------------------------------------------ -static Object & CreateObject(Int32 model, Int32 world, const Vector3 & pos, Int32 alpha) +static Object & Object_Create(Int32 model, Int32 world, const Vector3 & pos, Int32 alpha) { return _Core->NewObject(model, world, pos.x, pos.y, pos.z, alpha, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateObject(Int32 model, Int32 world, const Vector3 & pos, Int32 alpha, +static Object & Object_Create(Int32 model, Int32 world, const Vector3 & pos, Int32 alpha, Int32 header, Object & payload) { return _Core->NewObject(model, world, pos.x, pos.y, pos.z, alpha, header, payload); @@ -419,22 +569,24 @@ void Register_CObject(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqObject"), Class< CObject, NoConstructor< CObject > >(vm, _SC("SqObject")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CObject::Cmp) + .SquirrelFunc(_SC("_typename"), &CObject::Typename) .Func(_SC("_tostring"), &CObject::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CObject::Max) + // Core Properties .Prop(_SC("ID"), &CObject::GetID) .Prop(_SC("Tag"), &CObject::GetTag, &CObject::SetTag) .Prop(_SC("Data"), &CObject::GetData, &CObject::SetData) - .Prop(_SC("MaxID"), &CObject::GetMaxID) .Prop(_SC("Active"), &CObject::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CObject::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CObject::*)(void) >(_SC("Destroy"), &CObject::Destroy) .Overload< bool (CObject::*)(Int32) >(_SC("Destroy"), &CObject::Destroy) .Overload< bool (CObject::*)(Int32, Object &) >(_SC("Destroy"), &CObject::Destroy) - /* Properties */ + // Properties .Prop(_SC("Model"), &CObject::GetModel) .Prop(_SC("World"), &CObject::GetWorld, &CObject::SetWorld) .Prop(_SC("Alpha"), &CObject::GetAlpha, &CObject::SetAlpha) @@ -455,11 +607,11 @@ void Register_CObject(HSQUIRRELVM vm) .Prop(_SC("EX"), &CObject::GetERotX) .Prop(_SC("EY"), &CObject::GetERotY) .Prop(_SC("EZ"), &CObject::GetERotZ) - /* Functions */ + // Functions .Func(_SC("StreamedFor"), &CObject::IsStreamedFor) .Func(_SC("SetAlpha"), &CObject::SetAlphaEx) .Func(_SC("SetPosition"), &CObject::SetPositionEx) - /* Overloads */ + // Overloads .Overload< void (CObject::*)(const Vector3 &, Int32) const > (_SC("MoveTo"), &CObject::MoveTo) .Overload< void (CObject::*)(Float32, Float32, Float32, Int32) const > @@ -484,17 +636,16 @@ void Register_CObject(HSQUIRRELVM vm) (_SC("RotateByEuler"), &CObject::RotateByEuler) .Overload< void (CObject::*)(Float32, Float32, Float32, Int32) const > (_SC("RotateByEuler"), &CObject::RotateByEulerEx) + // Static Overloads + .StaticOverload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32) > + (_SC("CreateEx"), &Object_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32, Int32, Object &) > + (_SC("CreateEx"), &Object_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, const Vector3 &, Int32) > + (_SC("Create"), &Object_Create) + .StaticOverload< Object & (*)(Int32, Int32, const Vector3 &, Int32, Int32, Object &) > + (_SC("Create"), &Object_Create) ); - - RootTable(vm) - .Overload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32) > - (_SC("CreateObjectEx"), &CreateObjectEx) - .Overload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Int32, Int32, Object &) > - (_SC("CreateObjectEx"), &CreateObjectEx) - .Overload< Object & (*)(Int32, Int32, const Vector3 &, Int32) > - (_SC("CreateObject"), &CreateObject) - .Overload< Object & (*)(Int32, Int32, const Vector3 &, Int32, Int32, Object &) > - (_SC("CreateObject"), &CreateObject); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Object.hpp b/source/Entity/Object.hpp index feeb5191..b049b1d5 100644 --- a/source/Entity/Object.hpp +++ b/source/Entity/Object.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Object instances. + * Manages a single object entity. */ class CObject { @@ -21,20 +21,19 @@ private: static Vector3 s_Vector3; static Quaternion s_Quaternion; - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_OBJECT_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -42,20 +41,22 @@ private: */ CObject(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CObject(const CObject &); + CObject(const CObject &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CObject & operator = (const CObject &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CObject(CObject &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. @@ -63,14 +64,22 @@ public: ~CObject(); /* -------------------------------------------------------------------------------------------- - * See whether this instance manages a valid entity. + * Copy assignment operator. (disabled) */ - bool Validate() const + CObject & operator = (const CObject &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CObject & operator = (CObject &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * See whether this instance manages a valid entity instance otherwise throw an exception. + */ + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid object reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid object reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -81,27 +90,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_OBJECT_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -118,59 +133,235 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed object entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed object entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed object entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * See if the managed object entity is streamed for the specified player. + */ bool IsStreamedFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the model of the managed object entity. + */ Int32 GetModel() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the managed object entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the world in which the managed object entity exists. + */ void SetWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the alpha of the managed object entity. + */ Int32 GetAlpha() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the alpha of the managed object entity. + */ void SetAlpha(Int32 alpha) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the alpha of the managed object entity over the specified time. + */ void SetAlphaEx(Int32 alpha, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Move the managed object entity to the specified position over the specified time. + */ void MoveTo(const Vector3 & pos, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Move the managed object entity to the specified position over the specified time. + */ void MoveToEx(Float32 x, Float32 y, Float32 z, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Move the managed object entity by the specified position over the specified time. + */ void MoveBy(const Vector3 & pos, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Move the managed object entity by the specified position over the specified time. + */ void MoveByEx(Float32 x, Float32 y, Float32 z, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed object entity. + */ const Vector3 & GetPosition(); + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed object entity. + */ void SetPosition(const Vector3 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed object entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity to the specified rotation over the specified time. + */ void RotateTo(const Quaternion & rot, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity to the specified rotation over the specified time. + */ void RotateToEx(Float32 x, Float32 y, Float32 z, Float32 w, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity to the specified euler rotation over the specified time. + */ void RotateToEuler(const Vector3 & rot, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity to the specified euler rotation over the specified time. + */ void RotateToEulerEx(Float32 x, Float32 y, Float32 z, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity by the specified rotation over the specified time. + */ void RotateBy(const Quaternion & rot, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity by the specified rotation over the specified time. + */ void RotateByEx(Float32 x, Float32 y, Float32 z, Float32 w, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity by the specified euler rotation over the specified time. + */ void RotateByEuler(const Vector3 & rot, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Rotate the managed object entity by the specified euler rotation over the specified time. + */ void RotateByEulerEx(Float32 x, Float32 y, Float32 z, Int32 time) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation of the managed object entity. + */ const Quaternion & GetRotation(); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation of the managed object entity. + */ const Vector3 & GetRotationEuler(); + + /* -------------------------------------------------------------------------------------------- + * See whether the managed object entity reports gunshots. + */ bool GetShotReport() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed object entity reports gunshots. + */ void SetShotReport(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed object entity reports player bumps. + */ bool GetBumpReport() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed object entity reports player bumps. + */ void SetBumpReport(bool toggle) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed object entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed object entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed object entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the x axis of the managed object entity. + */ void SetPosX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the y axis of the managed object entity. + */ void SetPosY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the z axis of the managed object entity. + */ void SetPosZ(Float32 z) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation on the x axis of the managed object entity. + */ Float32 GetRotX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation on the y axis of the managed object entity. + */ Float32 GetRotY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation on the z axis of the managed object entity. + */ Float32 GetRotZ() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation amount of the managed object entity. + */ Float32 GetRotW() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation on the x axis of the managed object entity. + */ Float32 GetERotX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation on the y axis of the managed object entity. + */ Float32 GetERotY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation on the z axis of the managed object entity. + */ Float32 GetERotZ() const; }; diff --git a/source/Entity/Pickup.cpp b/source/Entity/Pickup.cpp index 145cf4fd..ba6e54c3 100644 --- a/source/Entity/Pickup.cpp +++ b/source/Entity/Pickup.cpp @@ -11,15 +11,20 @@ namespace SqMod { Vector3 CPickup::s_Vector3; // ------------------------------------------------------------------------------------------------ -SQChar CPickup::s_StrID[SQMOD_PICKUP_POOL][8]; +const Int32 CPickup::Max = SQMOD_PICKUP_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CPickup::Max = SQMOD_PICKUP_POOL; +SQInteger CPickup::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqPickup"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CPickup::CPickup(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_PICKUP_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -41,221 +46,289 @@ Int32 CPickup::Cmp(const CPickup & o) const return -1; } -CSStr CPickup::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CPickup::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_PICKUP_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CPickup::GetTag() const +const String & CPickup::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CPickup::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CPickup::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CPickup::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CPickup::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelPickup(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CPickup::BindEvent(Int32 evid, Object & env, Function & func) const +void CPickup::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetPickupEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ bool CPickup::IsStreamedFor(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - return _Func->IsPickupStreamedForPlayer(m_ID, player.GetID()); - return false; + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPickupStreamedForPlayer(m_ID, player.GetID()); } +// ------------------------------------------------------------------------------------------------ Int32 CPickup::GetModel() const { - if (Validate()) - return _Func->PickupGetModel(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->PickupGetModel(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPickup::GetWorld() const { - if (Validate()) - return _Func->GetPickupWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPickupWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPickup::SetWorld(Int32 world) const { - if (Validate()) - _Func->SetPickupWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPickupWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ Int32 CPickup::GetAlpha() const { - if (Validate()) - return _Func->GetVehicleModel(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleModel(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPickup::SetAlpha(Int32 alpha) const { - if (Validate()) - _Func->PickupSetAlpha(m_ID, alpha); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PickupSetAlpha(m_ID, alpha); } +// ------------------------------------------------------------------------------------------------ bool CPickup::GetAutomatic() const { - if (Validate()) - return _Func->PickupIsAutomatic(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->PickupIsAutomatic(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPickup::SetAutomatic(bool toggle) const { - if (Validate()) - _Func->PickupSetAutomatic(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PickupSetAutomatic(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ Int32 CPickup::GetAutoTimer() const { - if (Validate()) - return _Func->GetPickupAutoTimer(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPickupAutoTimer(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPickup::SetAutoTimer(Int32 timer) const { - if (Validate()) - _Func->SetPickupAutoTimer(m_ID, timer); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPickupAutoTimer(m_ID, timer); } +// ------------------------------------------------------------------------------------------------ void CPickup::Refresh() const { - if (Validate()) - _Func->PickupRefresh(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PickupRefresh(m_ID); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CPickup::GetPosition() { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.Clear(); - if (Validate()) - _Func->PickupGetPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->PickupGetPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CPickup::SetPosition(const Vector3 & pos) const { - if (Validate()) - _Func->PickupSetPos(m_ID, pos.x, pos.y, pos.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PickupSetPos(m_ID, pos.x, pos.y, pos.z); } +// ------------------------------------------------------------------------------------------------ void CPickup::SetPositionEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->PickupSetPos(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PickupSetPos(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ Int32 CPickup::GetQuantity() const { - if (Validate()) - return _Func->PickupGetQuantity(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->PickupGetQuantity(m_ID); } // ------------------------------------------------------------------------------------------------ Float32 CPickup::GetPosX() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.x = 0; - if (Validate()) - _Func->PickupGetPos(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->PickupGetPos(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CPickup::GetPosY() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.y = 0; - if (Validate()) - _Func->PickupGetPos(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->PickupGetPos(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CPickup::GetPosZ() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.z = 0; - if (Validate()) - _Func->PickupGetPos(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->PickupGetPos(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ void CPickup::SetPosX(Float32 x) const { - if (Validate()) - { - _Func->PickupGetPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->PickupSetPos(m_ID, x, s_Vector3.y, s_Vector3.z); - } -} - -void CPickup::SetPosY(Float32 y) const -{ - if (Validate()) - { - _Func->PickupGetPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->PickupSetPos(m_ID, s_Vector3.x, y, s_Vector3.z); - } -} - -void CPickup::SetPosZ(Float32 z) const -{ - if (Validate()) - { - _Func->PickupGetPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->PickupSetPos(m_ID, s_Vector3.z, s_Vector3.y, z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->PickupGetPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->PickupSetPos(m_ID, x, s_Vector3.y, s_Vector3.z); } // ------------------------------------------------------------------------------------------------ -static Object & CreatePickupEx(Int32 model, Int32 world, Int32 quantity, +void CPickup::SetPosY(Float32 y) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->PickupGetPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->PickupSetPos(m_ID, s_Vector3.x, y, s_Vector3.z); +} + +// ------------------------------------------------------------------------------------------------ +void CPickup::SetPosZ(Float32 z) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->PickupGetPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->PickupSetPos(m_ID, s_Vector3.z, s_Vector3.y, z); +} + +// ------------------------------------------------------------------------------------------------ +static Object & Pickup_CreateEx(Int32 model, Int32 world, Int32 quantity, Float32 x, Float32 y, Float32 z, Int32 alpha, bool automatic) { return _Core->NewPickup(model, world, quantity, x, y, z, alpha, automatic, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreatePickupEx(Int32 model, Int32 world, Int32 quantity, +static Object & Pickup_CreateEx(Int32 model, Int32 world, Int32 quantity, Float32 x, Float32 y, Float32 z, Int32 alpha, bool automatic, Int32 header, Object & payload) { @@ -263,14 +336,14 @@ static Object & CreatePickupEx(Int32 model, Int32 world, Int32 quantity, } // ------------------------------------------------------------------------------------------------ -static Object & CreatePickup(Int32 model, Int32 world, Int32 quantity, const Vector3 & pos, +static Object & Pickup_Create(Int32 model, Int32 world, Int32 quantity, const Vector3 & pos, Int32 alpha, bool automatic) { return _Core->NewPickup(model, world, quantity, pos.x, pos.y, pos.z, alpha, automatic, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreatePickup(Int32 model, Int32 world, Int32 quantity, const Vector3 & pos, +static Object & Pickup_Create(Int32 model, Int32 world, Int32 quantity, const Vector3 & pos, Int32 alpha, bool automatic, Int32 header, Object & payload) { return _Core->NewPickup(model, world, quantity, pos.x, pos.y, pos.z, alpha, automatic, @@ -282,22 +355,24 @@ void Register_CPickup(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqPickup"), Class< CPickup, NoConstructor< CPickup > >(vm, _SC("SqPickup")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CPickup::Cmp) + .SquirrelFunc(_SC("_typename"), &CPickup::Typename) .Func(_SC("_tostring"), &CPickup::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CPickup::Max) + // Core Properties .Prop(_SC("ID"), &CPickup::GetID) .Prop(_SC("Tag"), &CPickup::GetTag, &CPickup::SetTag) .Prop(_SC("Data"), &CPickup::GetData, &CPickup::SetData) - .Prop(_SC("MaxID"), &CPickup::GetMaxID) .Prop(_SC("Active"), &CPickup::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CPickup::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CPickup::*)(void) >(_SC("Destroy"), &CPickup::Destroy) .Overload< bool (CPickup::*)(Int32) >(_SC("Destroy"), &CPickup::Destroy) .Overload< bool (CPickup::*)(Int32, Object &) >(_SC("Destroy"), &CPickup::Destroy) - /* Properties */ + // Properties .Prop(_SC("Model"), &CPickup::GetModel) .Prop(_SC("World"), &CPickup::GetWorld, &CPickup::SetWorld) .Prop(_SC("Alpha"), &CPickup::GetAlpha, &CPickup::SetAlpha) @@ -311,22 +386,21 @@ void Register_CPickup(HSQUIRRELVM vm) .Prop(_SC("X"), &CPickup::GetPosX, &CPickup::SetPosX) .Prop(_SC("Y"), &CPickup::GetPosY, &CPickup::SetPosY) .Prop(_SC("Z"), &CPickup::GetPosZ, &CPickup::SetPosZ) - /* Functions */ + // Functions .Func(_SC("StreamedFor"), &CPickup::IsStreamedFor) .Func(_SC("Refresh"), &CPickup::Refresh) .Func(_SC("SetPos"), &CPickup::SetPositionEx) .Func(_SC("SetPosition"), &CPickup::SetPositionEx) + // Static Overloads + .StaticOverload< Object & (*)(Int32, Int32, Int32, Float32, Float32, Float32, Int32, bool) > + (_SC("CreateEx"), &Pickup_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, Int32, Float32, Float32, Float32, Int32, bool, Int32, Object &) > + (_SC("CreateEx"), &Pickup_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, Int32, const Vector3 &, Int32, bool) > + (_SC("Create"), &Pickup_Create) + .StaticOverload< Object & (*)(Int32, Int32, Int32, const Vector3 &, Int32, bool, Int32, Object &) > + (_SC("Create"), &Pickup_Create) ); - - RootTable(vm) - .Overload< Object & (*)(Int32, Int32, Int32, Float32, Float32, Float32, Int32, bool) > - (_SC("CreatePickupEx"), &CreatePickupEx) - .Overload< Object & (*)(Int32, Int32, Int32, Float32, Float32, Float32, Int32, bool, Int32, Object &) > - (_SC("CreatePickupEx"), &CreatePickupEx) - .Overload< Object & (*)(Int32, Int32, Int32, const Vector3 &, Int32, bool) > - (_SC("CreatePickup"), &CreatePickup) - .Overload< Object & (*)(Int32, Int32, Int32, const Vector3 &, Int32, bool, Int32, Object &) > - (_SC("CreatePickup"), &CreatePickup); } } // Namespace:: SqMod \ No newline at end of file diff --git a/source/Entity/Pickup.hpp b/source/Entity/Pickup.hpp index 834b50a7..4284d27b 100644 --- a/source/Entity/Pickup.hpp +++ b/source/Entity/Pickup.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Pickup instances. + * Manages a single pickup entity. */ class CPickup { @@ -20,20 +20,19 @@ private: // -------------------------------------------------------------------------------------------- static Vector3 s_Vector3; - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_PICKUP_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -41,20 +40,22 @@ private: */ CPickup(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CPickup(const CPickup &); + CPickup(const CPickup &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CPickup & operator = (const CPickup &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CPickup(CPickup &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. @@ -62,14 +63,22 @@ public: ~CPickup(); /* -------------------------------------------------------------------------------------------- - * See whether this instance manages a valid entity. + * Copy assignment operator. (disabled) */ - bool Validate() const + CPickup & operator = (const CPickup &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CPickup & operator = (CPickup &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * See whether this instance manages a valid entity instance otherwise throw an exception. + */ + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid pickup reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid pickup reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -80,27 +89,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_PICKUP_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -117,37 +132,135 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed pickup entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed pickup entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed pickup entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * See if the managed pickup entity is streamed for the specified player. + */ bool IsStreamedFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the model of the managed pickup entity. + */ Int32 GetModel() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the managed pickup entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Mpdify the world in which the managed pickup entity exists. + */ void SetWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the alpha of the managed pickup entity. + */ Int32 GetAlpha() const; + + /* -------------------------------------------------------------------------------------------- + * Mpdify the alpha of the managed pickup entity. + */ void SetAlpha(Int32 alpha) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed pickup entity is automatic. + */ bool GetAutomatic() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed pickup entity is automatic. + */ void SetAutomatic(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the automatic timer of the managed pickup entity. + */ Int32 GetAutoTimer() const; + + /* -------------------------------------------------------------------------------------------- + * Mpdify the automatic timer of the managed pickup entity. + */ void SetAutoTimer(Int32 timer) const; + + /* -------------------------------------------------------------------------------------------- + * Refresh the managed pickup entity. + */ void Refresh() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed pickup entity. + */ const Vector3 & GetPosition(); + + /* -------------------------------------------------------------------------------------------- + * Mpdify the position of the managed pickup entity. + */ void SetPosition(const Vector3 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Mpdify the position of the managed pickup entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the quantity of the managed pickup entity. + */ Int32 GetQuantity() const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed pickup entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed pickup entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed pickup entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the x axis of the managed pickup entity. + */ void SetPosX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the y axis of the managed pickup entity. + */ void SetPosY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the z axis of the managed pickup entity. + */ void SetPosZ(Float32 z) const; }; diff --git a/source/Entity/Player.cpp b/source/Entity/Player.cpp index 4873d204..4f966307 100644 --- a/source/Entity/Player.cpp +++ b/source/Entity/Player.cpp @@ -19,15 +19,20 @@ Vector3 CPlayer::s_Vector3; SQChar CPlayer::s_Buffer[SQMOD_PLAYER_TMP_BUFFER]; // ------------------------------------------------------------------------------------------------ -SQChar CPlayer::s_StrID[SQMOD_PLAYER_POOL][8]; +const Int32 CPlayer::Max = SQMOD_PLAYER_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CPlayer::Max = SQMOD_PLAYER_POOL; +SQInteger CPlayer::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqPlayer"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CPlayer::CPlayer(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_PLAYER_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -49,936 +54,1269 @@ Int32 CPlayer::Cmp(const CPlayer & o) const return -1; } -CSStr CPlayer::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CPlayer::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_PLAYER_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CPlayer::GetTag() const +const String & CPlayer::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CPlayer::GetData() { - if (Validate()) - return m_Data; - return NullObject(); -} - -void CPlayer::SetData(Object & data) -{ - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } // ------------------------------------------------------------------------------------------------ -bool CPlayer::BindEvent(Int32 evid, Object & env, Function & func) const +void CPlayer::SetData(Object & data) { - if (!Validate()) - return false; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; +} +// ------------------------------------------------------------------------------------------------ +void CPlayer::BindEvent(Int32 evid, Object & env, Function & func) const +{ + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetPlayerEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ bool CPlayer::IsStreamedFor(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - return _Func->IsPlayerStreamedForPlayer(m_ID, player.GetID()); - return false; + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPlayerStreamedForPlayer(m_ID, player.GetID()); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetClass() const { - if (Validate()) - return _Func->GetPlayerClass(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerClass(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetAdmin() const { - if (Validate()) - return _Func->IsPlayerAdmin(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPlayerAdmin(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetAdmin(bool toggle) const { - if (Validate()) - _Func->SetPlayerAdmin(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerAdmin(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ CSStr CPlayer::GetIP() const { + // Validate the managed identifier + Validate(); + // Clear any previous string s_Buffer[0] = 0; - - if (Validate()) - { - memset(s_Buffer, 0, sizeof(s_Buffer)); - _Func->GetPlayerIP(m_ID, s_Buffer, sizeof(s_Buffer)); - } - + // The server doesn't include the null terminator in the string (yet) + memset(s_Buffer, 0, sizeof(s_Buffer)); + // Query the server for the ip of the managed player + _Func->GetPlayerIP(m_ID, s_Buffer, sizeof(s_Buffer)); + // Return the requested information return s_Buffer; } +// ------------------------------------------------------------------------------------------------ void CPlayer::Kick() const { - if (Validate()) - _Func->KickPlayer(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->KickPlayer(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::Ban() const { - if (Validate()) - _Func->BanPlayer(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->BanPlayer(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsConnected() const { return _Func->IsPlayerConnected(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsSpawned() const { - if (Validate()) - return _Func->IsPlayerSpawned(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPlayerSpawned(m_ID); } +// ------------------------------------------------------------------------------------------------ Uint32 CPlayer::GetKey() const { - if (Validate()) - return _Func->GetPlayerKey(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerKey(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetWorld() const { - if (Validate()) - return _Func->GetPlayerWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetWorld(Int32 world) const { - if (Validate()) - _Func->SetPlayerWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetSecWorld() const { - if (Validate()) - return _Func->GetPlayerSecWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerSecWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetSecWorld(Int32 world) const { - if (Validate()) - _Func->SetPlayerSecWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerSecWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetUniqueWorld() const { - if (Validate()) - return _Func->GetPlayerUniqueWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerUniqueWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsWorldCompatible(Int32 world) const { - if (Validate()) - return _Func->IsPlayerWorldCompatible(m_ID, world); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPlayerWorldCompatible(m_ID, world); } +// ------------------------------------------------------------------------------------------------ CSStr CPlayer::GetName() const { + // Validate the managed identifier + Validate(); + // Clear any previous string s_Buffer[0] = 0; - - if (Validate()) - { - memset(s_Buffer, 0, sizeof(s_Buffer)); - _Func->GetPlayerName(m_ID, s_Buffer, sizeof(s_Buffer)); - } - + // The server doesn't include the null terminator in the string (yet) + memset(s_Buffer, 0, sizeof(s_Buffer)); + // Query the server for the name of the managed player + _Func->GetPlayerName(m_ID, s_Buffer, sizeof(s_Buffer)); + // Return the requested information return s_Buffer; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetName(CSStr name) const { - if (Validate()) - _Func->SetPlayerName(m_ID, static_cast< CCStr >(name)); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerName(m_ID, static_cast< CCStr >(name)); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetTeam() const { - if (Validate()) - return _Func->GetPlayerTeam(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerTeam(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetTeam(Int32 team) const { - if (Validate()) - _Func->SetPlayerTeam(m_ID, team); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerTeam(m_ID, team); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetSkin() const { - if (Validate()) - return _Func->GetPlayerSkin(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerSkin(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetSkin(Int32 skin) const { - - if (Validate()) - _Func->SetPlayerSkin(m_ID, skin); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerSkin(m_ID, skin); } +// ------------------------------------------------------------------------------------------------ const Color3 & CPlayer::GetColor() const { + // Validate the managed identifier + Validate(); + // Clear previous color information, if any s_Color3.Clear(); - if (Validate()) - s_Color3.SetRGB(_Func->GetPlayerColour(m_ID)); + // Query the server for the color values + s_Color3.SetRGB(_Func->GetPlayerColour(m_ID)); + // Return the requested information return s_Color3; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetColor(const Color3 & color) const { - if (Validate()) - _Func->SetPlayerColour(m_ID, color.GetRGB()); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerColour(m_ID, color.GetRGB()); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetColorEx(Uint8 r, Uint8 g, Uint8 b) const { - if (Validate()) - _Func->SetPlayerColour(m_ID, SQMOD_PACK_RGB(r, g, b)); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerColour(m_ID, SQMOD_PACK_RGB(r, g, b)); } +// ------------------------------------------------------------------------------------------------ void CPlayer::ForceSpawn() const { - if (Validate()) - _Func->ForcePlayerSpawn(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ForcePlayerSpawn(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::ForceSelect() const { - if (Validate()) - _Func->ForcePlayerSelect(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ForcePlayerSelect(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetMoney() const { - if (Validate()) - return _Func->GetPlayerMoney(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerMoney(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetMoney(Int32 amount) const { - if (Validate()) - _Func->SetPlayerMoney(m_ID, amount); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerMoney(m_ID, amount); } +// ------------------------------------------------------------------------------------------------ void CPlayer::GiveMoney(Int32 amount) const { - if (Validate()) - _Func->GivePlayerMoney(m_ID, amount); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->GivePlayerMoney(m_ID, amount); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetScore() const { - if (Validate()) - return _Func->GetPlayerScore(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerScore(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetScore(Int32 score) const { - if (Validate()) - _Func->SetPlayerScore(m_ID, score); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerScore(m_ID, score); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetPing() const { - if (Validate()) - return _Func->GetPlayerPing(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerPing(m_ID); } +// ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetFPS() const { - if (Validate()) - return _Func->GetPlayerFPS(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerFPS(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsTyping() const { - if (Validate()) - return _Func->IsPlayerTyping(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPlayerTyping(m_ID); } +// ------------------------------------------------------------------------------------------------ CSStr CPlayer::GetUID() const { + // Validate the managed identifier + Validate(); + // Clear any previous string s_Buffer[0] = 0; - - if (Validate()) - { - memset(s_Buffer, 0, sizeof(s_Buffer)); - _Func->GetPlayerUID(m_ID, s_Buffer, sizeof(s_Buffer)); - } - + // The server doesn't include the null terminator in the string (yet) + memset(s_Buffer, 0, sizeof(s_Buffer)); + // Query the server for the uid of the managed player + _Func->GetPlayerUID(m_ID, s_Buffer, sizeof(s_Buffer)); + // Return the requested information return s_Buffer; } +// ------------------------------------------------------------------------------------------------ CSStr CPlayer::GetUID2() const { + // Validate the managed identifier + Validate(); + // Clear any previous string s_Buffer[0] = 0; - - if (Validate()) - { - memset(s_Buffer, 0, sizeof(s_Buffer)); - _Func->GetPlayerUID2(m_ID, s_Buffer, sizeof(s_Buffer)); - } - + // The server doesn't include the null terminator in the string (yet) + memset(s_Buffer, 0, sizeof(s_Buffer)); + // Query the server for the uid2 of the managed player + _Func->GetPlayerUID2(m_ID, s_Buffer, sizeof(s_Buffer)); + // Return the requested information return s_Buffer; } +// ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetHealth() const { - if (Validate()) - return _Func->GetPlayerHealth(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerHealth(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetHealth(Float32 amount) const { - if (Validate()) - _Func->SetPlayerHealth(m_ID, amount); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerHealth(m_ID, amount); } +// ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetArmor() const { - if (Validate()) - return _Func->GetPlayerArmour(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerArmour(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetArmor(Float32 amount) const { - if (Validate()) - _Func->SetPlayerArmour(m_ID, amount); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerArmour(m_ID, amount); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetImmunity() const { - if (Validate()) - return _Func->GetPlayerImmunityFlags(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerImmunityFlags(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetImmunity(Int32 flags) const { - if (Validate()) - _Func->SetPlayerImmunityFlags(m_ID, flags); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerImmunityFlags(m_ID, flags); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CPlayer::GetPosition() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetPlayerPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->GetPlayerPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetPosition(const Vector3 & pos) const { - if (Validate()) - _Func->SetPlayerPos(m_ID, pos.x, pos.y, pos.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerPos(m_ID, pos.x, pos.y, pos.z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetPositionEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetPlayerPos(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerPos(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CPlayer::GetSpeed() const { + // Validate the managed identifier + Validate(); + // Clear previous speed information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetPlayerSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the speed values + _Func->GetPlayerSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->SetPlayerSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetPlayerSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::AddSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->AddPlayerSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddPlayerSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::AddSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->AddPlayerSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddPlayerSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetHeading() const { - if (Validate()) - return _Func->GetPlayerHeading(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerHeading(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetHeading(Float32 angle) const { - if (Validate()) - _Func->SetPlayerHeading(m_ID, angle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerHeading(m_ID, angle); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetAlpha() const { - if (Validate()) - return _Func->GetPlayerAlpha(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerAlpha(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetAlpha(Int32 alpha, Int32 fade) const { - if (Validate()) - _Func->SetPlayerAlpha(m_ID, alpha, fade); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerAlpha(m_ID, alpha, fade); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetVehicleStatus() const { - if (Validate()) - return _Func->GetPlayerInVehicleStatus(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerInVehicleStatus(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetOccupiedSlot() const { - if (Validate()) - return _Func->GetPlayerInVehicleSlot(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerInVehicleSlot(m_ID); } +// ------------------------------------------------------------------------------------------------ Object & CPlayer::GetVehicle() const { - if (Validate()) - return _Core->GetVehicle(_Func->GetPlayerVehicleID(m_ID)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetVehicle(_Func->GetPlayerVehicleID(m_ID)).mObj; } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetVehicleID() const { - if (Validate()) - return _Func->GetPlayerVehicleID(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerVehicleID(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetControllable() const { - if (Validate()) - return _Func->EnabledPlayerControllable(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerControllable(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetControllable(bool toggle) const { - if (Validate()) - _Func->TogglePlayerControllable(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerControllable(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetDriveby() const { - if (Validate()) - return _Func->EnabledPlayerDriveby(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerDriveby(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetDriveby(bool toggle) const { - if (Validate()) - _Func->TogglePlayerDriveby(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerDriveby(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetWhiteScanlines() const { - if (Validate()) - return _Func->EnabledPlayerWhiteScanlines(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerWhiteScanlines(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetWhiteScanlines(bool toggle) const { - if (Validate()) - _Func->TogglePlayerWhiteScanlines(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerWhiteScanlines(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetGreenScanlines() const { - if (Validate()) - return _Func->EnabledPlayerGreenScanlines(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerGreenScanlines(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetGreenScanlines(bool toggle) const { - if (Validate()) - _Func->TogglePlayerGreenScanlines(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerGreenScanlines(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetWidescreen() const { - if (Validate()) - return _Func->EnabledPlayerWidescreen(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerWidescreen(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetWidescreen(bool toggle) const { - if (Validate()) - _Func->TogglePlayerWidescreen(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerWidescreen(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetShowMarkers() const { - if (Validate()) - return _Func->EnabledPlayerShowMarkers(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerShowMarkers(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetShowMarkers(bool toggle) const { - if (Validate()) - _Func->TogglePlayerShowMarkers(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerShowMarkers(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetAttackPriv() const { - if (Validate()) - return _Func->EnabledPlayerAttackPriv(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerAttackPriv(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetAttackPriv(bool toggle) const { - if (Validate()) - _Func->TogglePlayerAttackPriv(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerAttackPriv(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetHasMarker() const { - if (Validate()) - return _Func->EnabledPlayerHasMarker(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerHasMarker(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetHasMarker(bool toggle) const { - if (Validate()) - _Func->TogglePlayerHasMarker(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerHasMarker(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetChatTags() const { - if (Validate()) - return _Func->EnabledPlayerChatTags(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerChatTags(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetChatTags(bool toggle) const { - if (Validate()) - _Func->TogglePlayerChatTagsEnabled(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerChatTagsEnabled(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::GetDrunkEffects() const { - if (Validate()) - return _Func->EnabledPlayerDrunkEffects(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->EnabledPlayerDrunkEffects(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetDrunkEffects(bool toggle) const { - if (Validate()) - _Func->TogglePlayerDrunkEffects(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->TogglePlayerDrunkEffects(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetWeapon() const { - if (Validate()) - return _Func->GetPlayerWeapon(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerWeapon(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetWeapon(Int32 wep, Int32 ammo) const { - if (Validate()) - _Func->SetPlayerWeapon(m_ID, wep, ammo); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerWeapon(m_ID, wep, ammo); } +// ------------------------------------------------------------------------------------------------ void CPlayer::GiveWeapon(Int32 wep, Int32 ammo) const { - if (Validate()) - _Func->GivePlayerWeapon(m_ID, wep, ammo); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->GivePlayerWeapon(m_ID, wep, ammo); } +// ------------------------------------------------------------------------------------------------ void CPlayer::StripWeapons() const { - if (Validate()) - _Func->RemoveAllWeapons(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RemoveAllWeapons(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetCameraPosition(const Vector3 & pos, const Vector3 & aim) const { - if (Validate()) - _Func->SetCameraPosition(m_ID, pos.x, pos.y, pos.z, aim.x, aim.y, aim.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCameraPosition(m_ID, pos.x, pos.y, pos.z, aim.x, aim.y, aim.z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetCameraPosition(Float32 xp, Float32 yp, Float32 zp, Float32 xa, Float32 ya, Float32 za) const { - if (Validate()) - _Func->SetCameraPosition(m_ID, xp, yp, zp, xa, ya, za); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetCameraPosition(m_ID, xp, yp, zp, xa, ya, za); } +// ------------------------------------------------------------------------------------------------ void CPlayer::RestoreCamera() const { - if (Validate()) - _Func->RestoreCamera(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RestoreCamera(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsCameraLocked() const { - if (Validate()) - _Func->IsCameraLocked(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsCameraLocked(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetAnimation(Int32 group, Int32 anim) const { - if (Validate()) - _Func->SetPlayerAnimation(m_ID, group, anim); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerAnimation(m_ID, group, anim); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetWantedLevel() const { - if (Validate()) - return _Func->GetPlayerWantedLevel(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerWantedLevel(m_ID); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetWantedLevel(Int32 level) const { - if (Validate()) - _Func->SetPlayerWantedLevel(m_ID, level); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerWantedLevel(m_ID, level); } +// ------------------------------------------------------------------------------------------------ Object & CPlayer::StandingOnVehicle() const { - if (Validate()) - return _Core->GetVehicle(_Func->GetPlayerStandingOnVehicle(m_ID)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetVehicle(_Func->GetPlayerStandingOnVehicle(m_ID)).mObj; } +// ------------------------------------------------------------------------------------------------ Object & CPlayer::StandingOnObject() const { - if (Validate()) - return _Core->GetObject(_Func->GetPlayerStandingOnObject(m_ID)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetObject(_Func->GetPlayerStandingOnObject(m_ID)).mObj; } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsAway() const { - if (Validate()) - return _Func->IsPlayerAway(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsPlayerAway(m_ID); } +// ------------------------------------------------------------------------------------------------ Object & CPlayer::GetSpectator() const { - if (Validate()) - return _Core->GetPlayer(_Func->GetPlayerSpectateTarget(m_ID)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(_Func->GetPlayerSpectateTarget(m_ID)).mObj; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetSpectator(CPlayer & target) const { + // Is the specified player even valid? if (!target.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->SetPlayerSpectateTarget(m_ID, target.GetID()); + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetPlayerSpectateTarget(m_ID, target.GetID()); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsBurning() const { - if (Validate()) - return _Func->GetPlayerOnFireStatus(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerOnFireStatus(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::IsCrouched() const { - if (Validate()) - return _Func->GetPlayerCrouchStatus(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerCrouchStatus(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetState() const { - if (Validate()) - return _Func->GetPlayerState(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerState(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetAction() const { - if (Validate()) - return _Func->GetPlayerAction(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerAction(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetGameKeys() const { - if (Validate()) - return _Func->GetPlayerGameKeys(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetPlayerGameKeys(m_ID); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CPlayer::GetAimPos() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetPlayerAimPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->GetPlayerAimPos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ const Vector3 & CPlayer::GetAimDir() const { + // Validate the managed identifier + Validate(); + // Clear previous direction information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetPlayerAimDir(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the direction values + _Func->GetPlayerAimDir(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CPlayer::Embark(CVehicle & vehicle) const { + // Is the specified vehicle even valid? if (!vehicle.IsActive()) - SqThrow("Invalid vehicle argument: null"); - else if (Validate()) - _Func->PutPlayerInVehicle(m_ID, vehicle.GetID(), 0, true, true); + SqThrowF("Invalid vehicle argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PutPlayerInVehicle(m_ID, vehicle.GetID(), 0, true, true); } +// ------------------------------------------------------------------------------------------------ void CPlayer::Embark(CVehicle & vehicle, Int32 slot, bool allocate, bool warp) const { + // Is the specified vehicle even valid? if (!vehicle.IsActive()) - SqThrow("Invalid vehicle argument: null"); - else if (Validate()) - _Func->PutPlayerInVehicle(m_ID, vehicle.GetID(), slot, allocate, warp); + SqThrowF("Invalid vehicle argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PutPlayerInVehicle(m_ID, vehicle.GetID(), slot, allocate, warp); } +// ------------------------------------------------------------------------------------------------ void CPlayer::Disembark() const { - if (Validate()) - _Func->RemovePlayerFromVehicle(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RemovePlayerFromVehicle(m_ID); } +// ------------------------------------------------------------------------------------------------ bool CPlayer::Redirect(CSStr ip, Uint32 port, CSStr nick, CSStr pass, CSStr user) { - if (Validate()) - return _Func->RedirectPlayerToServer(m_ID, ip, port, nick, pass, user); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->RedirectPlayerToServer(m_ID, ip, port, nick, pass, user); } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetAuthority() const { - if (Validate()) - return _Core->GetPlayer(m_ID).mAuthority; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(m_ID).mAuthority; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetAuthority(Int32 level) const { - if (Validate()) - _Core->GetPlayer(m_ID).mAuthority = level; + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Core->GetPlayer(m_ID).mAuthority = level; } +// ------------------------------------------------------------------------------------------------ CSStr CPlayer::GetMessagePrefix(Uint32 index) const { + // Perform a range check on the specified prefix index if (index >= SQMOD_PLAYER_MSG_PREFIXES) - SqThrow("Prefix index is out of range: %u >= %d", index, SQMOD_PLAYER_MSG_PREFIXES); - else if (Validate()) - return _Core->GetPlayer(m_ID).mPrefixes[index].c_str(); - return _SC(""); + SqThrowF("Prefix index is out of range: %u >= %d", index, SQMOD_PLAYER_MSG_PREFIXES); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(m_ID).mPrefixes[index].c_str(); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetMessagePrefix(Uint32 index, CSStr prefix) const { + // Perform a range check on the specified prefix index if (index >= SQMOD_PLAYER_MSG_PREFIXES) - SqThrow("Prefix index is out of range: %u >= %d", index, SQMOD_PLAYER_MSG_PREFIXES); - else if (Validate()) - _Core->GetPlayer(m_ID).mPrefixes[index].assign(prefix); + SqThrowF("Prefix index is out of range: %u >= %d", index, SQMOD_PLAYER_MSG_PREFIXES); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Core->GetPlayer(m_ID).mPrefixes[index].assign(prefix); } +// ------------------------------------------------------------------------------------------------ Uint32 CPlayer::GetMessageColor() const { - if (Validate()) - return _Core->GetPlayer(m_ID).mMessageColor; - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(m_ID).mMessageColor; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetMessageColor(Uint32 color) const { - if (Validate()) - _Core->GetPlayer(m_ID).mMessageColor = color; + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Core->GetPlayer(m_ID).mMessageColor = color; } +// ------------------------------------------------------------------------------------------------ Int32 CPlayer::GetAnnounceStyle() const { - if (Validate()) - return _Core->GetPlayer(m_ID).mAnnounceStyle; - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(m_ID).mAnnounceStyle; } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetAnnounceStyle(Int32 style) const { - if (Validate()) - _Core->GetPlayer(m_ID).mAnnounceStyle = style; + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Core->GetPlayer(m_ID).mAnnounceStyle = style; } // ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetPosX() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetPlayerPos(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetPlayerPos(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetPosY() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetPlayerPos(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetPlayerPos(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CPlayer::GetPosZ() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetPlayerPos(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetPlayerPos(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ void CPlayer::SetPosX(Float32 x) const { - if (Validate()) - { - _Func->GetPlayerPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->SetPlayerPos(m_ID, x, s_Vector3.y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetPlayerPos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->SetPlayerPos(m_ID, x, s_Vector3.y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetPosY(Float32 y) const { - if (Validate()) - { - _Func->GetPlayerPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->SetPlayerPos(m_ID, s_Vector3.x, y, s_Vector3.z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetPlayerPos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->SetPlayerPos(m_ID, s_Vector3.x, y, s_Vector3.z); } +// ------------------------------------------------------------------------------------------------ void CPlayer::SetPosZ(Float32 z) const { - if (Validate()) - { - _Func->GetPlayerPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->SetPlayerPos(m_ID, s_Vector3.z, s_Vector3.y, z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetPlayerPos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->SetPlayerPos(m_ID, s_Vector3.z, s_Vector3.y, z); } // ------------------------------------------------------------------------------------------------ SQInteger CPlayer::Msg(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); - + // Was the message color specified? if (top <= 1) + return sq_throwerror(vm, "Missing message color"); + // Was the message value specified? + else if (top <= 2) + return sq_throwerror(vm, "Missing message value"); + // The player instance + CPlayer * player = nullptr; + // The message color + Color3 color; + // Attempt to extract the argument values + try { - SqThrow("Missing the message color"); - return 0; + player = Var< CPlayer * >(vm, 1).value; + color = Var< Color3 >(vm, 2).value; } - else if (top == 2) + catch (const Sqrat::Exception & e) { - SqThrow("Missing the message value"); - return 0; - } - - Var< CPlayer & > inst(vm, 1); - Var< Color3 > color(vm, 2); - - if (!inst.value.IsActive()) - SqThrow("Invalid player reference: %d", inst.value.GetID()); - else if (top == 3 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) - { - CSStr msg = NULL; - - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the message"); - else - _Func->SendClientMessage(inst.value.GetID(), color.value.GetRGBA(), "%s", msg); - - sq_settop(vm, top); + // Propagate the error + return sq_throwerror(vm, e.Message().c_str()); } + // Do we have a valid player instance? + if (!player) + return sq_throwerror(vm, "Invalid player instance"); + // Do we have a valid player identifier? + else if (!player->IsActive()) + return sq_throwerror(vm, "Invalid player reference"); + // Do we have enough values to call the format function? else if (top > 3) { SStr msg = NULL; SQInteger len = 0; - - if (SQ_FAILED(sqstd_format(vm, 3, &len, &msg))) - SqThrow("Unable to generate the player message [%s]", Error::Message(vm).c_str()); - else - _Func->SendClientMessage(inst.value.GetID(), color.value.GetRGBA(), "%s", msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 3, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), color.GetRGBA(), "%s", msg); } else - SqThrow("Unable to extract the player message"); - + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 3); + // See if the obtained value is a valid message + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the message"); + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), color.GetRGBA(), "%s", msg.value); + } + // This function does not return a value return 0; } @@ -986,52 +1324,67 @@ SQInteger CPlayer::Msg(HSQUIRRELVM vm) SQInteger CPlayer::MsgP(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); - + // Was the index of the message prefix specified? if (top <= 1) + return sq_throwerror(vm, "Missing prefix index"); + // Was the message value specified? + else if (top <= 2) + return sq_throwerror(vm, "Missing message value"); + // The player instance + CPlayer * player = nullptr; + // The prefix index + Uint32 index; + // Attempt to extract the argument values + try { - SqThrow("Missing message prefix index"); - return 0; + player = Var< CPlayer * >(vm, 1).value; + index = Var< Uint32 >(vm, 2).value; } - else if (top == 2) + catch (const Sqrat::Exception & e) { - SqThrow("Missing the message value"); - return 0; - } - - Var< CPlayer & > inst(vm, 1); - Var< Uint32 > index(vm, 2); - - if (!inst.value.IsActive()) - SqThrow("Invalid player reference: %d", inst.value.GetID()); - else if (index.value > SQMOD_PLAYER_MSG_PREFIXES) - SqThrow("Prefix index is out of range: %u > %u", index.value, SQMOD_PLAYER_MSG_PREFIXES); - else if (top == 3 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) - { - CSStr msg = NULL; - const Int32 id = inst.value.GetID(); - - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the message"); - else - _Func->SendClientMessage(id, _Core->GetPlayer(id).mMessageColor, "%s%s", - _Core->GetPlayer(id).mPrefixes[index.value].c_str(), msg); - sq_settop(vm, top); + // Propagate the error + return sq_throwerror(vm, e.Message().c_str()); } + // Do we have a valid player instance? + if (!player) + return sq_throwerror(vm, "Invalid player instance"); + // Do we have a valid player identifier? + else if (!player->IsActive()) + return sq_throwerror(vm, "Invalid player reference"); + // Perform a range check on the specified prefix index + else if (index > SQMOD_PLAYER_MSG_PREFIXES) + return sq_throwerror(vm, ToStrF("Prefix index is out of range: %u > %u", + index, SQMOD_PLAYER_MSG_PREFIXES)); + // Do we have enough values to call the format function? else if (top > 3) { SStr msg = NULL; SQInteger len = 0; - const Int32 id = inst.value.GetID(); - - if (SQ_FAILED(sqstd_format(vm, 3, &len, &msg))) - SqThrow("Unable to generate the player message [%s]", Error::Message(vm).c_str()); - else - _Func->SendClientMessage(id, _Core->GetPlayer(id).mMessageColor, "%s%s", - _Core->GetPlayer(id).mPrefixes[index.value].c_str(), msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 3, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Retrieve the associated player structure + const auto & splayer = _Core->GetPlayer(player->GetID()); + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), splayer.mMessageColor, "%s%s", + splayer.mPrefixes[index].c_str(), msg); } else - SqThrow("Unable to extract the player message"); - + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 3); + // See if the obtained value is a valid message + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the message"); + // Retrieve the associated player structure + const auto & splayer = _Core->GetPlayer(player->GetID()); + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), splayer.mMessageColor, "%s%s", + splayer.mPrefixes[index].c_str(), msg.value); + } + // This function does not return a value return 0; } @@ -1039,52 +1392,59 @@ SQInteger CPlayer::MsgP(HSQUIRRELVM vm) SQInteger CPlayer::MsgEx(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); - - if (top <= 1) - { - SqThrow("Missing the message color"); - return 0; - } + // Was the message color specified? + if (top <= 3) + return sq_throwerror(vm, "Missing message color"); + // Was the message value specified? else if (top <= 4) + return sq_throwerror(vm, "Missing message value"); + // The player instance + CPlayer * player = nullptr; + // The message color + Uint8 r, g, b; + // Attempt to extract the argument values + try { - SqThrow("Missing the message value"); - return 0; + player = Var< CPlayer * >(vm, 1).value; + r = Var< Uint8 >(vm, 2).value; + g = Var< Uint8 >(vm, 3).value; + b = Var< Uint8 >(vm, 4).value; } - - Var< CPlayer & > inst(vm, 1); - - Var< Int32 > r(vm, 2); - Var< Int32 > g(vm, 3); - Var< Int32 > b(vm, 4); - - if (!inst.value.IsActive()) - SqThrow("Invalid player reference: %d", inst.value.GetID()); - else if (top == 5 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) + catch (const Sqrat::Exception & e) { - CSStr msg = NULL; - - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the message"); - else - _Func->SendClientMessage(inst.value.GetID(), - SQMOD_PACK_RGBA(r.value, g.value, b.value, 0), "%s", msg); - - sq_settop(vm, top); + // Propagate the error + return sq_throwerror(vm, e.Message().c_str()); } + // Do we have a valid player instance? + if (!player) + return sq_throwerror(vm, "Invalid player instance"); + // Do we have a valid player identifier? + else if (!player->IsActive()) + return sq_throwerror(vm, "Invalid player reference"); + // Do we have enough values to call the format function? else if (top > 5) { SStr msg = NULL; SQInteger len = 0; - - if (SQ_FAILED(sqstd_format(vm, 5, &len, &msg))) - SqThrow("Unable to generate the player message [%s]", Error::Message(vm).c_str()); - else - _Func->SendClientMessage(inst.value.GetID(), - SQMOD_PACK_RGBA(r.value, g.value, b.value, 0), "%s", msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 5, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), SQMOD_PACK_RGBA(r, g, b, 0), "%s", msg); } else - SqThrow("Unable to extract the player message"); - + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 5); + // See if the obtained value is a valid message + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the message"); + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), SQMOD_PACK_RGBA(r, g, b, 0), "%s", msg.value); + } + // This function does not return a value return 0; } @@ -1092,43 +1452,53 @@ SQInteger CPlayer::MsgEx(HSQUIRRELVM vm) SQInteger CPlayer::Message(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); - + // Was the message value specified? if (top <= 1) + return sq_throwerror(vm, "Missing message value"); + // The player instance + CPlayer * player = nullptr; + // Attempt to extract the argument values + try { - SqThrow("Missing the message value"); - return 0; + player = Var< CPlayer * >(vm, 1).value; } - - Var< CPlayer & > inst(vm, 1); - - if (!inst.value.IsActive()) - SqThrow("Invalid player reference: %d", inst.value.GetID()); - else if (top == 2 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) + catch (const Sqrat::Exception & e) { - CSStr msg = NULL; - const Int32 id = inst.value.GetID(); - - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the message"); - else - _Func->SendClientMessage(id, _Core->GetPlayer(id).mMessageColor, "%s", msg); - - sq_settop(vm, top); + // Propagate the error + return sq_throwerror(vm, e.Message().c_str()); } + // Do we have a valid player instance? + if (!player) + return sq_throwerror(vm, "Invalid player instance"); + // Do we have a valid player identifier? + else if (!player->IsActive()) + return sq_throwerror(vm, "Invalid player reference"); + // Do we have enough values to call the format function? else if (top > 2) { SStr msg = NULL; SQInteger len = 0; - const Int32 id = inst.value.GetID(); - - if (SQ_FAILED(sqstd_format(vm, 2, &len, &msg))) - SqThrow("Unable to generate the player message [%s]", Error::Message(vm).c_str()); - else - _Func->SendClientMessage(id, _Core->GetPlayer(id).mMessageColor, "%s", msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 2, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), + _Core->GetPlayer(player->GetID()).mMessageColor, "%s", msg); } else - SqThrow("Unable to extract the player message"); - + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 2); + // See if the obtained value is a valid message + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the message"); + // Send the resulted message string + _Func->SendClientMessage(player->GetID(), + _Core->GetPlayer(player->GetID()).mMessageColor, "%s", msg.value); + } + // This function does not return a value return 0; } @@ -1136,43 +1506,53 @@ SQInteger CPlayer::Message(HSQUIRRELVM vm) SQInteger CPlayer::Announce(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); - + // Was the announcement value specified? if (top <= 1) + return sq_throwerror(vm, "Missing announcement value"); + // The player instance + CPlayer * player = nullptr; + // Attempt to extract the argument values + try { - SqThrow("Missing the announcement value"); - return 0; + player = Var< CPlayer * >(vm, 1).value; } - - Var< CPlayer & > inst(vm, 1); - - if (!inst.value.IsActive()) - SqThrow("Invalid player reference: %d", inst.value.GetID()); - else if (top == 2 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) + catch (const Sqrat::Exception & e) { - CSStr msg = 0; - const Int32 id = inst.value.GetID(); - - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the announcement"); - else - _Func->SendGameMessage(id, _Core->GetPlayer(id).mAnnounceStyle, "%s", msg); - - sq_settop(vm, top); + // Propagate the error + return sq_throwerror(vm, e.Message().c_str()); } + // Do we have a valid player instance? + if (!player) + return sq_throwerror(vm, "Invalid player instance"); + // Do we have a valid player identifier? + else if (!player->IsActive()) + return sq_throwerror(vm, "Invalid player reference"); + // Do we have enough values to call the format function? else if (top > 2) { SStr msg = NULL; SQInteger len = 0; - const Int32 id = inst.value.GetID(); - - if (SQ_FAILED(sqstd_format(vm, 2, &len, &msg))) - SqThrow("Unable to generate the player announcement [%s]", Error::Message(vm).c_str()); - else - _Func->SendGameMessage(id, _Core->GetPlayer(id).mAnnounceStyle, "%s", msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 2, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Send the resulted announcement string + _Func->SendGameMessage(player->GetID(), + _Core->GetPlayer(player->GetID()).mAnnounceStyle, "%s", msg); } else - SqThrow("Unable to extract the player message"); - + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 2); + // See if the obtained value is a valid announcement + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the announcement"); + // Send the resulted announcement string + _Func->SendGameMessage(player->GetID(), + _Core->GetPlayer(player->GetID()).mAnnounceStyle, "%s", msg.value); + } + // This function does not return a value return 0; } @@ -1180,47 +1560,57 @@ SQInteger CPlayer::Announce(HSQUIRRELVM vm) SQInteger CPlayer::AnnounceEx(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); - + // Was the announcement style specified? if (top <= 1) + return sq_throwerror(vm, "Missing announcement style"); + // Was the announcement value specified? + else if (top <= 2) + return sq_throwerror(vm, "Missing announcement value"); + // The player instance + CPlayer * player = nullptr; + // The announcement style + Int32 style; + // style to extract the argument values + try { - SqThrow("Missing the announcement style"); - return 0; + player = Var< CPlayer * >(vm, 1).value; + style = Var< Int32 >(vm, 2).value; } - else if (top == 2) + catch (const Sqrat::Exception & e) { - SqThrow("Missing the announcement value"); - return 0; - } - - Var< CPlayer & > inst(vm, 1); - Var< SQInt32 > type(vm, 2); - - if (!inst.value.IsActive()) - SqThrow("Invalid player reference: %d", inst.value.GetID()); - else if (top == 3 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) - { - CSStr msg = 0; - - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the announcement"); - else - _Func->SendGameMessage(inst.value.GetID(), type.value, "%s", msg); - - sq_settop(vm, top); + // Propagate the error + return sq_throwerror(vm, e.Message().c_str()); } + // Do we have a valid player instance? + if (!player) + return sq_throwerror(vm, "Invalid player instance"); + // Do we have a valid player identifier? + else if (!player->IsActive()) + return sq_throwerror(vm, "Invalid player reference"); + // Do we have enough values to call the format function? else if (top > 3) { SStr msg = NULL; SQInteger len = 0; - - if (SQ_FAILED(sqstd_format(vm, 3, &len, &msg))) - SqThrow("Unable to generate the player announcement [%s]", Error::Message(vm).c_str()); - else - _Func->SendGameMessage(inst.value.GetID(), type.value, "%s", msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 3, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Send the resulted announcement string + _Func->SendGameMessage(player->GetID(), style, "%s", msg); } else - SqThrow("Unable to extract the player message"); - + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 3); + // See if the obtained value is a valid announcement + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the announcement"); + // Send the resulted announcement string + _Func->SendGameMessage(player->GetID(), style, "%s", msg.value); + } + // This function does not return a value return 0; } @@ -1229,20 +1619,21 @@ void Register_CPlayer(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqPlayer"), Class< CPlayer, NoConstructor< CPlayer > >(vm, _SC("SqPlayer")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CPlayer::Cmp) + .SquirrelFunc(_SC("_typename"), &CPlayer::Typename) .Func(_SC("_tostring"), &CPlayer::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CPlayer::Max) + // Core Properties .Prop(_SC("ID"), &CPlayer::GetID) .Prop(_SC("Tag"), &CPlayer::GetTag, &CPlayer::SetTag) .Prop(_SC("Data"), &CPlayer::GetData, &CPlayer::SetData) - .Prop(_SC("MaxID"), &CPlayer::GetMaxID) .Prop(_SC("Active"), &CPlayer::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CPlayer::BindEvent) - /* Properties */ - .Prop(_SC("Cls"), &CPlayer::GetClass) - .Prop(_SC("ClassID"), &CPlayer::GetClass) + // Properties + .Prop(_SC("Class"), &CPlayer::GetClass) .Prop(_SC("Admin"), &CPlayer::GetAdmin, &CPlayer::SetAdmin) .Prop(_SC("IP"), &CPlayer::GetIP) .Prop(_SC("Connected"), &CPlayer::IsConnected) @@ -1265,7 +1656,7 @@ void Register_CPlayer(HSQUIRRELVM vm) .Prop(_SC("UID"), &CPlayer::GetUID) .Prop(_SC("UID2"), &CPlayer::GetUID2) .Prop(_SC("Health"), &CPlayer::GetHealth, &CPlayer::SetHealth) - .Prop(_SC("Armur"), &CPlayer::GetArmor, &CPlayer::SetArmor) + .Prop(_SC("Armor"), &CPlayer::GetArmor, &CPlayer::SetArmor) .Prop(_SC("Immunity"), &CPlayer::GetImmunity, &CPlayer::SetImmunity) .Prop(_SC("Pos"), &CPlayer::GetPosition, &CPlayer::SetPosition) .Prop(_SC("Position"), &CPlayer::GetPosition, &CPlayer::SetPosition) @@ -1307,7 +1698,7 @@ void Register_CPlayer(HSQUIRRELVM vm) .Prop(_SC("X"), &CPlayer::GetPosX, &CPlayer::SetPosX) .Prop(_SC("Y"), &CPlayer::GetPosY, &CPlayer::SetPosY) .Prop(_SC("Z"), &CPlayer::GetPosZ, &CPlayer::SetPosZ) - /* Functions */ + // Functions .Func(_SC("StreamedFor"), &CPlayer::IsStreamedFor) .Func(_SC("Kick"), &CPlayer::Kick) .Func(_SC("Ban"), &CPlayer::Ban) @@ -1330,7 +1721,7 @@ void Register_CPlayer(HSQUIRRELVM vm) .Func(_SC("Redirect"), &CPlayer::Redirect) .Func(_SC("GetMsgPrefix"), &CPlayer::GetMessagePrefix) .Func(_SC("SetMsgPrefix"), &CPlayer::SetMessagePrefix) - /* Raw Functions */ + // Raw Functions .SquirrelFunc(_SC("Msg"), &CPlayer::Msg) .SquirrelFunc(_SC("MsgP"), &CPlayer::MsgP) .SquirrelFunc(_SC("MsgEx"), &CPlayer::MsgEx) @@ -1339,7 +1730,7 @@ void Register_CPlayer(HSQUIRRELVM vm) .SquirrelFunc(_SC("AnnounceEx"), &CPlayer::AnnounceEx) .SquirrelFunc(_SC("Text"), &CPlayer::Announce) .SquirrelFunc(_SC("TextEx"), &CPlayer::AnnounceEx) - /* Overloads */ + // Overloads .Overload< void (CPlayer::*)(const Vector3 &) const > (_SC("AddSpeed"), &CPlayer::AddSpeed) .Overload< void (CPlayer::*)(Float32, Float32, Float32) const > diff --git a/source/Entity/Player.hpp b/source/Entity/Player.hpp index 01aee66a..b786e459 100644 --- a/source/Entity/Player.hpp +++ b/source/Entity/Player.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Player instances. + * Manages a single player entity. */ class CPlayer { @@ -24,20 +24,19 @@ private: // -------------------------------------------------------------------------------------------- static SQChar s_Buffer[SQMOD_PLAYER_TMP_BUFFER]; - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_PLAYER_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -45,35 +44,45 @@ private: */ CPlayer(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CPlayer(const CPlayer &); + CPlayer(const CPlayer &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CPlayer & operator = (const CPlayer &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CPlayer(CPlayer &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~CPlayer(); + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + CPlayer & operator = (const CPlayer &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CPlayer & operator = (CPlayer &&) = delete; + /* -------------------------------------------------------------------------------------------- * See whether this instance manages a valid entity. */ - bool Validate() const + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid player reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid player reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -84,27 +93,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_PLAYER_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -121,141 +136,639 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * See if the managed player entity is streamed for the specified player. + */ bool IsStreamedFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the class of the managed player entity. + */ Int32 GetClass() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has administrator privileges. + */ bool GetAdmin() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has administrator privileges. + */ void SetAdmin(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the ip address of the managed player entity. + */ CSStr GetIP() const; + + /* -------------------------------------------------------------------------------------------- + * Kick the managed player entity from the server. + */ void Kick() const; + + /* -------------------------------------------------------------------------------------------- + * Ban the managed player entity from the server. + */ void Ban() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is connected. + */ bool IsConnected() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is spawned. + */ bool IsSpawned() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the key of the managed player entity. + */ Uint32 GetKey() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the managed player entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the world in which the managed player entity exists. + */ void SetWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the secondary world of the managed player entity. + */ Int32 GetSecWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the secondary world of the managed player entity. + */ void SetSecWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the unique world of the managed player entity. + */ Int32 GetUniqueWorld() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is compatible with the specified world. + */ bool IsWorldCompatible(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the nick name of the managed player entity. + */ CSStr GetName() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the nick name of the managed player entity. + */ void SetName(CSStr name) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the team of the managed player entity. + */ Int32 GetTeam() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the team of the managed player entity. + */ void SetTeam(Int32 team) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the skin identifier of the managed player entity. + */ Int32 GetSkin() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the skin identifier of the managed player entity. + */ void SetSkin(Int32 skin) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the color of the managed player entity. + */ const Color3 & GetColor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the color of the managed player entity. + */ void SetColor(const Color3 & color) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the color of the managed player entity. + */ void SetColorEx(Uint8 r, Uint8 g, Uint8 b) const; + + /* -------------------------------------------------------------------------------------------- + * Force the managed player entity to spawn in the game. + */ void ForceSpawn() const; + + /* -------------------------------------------------------------------------------------------- + * Force the managed player entity to select a class. + */ void ForceSelect() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the money amount of the managed player entity. + */ Int32 GetMoney() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the money amount of the managed player entity. + */ void SetMoney(Int32 amount) const; + + /* -------------------------------------------------------------------------------------------- + * Give a certain amount of money to the managed player entity. + */ void GiveMoney(Int32 amount) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the score of the managed player entity. + */ Int32 GetScore() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the score of the managed player entity. + */ void SetScore(Int32 score) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the connection latency of the managed player entity. + */ Int32 GetPing() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the frames per second of the managed player entity. + */ Float32 GetFPS() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is typing. + */ bool IsTyping() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the unique user identifier of the managed player entity. + */ CSStr GetUID() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the unique user identifier version 2 of the managed player entity. + */ CSStr GetUID2() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the current health of the managed player entity. + */ Float32 GetHealth() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the health of the managed player entity. + */ void SetHealth(Float32 amount) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the current health of the managed player entity. + */ Float32 GetArmor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the health of the managed player entity. + */ void SetArmor(Float32 amount) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the immunity flags of the managed player entity. + */ Int32 GetImmunity() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the immunity flags of the managed player entity. + */ void SetImmunity(Int32 flags) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed player entity. + */ const Vector3 & GetPosition() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed player entity. + */ void SetPosition(const Vector3 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed player entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the speed of the managed player entity. + */ const Vector3 & GetSpeed() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed player entity. + */ void SetSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed player entity. + */ void SetSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed player entity. + */ void AddSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed player entity. + */ void AddSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the heading angle of the managed player entity. + */ Float32 GetHeading() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the heading angle of the managed player entity. + */ void SetHeading(Float32 angle) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the alpha of the managed player entity. + */ Int32 GetAlpha() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the alpha of the managed player entity. + */ void SetAlpha(Int32 alpha, Int32 fade) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the vehicle status of the managed player entity. + */ Int32 GetVehicleStatus() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the occupied vehicle slot by the managed player entity. + */ Int32 GetOccupiedSlot() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the vehicle in which the managed player entity is embarked. + */ Object & GetVehicle() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the vehicle identifier in which the managed player entity is embarked. + */ Int32 GetVehicleID() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity can be controlled. + */ bool GetControllable() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity can be controlled. + */ void SetControllable(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity can driveby. + */ bool GetDriveby() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity can driveby. + */ void SetDriveby(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has white scanlines. + */ bool GetWhiteScanlines() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has white scanlines. + */ void SetWhiteScanlines(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has green scanlines. + */ bool GetGreenScanlines() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has green scanlines. + */ void SetGreenScanlines(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has widescreen. + */ bool GetWidescreen() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has widescreen. + */ void SetWidescreen(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity displays markers. + */ bool GetShowMarkers() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity displays markers. + */ void SetShowMarkers(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has attacking privileges. + */ bool GetAttackPriv() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has attacking privileges. + */ void SetAttackPriv(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has markers. + */ bool GetHasMarker() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has markers. + */ void SetHasMarker(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has chat tags. + */ bool GetChatTags() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity has chat tags. + */ void SetChatTags(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is under drunk effects. + */ bool GetDrunkEffects() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed player entity is under drunk effects. + */ void SetDrunkEffects(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the weapon identifier of the managed player entity. + */ Int32 GetWeapon() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the weapon of the managed player entity. + */ void SetWeapon(Int32 wep, Int32 ammo) const; + + /* -------------------------------------------------------------------------------------------- + * Give a weapon of the managed player entity. + */ void GiveWeapon(Int32 wep, Int32 ammo) const; + + /* -------------------------------------------------------------------------------------------- + * Strip the managed player entity of all weapons. + */ void StripWeapons() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the camera position of the managed player entity. + */ void SetCameraPosition(const Vector3 & pos, const Vector3 & aim) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the camera position of the managed player entity. + */ void SetCameraPosition(Float32 xp, Float32 yp, Float32 zp, Float32 xa, Float32 ya, Float32 za) const; + + /* -------------------------------------------------------------------------------------------- + * Restore the camera position of the managed player entity. + */ void RestoreCamera() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity has camera locked. + */ bool IsCameraLocked() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the animation of the managed player entity. + */ void SetAnimation(Int32 group, Int32 anim) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the wanted level of the managed player entity. + */ Int32 GetWantedLevel() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the wanted level of the managed player entity. + */ void SetWantedLevel(Int32 level) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the vehicle that the managed player entity is standing on. + */ Object & StandingOnVehicle() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the object that the managed player entity is standing on. + */ Object & StandingOnObject() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is away. + */ bool IsAway() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the player that the managed player entity is spectating. + */ Object & GetSpectator() const; + + /* -------------------------------------------------------------------------------------------- + * Set the managed player entity to spectate the specified player entity. + */ void SetSpectator(CPlayer & target) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is burning. + */ bool IsBurning() const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed player entity is crouched. + */ bool IsCrouched() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the current state of the managed player entity. + */ Int32 GetState() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the current action of the managed player entity. + */ Int32 GetAction() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the game keys of the managed player entity. + */ Int32 GetGameKeys() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the aim position of the managed player entity. + */ const Vector3 & GetAimPos() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the aim direction of the managed player entity. + */ const Vector3 & GetAimDir() const; + + /* -------------------------------------------------------------------------------------------- + * Embark the managed player entity into the specified vehicle entity. + */ void Embark(CVehicle & vehicle) const; + + /* -------------------------------------------------------------------------------------------- + * Embark the managed player entity into the specified vehicle entity. + */ void Embark(CVehicle & vehicle, Int32 slot, bool allocate, bool warp) const; + + /* -------------------------------------------------------------------------------------------- + * Disembark the managed player entity from the currently embarked vehicle entity. + */ void Disembark() const; + + /* -------------------------------------------------------------------------------------------- + * Redirect the managed player entity to the specified server. + */ bool Redirect(CSStr ip, Uint32 port, CSStr nick, CSStr pass, CSStr user); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the authority level of the managed player entity. + */ Int32 GetAuthority() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the authority level of the managed player entity. + */ void SetAuthority(Int32 level) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the message prefix at the specified index for the managed player entity. + */ CSStr GetMessagePrefix(Uint32 index) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the message prefix at the specified index for the managed player entity. + */ void SetMessagePrefix(Uint32 index, CSStr prefix) const; + /* -------------------------------------------------------------------------------------------- + * Retrieve the message color for the managed player entity. + */ Uint32 GetMessageColor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the message color for the managed player entity. + */ void SetMessageColor(Uint32 color) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the announcement style for the managed player entity. + */ Int32 GetAnnounceStyle() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the announcement style for the managed player entity. + */ void SetAnnounceStyle(Int32 style) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed player entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed player entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed player entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the x axis of the managed player entity. + */ void SetPosX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the y axis of the managed player entity. + */ void SetPosY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the z axis of the managed player entity. + */ void SetPosZ(Float32 z) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Send a formatted colored message to the managed player entity. + */ static SQInteger Msg(HSQUIRRELVM vm); - static SQInteger MsgP(HSQUIRRELVM vm); - static SQInteger MsgEx(HSQUIRRELVM vm); - static SQInteger Message(HSQUIRRELVM vm); - static SQInteger Announce(HSQUIRRELVM vm); - static SQInteger AnnounceEx(HSQUIRRELVM vm); + /* -------------------------------------------------------------------------------------------- + * Send a formatted message with a prefix to the managed player entity. + */ + static SQInteger MsgP(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Send a formatted colored message to the managed player entity. + */ + static SQInteger MsgEx(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Send a formatted message to the managed player entity. + */ + static SQInteger Message(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Send a formatted announcement message to the managed player entity. + */ + static SQInteger Announce(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Send a formatted announcement message to the managed player entity. + */ + static SQInteger AnnounceEx(HSQUIRRELVM vm); }; } // Namespace:: SqMod diff --git a/source/Entity/Sprite.cpp b/source/Entity/Sprite.cpp index 8aaa5f32..1b734610 100644 --- a/source/Entity/Sprite.cpp +++ b/source/Entity/Sprite.cpp @@ -8,15 +8,20 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ -SQChar CSprite::s_StrID[SQMOD_SPRITE_POOL][8]; +const Int32 CSprite::Max = SQMOD_SPRITE_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CSprite::Max = SQMOD_SPRITE_POOL; +SQInteger CSprite::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqSprite"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CSprite::CSprite(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_SPRITE_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -38,301 +43,407 @@ Int32 CSprite::Cmp(const CSprite & o) const return -1; } -CSStr CSprite::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CSprite::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_SPRITE_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CSprite::GetTag() const +const String & CSprite::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CSprite::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CSprite::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CSprite::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CSprite::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelSprite(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CSprite::BindEvent(Int32 evid, Object & env, Function & func) const +void CSprite::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetSpriteEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ void CSprite::ShowAll() const { - if (Validate()) - _Func->ShowSprite(m_ID, -1); -} - -void CSprite::ShowFor(CPlayer & player) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->ShowSprite(m_ID, player.GetID()); - -} - -void CSprite::ShowRange(Int32 first, Int32 last) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->ShowSprite(m_ID, first); - } -} - -void CSprite::HideAll() const -{ - if (Validate()) - _Func->HideSprite(m_ID, -1); -} - -void CSprite::HideFor(CPlayer & player) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->HideSprite(m_ID, player.GetID()); -} - -void CSprite::HideRange(Int32 first, Int32 last) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->HideSprite(m_ID, first); - } -} - -void CSprite::SetPositionAll(const Vector2i & pos) const -{ - if (Validate()) - _Func->MoveSprite(m_ID, -1, pos.x, pos.y); -} - -void CSprite::SetPositionAllEx(Int32 x, Int32 y) const -{ - if (Validate()) - _Func->MoveSprite(m_ID, -1, x, y); -} - -void CSprite::SetPositionFor(CPlayer & player, const Vector2i & pos) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->MoveSprite(m_ID, player.GetID(), pos.x, pos.y); -} - -void CSprite::SetPositionForEx(CPlayer & player, Int32 x, Int32 y) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->MoveSprite(m_ID, player.GetID(), x, y); -} - -void CSprite::SetPositionRange(Int32 first, Int32 last, const Vector2i & pos) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->MoveSprite(m_ID, first, pos.x, pos.y); - } -} - -void CSprite::SetCenterAll(const Vector2i & pos) const -{ - if (Validate()) - _Func->SetSpriteCenter(m_ID, -1, pos.x, pos.y); -} - -void CSprite::SetCenterAllEx(Int32 x, Int32 y) const -{ - if (Validate()) - _Func->SetSpriteCenter(m_ID, -1, x, y); -} - -void CSprite::SetCenterFor(CPlayer & player, const Vector2i & pos) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->SetSpriteCenter(m_ID, player.GetID(), pos.x, pos.y); -} - -void CSprite::SetCenterForEx(CPlayer & player, Int32 x, Int32 y) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->SetSpriteCenter(m_ID, player.GetID(), x, y); -} - -void CSprite::SetCenterRange(Int32 first, Int32 last, const Vector2i & pos) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->SetSpriteCenter(m_ID, first, pos.x, pos.y); - } -} - -void CSprite::SetRotationAll(Float32 rot) const -{ - if (Validate()) - _Func->RotateSprite(m_ID, -1, rot); -} - -void CSprite::SetRotationFor(CPlayer & player, Float32 rot) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->RotateSprite(m_ID, player.GetID(), rot); -} - -void CSprite::SetRotationRange(Int32 first, Int32 last, Float32 rot) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->RotateSprite(m_ID, first, rot); - } -} - -void CSprite::SetAlphaAll(Uint8 alpha) const -{ - if (Validate()) - _Func->SetSpriteAlpha(m_ID, -1, alpha); -} - -void CSprite::SetAlphaFor(CPlayer & player, Uint8 alpha) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->SetSpriteAlpha(m_ID, player.GetID(), alpha); -} - -void CSprite::SetAlphaRange(Int32 first, Int32 last, Uint8 alpha) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->SetSpriteAlpha(m_ID, first, alpha); - } -} - -CSStr CSprite::GetFilePath() const -{ - if (Validate()) - _Core->GetSprite(m_ID).mPath.c_str(); - return g_EmptyStr; + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ShowSprite(m_ID, -1); } // ------------------------------------------------------------------------------------------------ -static Object & CreateSpriteEx(CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, +void CSprite::ShowFor(CPlayer & player) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ShowSprite(m_ID, player.GetID()); + +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::ShowRange(Int32 first, Int32 last) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then show this textdraw on his client + _Func->ShowSprite(m_ID, first); + } +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::HideAll() const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->HideSprite(m_ID, -1); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::HideFor(CPlayer & player) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->HideSprite(m_ID, player.GetID()); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::HideRange(Int32 first, Int32 last) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then hide this textdraw on his client + _Func->HideSprite(m_ID, first); + } +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetPositionAll(const Vector2i & pos) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveSprite(m_ID, -1, pos.x, pos.y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetPositionAllEx(Int32 x, Int32 y) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveSprite(m_ID, -1, x, y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetPositionFor(CPlayer & player, const Vector2i & pos) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveSprite(m_ID, player.GetID(), pos.x, pos.y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetPositionForEx(CPlayer & player, Int32 x, Int32 y) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveSprite(m_ID, player.GetID(), x, y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetPositionRange(Int32 first, Int32 last, const Vector2i & pos) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then move this textdraw on his client + _Func->MoveSprite(m_ID, first, pos.x, pos.y); + } +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetCenterAll(const Vector2i & pos) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpriteCenter(m_ID, -1, pos.x, pos.y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetCenterAllEx(Int32 x, Int32 y) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpriteCenter(m_ID, -1, x, y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetCenterFor(CPlayer & player, const Vector2i & pos) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpriteCenter(m_ID, player.GetID(), pos.x, pos.y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetCenterForEx(CPlayer & player, Int32 x, Int32 y) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpriteCenter(m_ID, player.GetID(), x, y); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetCenterRange(Int32 first, Int32 last, const Vector2i & pos) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then center this textdraw on his client + _Func->SetSpriteCenter(m_ID, first, pos.x, pos.y); + } +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetRotationAll(Float32 rot) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotateSprite(m_ID, -1, rot); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetRotationFor(CPlayer & player, Float32 rot) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RotateSprite(m_ID, player.GetID(), rot); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetRotationRange(Int32 first, Int32 last, Float32 rot) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then rotate this textdraw on his client + _Func->RotateSprite(m_ID, first, rot); + } +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetAlphaAll(Uint8 alpha) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpriteAlpha(m_ID, -1, alpha); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetAlphaFor(CPlayer & player, Uint8 alpha) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetSpriteAlpha(m_ID, player.GetID(), alpha); +} + +// ------------------------------------------------------------------------------------------------ +void CSprite::SetAlphaRange(Int32 first, Int32 last, Uint8 alpha) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then colorize this textdraw on his client + _Func->SetSpriteAlpha(m_ID, first, alpha); + } +} + +// ------------------------------------------------------------------------------------------------ +const String & CSprite::GetFilePath() const +{ + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetSprite(m_ID).mPath; +} + +// ------------------------------------------------------------------------------------------------ +static Object & Sprite_CreateEx(CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, Float32 angle, Int32 alpha, bool rel) { return _Core->NewSprite(-1, file, xp, yp, xr, yr, angle, alpha, rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateSpriteEx(CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, +// ------------------------------------------------------------------------------------------------ +static Object & Sprite_CreateEx(CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, Float32 angle, Int32 alpha, bool rel, Int32 header, Object & payload) { return _Core->NewSprite(-1, file, xp, yp, xr, yr, angle, alpha, rel, header, payload); } // ------------------------------------------------------------------------------------------------ -static Object & CreateSpriteEx(Int32 index, CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, +static Object & Sprite_CreateEx(Int32 index, CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, Float32 angle, Int32 alpha, bool rel) { return _Core->NewSprite(index, file, xp, yp, xr, yr, angle, alpha, rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateSpriteEx(Int32 index, CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, +// ------------------------------------------------------------------------------------------------ +static Object & Sprite_CreateEx(Int32 index, CSStr file, Int32 xp, Int32 yp, Int32 xr, Int32 yr, Float32 angle, Int32 alpha, bool rel, Int32 header, Object & payload) { return _Core->NewSprite(index, file, xp, yp, xr, yr, angle, alpha, rel, header, payload); } // ------------------------------------------------------------------------------------------------ -static Object & CreateSprite(CSStr file, const Vector2i & pos, const Vector2i & rot, +static Object & Sprite_Create(CSStr file, const Vector2i & pos, const Vector2i & rot, Float32 angle, Int32 alpha, bool rel) { return _Core->NewSprite(-1, file, pos.x, pos.y, rot.x, rot.y, angle, alpha, rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateSprite(CSStr file, const Vector2i & pos, const Vector2i & rot, +// ------------------------------------------------------------------------------------------------ +static Object & Sprite_Create(CSStr file, const Vector2i & pos, const Vector2i & rot, Float32 angle, Int32 alpha, bool rel, Int32 header, Object & payload) { return _Core->NewSprite(-1, file, pos.x, pos.y, rot.x, rot.y, angle, alpha, rel, header, payload); } // ------------------------------------------------------------------------------------------------ -static Object & CreateSprite(Int32 index, CSStr file, const Vector2i & pos, const Vector2i & rot, +static Object & Sprite_Create(Int32 index, CSStr file, const Vector2i & pos, const Vector2i & rot, Float32 angle, Int32 alpha, bool rel) { return _Core->NewSprite(index, file, pos.x, pos.y, rot.x, rot.y, angle, alpha, rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateSprite(Int32 index, CSStr file, const Vector2i & pos, const Vector2i & rot, +// ------------------------------------------------------------------------------------------------ +static Object & Sprite_Create(Int32 index, CSStr file, const Vector2i & pos, const Vector2i & rot, Float32 angle, Int32 alpha, bool rel, Int32 header, Object & payload) { return _Core->NewSprite(index, file, pos.x, pos.y, rot.x, rot.y, angle, alpha, rel, header, payload); @@ -343,24 +454,26 @@ void Register_CSprite(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqSprite"), Class< CSprite, NoConstructor< CSprite > >(vm, _SC("SqSprite")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CSprite::Cmp) + .SquirrelFunc(_SC("_typename"), &CSprite::Typename) .Func(_SC("_tostring"), &CSprite::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CSprite::Max) + // Core Properties .Prop(_SC("ID"), &CSprite::GetID) .Prop(_SC("Tag"), &CSprite::GetTag, &CSprite::SetTag) .Prop(_SC("Data"), &CSprite::GetData, &CSprite::SetData) - .Prop(_SC("MaxID"), &CSprite::GetMaxID) .Prop(_SC("Active"), &CSprite::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CSprite::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CSprite::*)(void) >(_SC("Destroy"), &CSprite::Destroy) .Overload< bool (CSprite::*)(Int32) >(_SC("Destroy"), &CSprite::Destroy) .Overload< bool (CSprite::*)(Int32, Object &) >(_SC("Destroy"), &CSprite::Destroy) - /* Properties */ + // Properties .Prop(_SC("Path"), &CSprite::GetFilePath) - /* Functions */ + // Functions .Func(_SC("ShowAll"), &CSprite::ShowAll) .Func(_SC("ShowTo"), &CSprite::ShowFor) .Func(_SC("ShowFor"), &CSprite::ShowFor) @@ -377,7 +490,7 @@ void Register_CSprite(HSQUIRRELVM vm) .Func(_SC("SetAlphaAll"), &CSprite::SetAlphaAll) .Func(_SC("SetAlphaFor"), &CSprite::SetAlphaFor) .Func(_SC("SetAlphaRange"), &CSprite::SetAlphaRange) - /* Overloads */ + // Overloads .Overload< void (CSprite::*)(const Vector2i &) const > (_SC("SetPositionAll"), &CSprite::SetPositionAll) .Overload< void (CSprite::*)(Int32, Int32) const > @@ -394,25 +507,24 @@ void Register_CSprite(HSQUIRRELVM vm) (_SC("SetCenterFor"), &CSprite::SetCenterFor) .Overload< void (CSprite::*)(CPlayer &, Int32, Int32) const > (_SC("SetCenterFor"), &CSprite::SetCenterForEx) + // Static Overloads + .StaticOverload< Object & (*)(CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel) > + (_SC("CreateEx"), &Sprite_CreateEx) + .StaticOverload< Object & (*)(CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel, Int32, Object &) > + (_SC("CreateEx"), &Sprite_CreateEx) + .StaticOverload< Object & (*)(Int32, CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel) > + (_SC("CreateEx"), &Sprite_CreateEx) + .StaticOverload< Object & (*)(Int32, CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel, Int32, Object &) > + (_SC("CreateEx"), &Sprite_CreateEx) + .StaticOverload< Object & (*)(CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool) > + (_SC("Create"), &Sprite_Create) + .StaticOverload< Object & (*)(CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool, Int32, Object &) > + (_SC("Create"), &Sprite_Create) + .StaticOverload< Object & (*)(Int32, CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool) > + (_SC("Create"), &Sprite_Create) + .StaticOverload< Object & (*)(Int32, CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool, Int32, Object &) > + (_SC("Create"), &Sprite_Create) ); - - RootTable(vm) - .Overload< Object & (*)(CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel) > - (_SC("CreateSpriteEx"), &CreateSpriteEx) - .Overload< Object & (*)(CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel, Int32, Object &) > - (_SC("CreateSpriteEx"), &CreateSpriteEx) - .Overload< Object & (*)(Int32, CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel) > - (_SC("CreateSpriteEx"), &CreateSpriteEx) - .Overload< Object & (*)(Int32, CSStr, Int32, Int32, Int32, Int32, Float32, Int32, bool rel, Int32, Object &) > - (_SC("CreateSpriteEx"), &CreateSpriteEx) - .Overload< Object & (*)(CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool) > - (_SC("CreateSprite"), &CreateSprite) - .Overload< Object & (*)(CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool, Int32, Object &) > - (_SC("CreateSprite"), &CreateSprite) - .Overload< Object & (*)(Int32, CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool) > - (_SC("CreateSprite"), &CreateSprite) - .Overload< Object & (*)(Int32, CSStr, const Vector2i &, const Vector2i &, Float32, Int32, bool, Int32, Object &) > - (_SC("CreateSprite"), &CreateSprite); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Sprite.hpp b/source/Entity/Sprite.hpp index 0ec16f3b..5b6394d7 100644 --- a/source/Entity/Sprite.hpp +++ b/source/Entity/Sprite.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Sprite instances. + * Manages a single sprite entity. */ class CSprite { @@ -17,20 +17,19 @@ class CSprite private: - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_SPRITE_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -38,35 +37,45 @@ private: */ CSprite(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CSprite(const CSprite &); + CSprite(const CSprite &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CSprite & operator = (const CSprite &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CSprite(CSprite &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~CSprite(); + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + CSprite & operator = (const CSprite &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CSprite & operator = (CSprite &&) = delete; + /* -------------------------------------------------------------------------------------------- * See whether this instance manages a valid entity. */ - bool Validate() const + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid sprite reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid sprite reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -77,27 +86,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_SPRITE_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -114,38 +129,146 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed sprite entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed sprite entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed sprite entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Show the managed sprite entity to all players on the server. + */ void ShowAll() const; + + /* -------------------------------------------------------------------------------------------- + * Show the managed sprite entity to the specified player entity. + */ void ShowFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Show the managed sprite entity to all players in the specified range. + */ void ShowRange(Int32 first, Int32 last) const; + + /* -------------------------------------------------------------------------------------------- + * Hide the managed sprite entity from all players on the server. + */ void HideAll() const; + + /* -------------------------------------------------------------------------------------------- + * Hide the managed sprite entity from the specified player entity. + */ void HideFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Hide the managed sprite entity from all players in the specified range. + */ void HideRange(Int32 first, Int32 last) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed sprite entity for all players on the server. + */ void SetPositionAll(const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed sprite entity for all players on the server. + */ void SetPositionAllEx(Int32 x, Int32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed sprite entity for the specified player entity. + */ void SetPositionFor(CPlayer & player, const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed sprite entity for the specified player entity. + */ void SetPositionForEx(CPlayer & player, Int32 x, Int32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed sprite entity for all players in the specified range. + */ void SetPositionRange(Int32 first, Int32 last, const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the center of the managed sprite entity for all players on the server. + */ void SetCenterAll(const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the center of the managed sprite entity for all players on the server. + */ void SetCenterAllEx(Int32 x, Int32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Set the center of the managed sprite entity for the specified player entity. + */ void SetCenterFor(CPlayer & player, const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the center of the managed sprite entity for the specified player entity. + */ void SetCenterForEx(CPlayer & player, Int32 x, Int32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Set the center of the managed sprite entity for all players in the specified range. + */ void SetCenterRange(Int32 first, Int32 last, const Vector2i & pos) const; - void SetRotationAll(SQFloat rot) const; - void SetRotationFor(CPlayer & player, SQFloat rot) const; - void SetRotationRange(Int32 first, Int32 last, SQFloat rot) const; + + /* -------------------------------------------------------------------------------------------- + * Set the rotation of the managed sprite entity for all players on the server. + */ + void SetRotationAll(Float32 rot) const; + + /* -------------------------------------------------------------------------------------------- + * Set the rotation of the managed sprite entity for the specified player entity. + */ + void SetRotationFor(CPlayer & player, Float32 rot) const; + + /* -------------------------------------------------------------------------------------------- + * Set the rotation of the managed sprite entity for all players in the specified range. + */ + void SetRotationRange(Int32 first, Int32 last, Float32 rot) const; + + /* -------------------------------------------------------------------------------------------- + * Set the alpha of the managed sprite entity for all players on the server. + */ void SetAlphaAll(Uint8 alpha) const; + + /* -------------------------------------------------------------------------------------------- + * Set the alpha of the managed sprite entity for the specified player entity. + */ void SetAlphaFor(CPlayer & player, Uint8 alpha) const; + + /* -------------------------------------------------------------------------------------------- + * Set the alpha of the managed sprite entity for all players in the specified range. + */ void SetAlphaRange(Int32 first, Int32 last, Uint8 alpha) const; - CSStr GetFilePath() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the file path of the texture used by the managed sprite entity. + */ + const String & GetFilePath() const; }; } // Namespace:: SqMod diff --git a/source/Entity/Textdraw.cpp b/source/Entity/Textdraw.cpp index eef34946..ed6500b2 100644 --- a/source/Entity/Textdraw.cpp +++ b/source/Entity/Textdraw.cpp @@ -8,15 +8,20 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ -SQChar CTextdraw::s_StrID[SQMOD_TEXTDRAW_POOL][8]; +const Int32 CTextdraw::Max = SQMOD_TEXTDRAW_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CTextdraw::Max = SQMOD_TEXTDRAW_POOL; +SQInteger CTextdraw::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqTextdraw"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CTextdraw::CTextdraw(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_TEXTDRAW_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -38,206 +43,283 @@ Int32 CTextdraw::Cmp(const CTextdraw & o) const return -1; } -CSStr CTextdraw::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CTextdraw::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_TEXTDRAW_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CTextdraw::GetTag() const +const String & CTextdraw::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CTextdraw::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CTextdraw::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CTextdraw::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CTextdraw::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelTextdraw(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CTextdraw::BindEvent(Int32 evid, Object & env, Function & func) const +void CTextdraw::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetTextdrawEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ void CTextdraw::ShowAll() const { - if (Validate()) - _Func->ShowTextdraw(m_ID, -1); -} - -void CTextdraw::ShowFor(CPlayer & player) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->ShowTextdraw(m_ID, player.GetID()); -} - -void CTextdraw::ShowRange(Int32 first, Int32 last) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->ShowTextdraw(m_ID, first); - } -} - -void CTextdraw::HideAll() const -{ - if (Validate()) - _Func->HideTextdraw(m_ID, -1); -} - -void CTextdraw::HideFor(CPlayer & player) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->HideTextdraw(m_ID, player.GetID()); -} - -void CTextdraw::HideRange(Int32 first, Int32 last) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->HideTextdraw(m_ID, first); - } -} - -void CTextdraw::SetPositionAll(const Vector2i & pos) const -{ - if (Validate()) - _Func->MoveTextdraw(m_ID, -1, pos.x, pos.y); -} - -void CTextdraw::SetPositionAllEx(Int32 x, Int32 y) const -{ - if (Validate()) - _Func->MoveTextdraw(m_ID, -1, x, y); -} - -void CTextdraw::SetPositionFor(CPlayer & player, const Vector2i & pos) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->MoveTextdraw(m_ID, player.GetID(), pos.x, pos.y); -} - -void CTextdraw::SetPositionForEx(CPlayer & player, Int32 x, Int32 y) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->MoveTextdraw(m_ID, player.GetID(), x, y); -} - -void CTextdraw::SetPositionRange(Int32 first, Int32 last, const Vector2i & pos) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (; first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->MoveTextdraw(m_ID, first, pos.x, pos.y); - } -} - -void CTextdraw::SetColorAll(const Color4 & col) const -{ - if (Validate()) - _Func->SetTextdrawColour(m_ID, -1, col.GetRGBA()); -} - -void CTextdraw::SetColorAllEx(Uint8 r, Uint8 g, Uint8 b, Uint8 a) const -{ - if (Validate()) - _Func->SetTextdrawColour(m_ID, -1, SQMOD_PACK_RGBA(r, g, b, a)); -} - -void CTextdraw::SetColorFor(CPlayer & player, const Color4 & col) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->SetTextdrawColour(m_ID, player.GetID(), col.GetRGBA()); -} - -void CTextdraw::SetColorForEx(CPlayer & player, Uint8 r, Uint8 g, Uint8 b, Uint8 a) const -{ - if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->SetTextdrawColour(m_ID, player.GetID(), SQMOD_PACK_RGBA(r, g, b, a)); -} - -void CTextdraw::SetColorRange(Int32 first, Int32 last, const Color4 & col) const -{ - if (first > last) - SqThrow("Invalid player range: %d > %d", first, last); - else if (Validate()) - for (const Uint32 color = col.GetRGBA(); first <= last; ++first) - { - if (_Func->IsPlayerConnected(first)) - _Func->SetTextdrawColour(m_ID, first, color); - } -} - -CSStr CTextdraw::GetText() const -{ - if (Validate()) - _Core->GetTextdraw(m_ID).mText.c_str(); - return g_EmptyStr; + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ShowTextdraw(m_ID, -1); } // ------------------------------------------------------------------------------------------------ -static Object & CreateTextdrawEx(CSStr text, Int32 xp, Int32 yp, +void CTextdraw::ShowFor(CPlayer & player) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ShowTextdraw(m_ID, player.GetID()); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::ShowRange(Int32 first, Int32 last) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then show this textdraw on his client + _Func->ShowTextdraw(m_ID, first); + } +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::HideAll() const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->HideTextdraw(m_ID, -1); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::HideFor(CPlayer & player) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->HideTextdraw(m_ID, player.GetID()); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::HideRange(Int32 first, Int32 last) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then hide this textdraw on his client + _Func->HideTextdraw(m_ID, first); + } +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetPositionAll(const Vector2i & pos) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveTextdraw(m_ID, -1, pos.x, pos.y); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetPositionAllEx(Int32 x, Int32 y) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveTextdraw(m_ID, -1, x, y); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetPositionFor(CPlayer & player, const Vector2i & pos) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveTextdraw(m_ID, player.GetID(), pos.x, pos.y); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetPositionForEx(CPlayer & player, Int32 x, Int32 y) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->MoveTextdraw(m_ID, player.GetID(), x, y); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetPositionRange(Int32 first, Int32 last, const Vector2i & pos) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (; first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then move this textdraw on his client + _Func->MoveTextdraw(m_ID, first, pos.x, pos.y); + } +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetColorAll(const Color4 & col) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetTextdrawColour(m_ID, -1, col.GetRGBA()); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetColorAllEx(Uint8 r, Uint8 g, Uint8 b, Uint8 a) const +{ + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetTextdrawColour(m_ID, -1, SQMOD_PACK_RGBA(r, g, b, a)); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetColorFor(CPlayer & player, const Color4 & col) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetTextdrawColour(m_ID, player.GetID(), col.GetRGBA()); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetColorForEx(CPlayer & player, Uint8 r, Uint8 g, Uint8 b, Uint8 a) const +{ + // Is the specified player even valid? + if (!player.IsActive()) + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetTextdrawColour(m_ID, player.GetID(), SQMOD_PACK_RGBA(r, g, b, a)); +} + +// ------------------------------------------------------------------------------------------------ +void CTextdraw::SetColorRange(Int32 first, Int32 last, const Color4 & col) const +{ + // Validate the specified range + if (first > last) + SqThrowF("Invalid player range: %d > %d", first, last); + // Validate the managed identifier + Validate(); + // Perform the requested operation + for (const Uint32 color = col.GetRGBA(); first <= last; ++first) + { + // Is the currently processed player even connected? + if (_Func->IsPlayerConnected(first)) + // Then colorize this textdraw on his client + _Func->SetTextdrawColour(m_ID, first, color); + } +} + +// ------------------------------------------------------------------------------------------------ +const String & CTextdraw::GetText() const +{ + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetTextdraw(m_ID).mText; +} + +// ------------------------------------------------------------------------------------------------ +static Object & Textdraw_CreateEx(CSStr text, Int32 xp, Int32 yp, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool rel) { return _Core->NewTextdraw(SQMOD_UNKNOWN, text, xp, yp, SQMOD_PACK_ARGB(a, r, g, b), rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateTextdrawEx(CSStr text, Int32 xp, Int32 yp, +// ------------------------------------------------------------------------------------------------ +static Object & Textdraw_CreateEx(CSStr text, Int32 xp, Int32 yp, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool rel, Int32 header, Object & payload) { @@ -246,14 +328,15 @@ static Object & CreateTextdrawEx(CSStr text, Int32 xp, Int32 yp, } // ------------------------------------------------------------------------------------------------ -static Object & CreateTextdrawEx(Int32 index, CSStr text, Int32 xp, Int32 yp, +static Object & Textdraw_CreateEx(Int32 index, CSStr text, Int32 xp, Int32 yp, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool rel) { return _Core->NewTextdraw(index,text, xp, yp, SQMOD_PACK_ARGB(a, r, g, b), rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateTextdrawEx(Int32 index, CSStr text, Int32 xp, Int32 yp, +// ------------------------------------------------------------------------------------------------ +static Object & Textdraw_CreateEx(Int32 index, CSStr text, Int32 xp, Int32 yp, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool rel, Int32 header, Object & payload) { @@ -262,13 +345,14 @@ static Object & CreateTextdrawEx(Int32 index, CSStr text, Int32 xp, Int32 yp, } // ------------------------------------------------------------------------------------------------ -static Object & CreateTextdraw(CSStr text, const Vector2i & pos, const Color4 & color, bool rel) +static Object & Textdraw_Create(CSStr text, const Vector2i & pos, const Color4 & color, bool rel) { return _Core->NewTextdraw(SQMOD_UNKNOWN, text, pos.x, pos.y, color.GetARGB(), rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateTextdraw(CSStr text, const Vector2i & pos, const Color4 & color, bool rel, +// ------------------------------------------------------------------------------------------------ +static Object & Textdraw_Create(CSStr text, const Vector2i & pos, const Color4 & color, bool rel, Int32 header, Object & payload) { return _Core->NewTextdraw(SQMOD_UNKNOWN, text, pos.x, pos.y, color.GetARGB(), rel, @@ -276,14 +360,15 @@ static Object & CreateTextdraw(CSStr text, const Vector2i & pos, const Color4 & } // ------------------------------------------------------------------------------------------------ -static Object & CreateTextdraw(Int32 index, CSStr text, const Vector2i & pos, const Color4 & color, +static Object & Textdraw_Create(Int32 index, CSStr text, const Vector2i & pos, const Color4 & color, bool rel) { return _Core->NewTextdraw(index, text, pos.x, pos.y, color.GetARGB(), rel, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateTextdraw(Int32 index, CSStr text, const Vector2i & pos, const Color4 & color, +// ------------------------------------------------------------------------------------------------ +static Object & Textdraw_Create(Int32 index, CSStr text, const Vector2i & pos, const Color4 & color, bool rel, Int32 header, Object & payload) { return _Core->NewTextdraw(index, text, pos.x, pos.y, color.GetARGB(), rel, header, payload); @@ -294,24 +379,26 @@ void Register_CTextdraw(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqTextdraw"), Class< CTextdraw, NoConstructor< CTextdraw > >(vm, _SC("SqTextdraw")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CTextdraw::Cmp) + .SquirrelFunc(_SC("_typename"), &CTextdraw::Typename) .Func(_SC("_tostring"), &CTextdraw::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CTextdraw::Max) + // Core Properties .Prop(_SC("ID"), &CTextdraw::GetID) .Prop(_SC("Tag"), &CTextdraw::GetTag, &CTextdraw::SetTag) .Prop(_SC("Data"), &CTextdraw::GetData, &CTextdraw::SetData) - .Prop(_SC("MaxID"), &CTextdraw::GetMaxID) .Prop(_SC("Active"), &CTextdraw::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CTextdraw::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CTextdraw::*)(void) >(_SC("Destroy"), &CTextdraw::Destroy) .Overload< bool (CTextdraw::*)(Int32) >(_SC("Destroy"), &CTextdraw::Destroy) .Overload< bool (CTextdraw::*)(Int32, Object &) >(_SC("Destroy"), &CTextdraw::Destroy) - /* Properties */ + // Properties .Prop(_SC("Text"), &CTextdraw::GetText) - /* Functions */ + // Functions .Func(_SC("ShowAll"), &CTextdraw::ShowAll) .Func(_SC("ShowTo"), &CTextdraw::ShowFor) .Func(_SC("ShowFor"), &CTextdraw::ShowFor) @@ -322,7 +409,7 @@ void Register_CTextdraw(HSQUIRRELVM vm) .Func(_SC("HideRange"), &CTextdraw::HideRange) .Func(_SC("SetPositionRange"), &CTextdraw::SetPositionRange) .Func(_SC("SetColorRange"), &CTextdraw::SetColorRange) - /* Overloads */ + // Overloads .Overload< void (CTextdraw::*)(const Vector2i &) const > (_SC("SetPositionAll"), &CTextdraw::SetPositionAll) .Overload< void (CTextdraw::*)(Int32, Int32) const > @@ -339,25 +426,24 @@ void Register_CTextdraw(HSQUIRRELVM vm) (_SC("SetColorFor"), &CTextdraw::SetColorFor) .Overload< void (CTextdraw::*)(CPlayer &, Uint8, Uint8, Uint8, Uint8) const > (_SC("SetColorFor"), &CTextdraw::SetColorForEx) + // Static Overloads + .StaticOverload< Object & (*)(CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool) > + (_SC("CreateEx"), &Textdraw_CreateEx) + .StaticOverload< Object & (*)(CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool, Int32, Object &) > + (_SC("CreateEx"), &Textdraw_CreateEx) + .StaticOverload< Object & (*)(Int32, CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool) > + (_SC("CreateEx"), &Textdraw_CreateEx) + .StaticOverload< Object & (*)(Int32, CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool, Int32, Object &) > + (_SC("CreateEx"), &Textdraw_CreateEx) + .StaticOverload< Object & (*)(CSStr, const Vector2i &, const Color4 &, bool) > + (_SC("Create"), &Textdraw_Create) + .StaticOverload< Object & (*)(CSStr, const Vector2i &, const Color4 &, bool, Int32, Object &) > + (_SC("Create"), &Textdraw_Create) + .StaticOverload< Object & (*)(Int32, CSStr, const Vector2i &, const Color4 &, bool) > + (_SC("Create"), &Textdraw_Create) + .StaticOverload< Object & (*)(Int32, CSStr, const Vector2i &, const Color4 &, bool, Int32, Object &) > + (_SC("Create"), &Textdraw_Create) ); - - RootTable(vm) - .Overload< Object & (*)(CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool) > - (_SC("CreateTextdrawEx"), &CreateTextdrawEx) - .Overload< Object & (*)(CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool, Int32, Object &) > - (_SC("CreateTextdrawEx"), &CreateTextdrawEx) - .Overload< Object & (*)(Int32, CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool) > - (_SC("CreateTextdrawEx"), &CreateTextdrawEx) - .Overload< Object & (*)(Int32, CSStr, Int32, Int32, Uint8, Uint8, Uint8, Uint8, bool, Int32, Object &) > - (_SC("CreateTextdrawEx"), &CreateTextdrawEx) - .Overload< Object & (*)(CSStr, const Vector2i &, const Color4 &, bool) > - (_SC("CreateTextdraw"), &CreateTextdraw) - .Overload< Object & (*)(CSStr, const Vector2i &, const Color4 &, bool, Int32, Object &) > - (_SC("CreateTextdraw"), &CreateTextdraw) - .Overload< Object & (*)(Int32, CSStr, const Vector2i &, const Color4 &, bool) > - (_SC("CreateTextdraw"), &CreateTextdraw) - .Overload< Object & (*)(Int32, CSStr, const Vector2i &, const Color4 &, bool, Int32, Object &) > - (_SC("CreateTextdraw"), &CreateTextdraw); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Textdraw.hpp b/source/Entity/Textdraw.hpp index c950e1a4..064fe330 100644 --- a/source/Entity/Textdraw.hpp +++ b/source/Entity/Textdraw.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Textdraw instances. + * Manages a single textdraw entity. */ class CTextdraw { @@ -17,20 +17,19 @@ class CTextdraw private: - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_TEXTDRAW_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -38,35 +37,45 @@ private: */ CTextdraw(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CTextdraw(const CTextdraw &); + CTextdraw(const CTextdraw &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CTextdraw & operator = (const CTextdraw &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CTextdraw(CTextdraw &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~CTextdraw(); + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + CTextdraw & operator = (const CTextdraw &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CTextdraw & operator = (CTextdraw &&) = delete; + /* -------------------------------------------------------------------------------------------- * See whether this instance manages a valid entity. */ - bool Validate() const + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid textdraw reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid textdraw reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -77,27 +86,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_TEXTDRAW_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -114,32 +129,116 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed textdraw entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed textdraw entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed textdraw entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Show the managed textdraw entity to all players on the server. + */ void ShowAll() const; + + /* -------------------------------------------------------------------------------------------- + * Show the managed textdraw entity to the specified player entity. + */ void ShowFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Show the managed textdraw entity to all players in the specified range. + */ void ShowRange(Int32 first, Int32 last) const; + + /* -------------------------------------------------------------------------------------------- + * Hide the managed textdraw entity from all players on the server. + */ void HideAll() const; + + /* -------------------------------------------------------------------------------------------- + * Hide the managed textdraw entity from the specified player entity. + */ void HideFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Hide the managed textdraw entity from all players in the specified range. + */ void HideRange(Int32 first, Int32 last) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed textdraw entity for all players on the server. + */ void SetPositionAll(const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed textdraw entity for all players on the server. + */ void SetPositionAllEx(Int32 x, Int32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed textdraw entity for the specified player entity. + */ void SetPositionFor(CPlayer & player, const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed textdraw entity for the specified player entity. + */ void SetPositionForEx(CPlayer & player, Int32 x, Int32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Set the position of the managed textdraw entity for all players in the specified range. + */ void SetPositionRange(Int32 first, Int32 last, const Vector2i & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Set the center of the managed textdraw entity for all players on the server. + */ void SetColorAll(const Color4 & col) const; + + /* -------------------------------------------------------------------------------------------- + * Set the color of the managed textdraw entity for all players on the server. + */ void SetColorAllEx(Uint8 r, Uint8 g, Uint8 b, Uint8 a) const; + + /* -------------------------------------------------------------------------------------------- + * Set the color of the managed textdraw entity for the specified player entity. + */ void SetColorFor(CPlayer & player, const Color4 & col) const; + + /* -------------------------------------------------------------------------------------------- + * Set the color of the managed textdraw entity for the specified player entity. + */ void SetColorForEx(CPlayer & player, Uint8 r, Uint8 g, Uint8 b, Uint8 a) const; + + /* -------------------------------------------------------------------------------------------- + * Set the color of the managed textdraw entity for all players in the specified range. + */ void SetColorRange(Int32 first, Int32 last, const Color4 & col) const; - CSStr GetText() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the text string used by the managed textdraw entity. + */ + const String & GetText() const; }; } // Namespace:: SqMod diff --git a/source/Entity/Vehicle.cpp b/source/Entity/Vehicle.cpp index 40e2085f..3cfd7bad 100644 --- a/source/Entity/Vehicle.cpp +++ b/source/Entity/Vehicle.cpp @@ -14,15 +14,20 @@ Vector4 CVehicle::s_Vector4; Quaternion CVehicle::s_Quaternion; // ------------------------------------------------------------------------------------------------ -SQChar CVehicle::s_StrID[SQMOD_VEHICLE_POOL][8]; +const Int32 CVehicle::Max = SQMOD_VEHICLE_POOL; // ------------------------------------------------------------------------------------------------ -const Int32 CVehicle::Max = SQMOD_VEHICLE_POOL; +SQInteger CVehicle::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqVehicle"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} // ------------------------------------------------------------------------------------------------ CVehicle::CVehicle(Int32 id) : m_ID(VALID_ENTITYGETEX(id, SQMOD_VEHICLE_POOL)) - , m_Tag(VALID_ENTITY(m_ID) ? s_StrID[m_ID] : _SC("-1")) + , m_Tag(ToStrF("%d", id)) { /* ... */ } @@ -44,818 +49,1155 @@ Int32 CVehicle::Cmp(const CVehicle & o) const return -1; } -CSStr CVehicle::ToString() const +// ------------------------------------------------------------------------------------------------ +const String & CVehicle::ToString() const { - return VALID_ENTITYEX(m_ID, SQMOD_VEHICLE_POOL) ? s_StrID[m_ID] : _SC("-1"); + return m_Tag; } // ------------------------------------------------------------------------------------------------ -CSStr CVehicle::GetTag() const +const String & CVehicle::GetTag() const { - return m_Tag.c_str(); + return m_Tag; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetTag(CSStr tag) { m_Tag.assign(tag); } +// ------------------------------------------------------------------------------------------------ Object & CVehicle::GetData() { - if (Validate()) - return m_Data; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return m_Data; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetData(Object & data) { - if (Validate()) - m_Data = data; + // Validate the managed identifier + Validate(); + // Apply the specified value + m_Data = data; } // ------------------------------------------------------------------------------------------------ bool CVehicle::Destroy(Int32 header, Object & payload) { + // Validate the managed identifier + Validate(); + // Perform the requested operation return _Core->DelVehicle(m_ID, header, payload); } // ------------------------------------------------------------------------------------------------ -bool CVehicle::BindEvent(Int32 evid, Object & env, Function & func) const +void CVehicle::BindEvent(Int32 evid, Object & env, Function & func) const { - if (!Validate()) - return false; - + // Validate the managed identifier + Validate(); + // Obtain the function instance called for this event Function & event = _Core->GetVehicleEvent(m_ID, evid); - + // Is the specified callback function null? if (func.IsNull()) - event.Release(); + event.Release(); // Then release the current callback + // Assign the specified environment and function else event = Function(env.GetVM(), env, func.GetFunc()); - - return true; } // ------------------------------------------------------------------------------------------------ bool CVehicle::IsStreamedFor(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - return _Func->IsVehicleStreamedForPlayer(m_ID, player.GetID()); - return false; + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsVehicleStreamedForPlayer(m_ID, player.GetID()); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetSyncSource() const { - if (Validate()) - return _Func->GetVehicleSyncSource(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleSyncSource(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetSyncType() const { - if (Validate()) - return _Func->GetVehicleSyncType(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleSyncType(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetWorld() const { - if (Validate()) - return _Func->GetVehicleWorld(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleWorld(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetWorld(Int32 world) const { - if (Validate()) - _Func->SetVehicleWorld(m_ID, world); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleWorld(m_ID, world); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetModel() const { - if (Validate()) - return _Func->GetVehicleModel(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleModel(m_ID); } +// ------------------------------------------------------------------------------------------------ Object & CVehicle::GetOccupant(Int32 slot) const { - if (Validate()) - return _Core->GetPlayer(_Func->GetVehicleOccupant(m_ID, slot)).mObj; - return NullObject(); + // Validate the managed identifier + Validate(); + // Return the requested information + return _Core->GetPlayer(_Func->GetVehicleOccupant(m_ID, slot)).mObj; } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetOccupantID(Int32 slot) const { - if (Validate()) - return _Func->GetVehicleOccupant(m_ID, slot); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleOccupant(m_ID, slot); } +// ------------------------------------------------------------------------------------------------ void CVehicle::Respawn() const { - if (Validate()) - _Func->RespawnVehicle(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->RespawnVehicle(m_ID); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetImmunity() const { - if (Validate()) - return _Func->GetVehicleImmunityFlags(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleImmunityFlags(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetImmunity(Int32 flags) const { - if (Validate()) - _Func->SetVehicleImmunityFlags(m_ID, flags); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleImmunityFlags(m_ID, flags); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::IsWrecked() const { - if (Validate()) - return _Func->IsVehicleWrecked(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsVehicleWrecked(m_ID); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetPosition() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehiclePos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the position values + _Func->GetVehiclePos(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPosition(const Vector3 & pos) const { - if (Validate()) - _Func->SetVehiclePos(m_ID, pos.x, pos.y, pos.z, false); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, pos.x, pos.y, pos.z, false); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPositionEx(const Vector3 & pos, bool empty) const { - if (Validate()) - _Func->SetVehiclePos(m_ID, pos.x, pos.y, pos.z, empty); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, pos.x, pos.y, pos.z, empty); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPositionEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehiclePos(m_ID, x, y, z, false); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, x, y, z, false); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPositionEx(Float32 x, Float32 y, Float32 z, bool empty) const { - if (Validate()) - _Func->SetVehiclePos(m_ID, x, y, z, empty); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, x, y, z, empty); } +// ------------------------------------------------------------------------------------------------ const Quaternion & CVehicle::GetRotation() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.Clear(); - if (Validate()) - _Func->GetVehicleRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, - &s_Quaternion.z, &s_Quaternion.w); + // Query the server for the rotation values + _Func->GetVehicleRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); + // Return the requested information return s_Quaternion; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotation(const Quaternion & rot) const { - if (Validate()) - _Func->SetVehicleRot(m_ID, rot.x, rot.y, rot.z, rot.w); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRot(m_ID, rot.x, rot.y, rot.z, rot.w); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotationEx(Float32 x, Float32 y, Float32 z, Float32 w) const { - if (Validate()) - _Func->SetVehicleRot(m_ID, x, y, z, w); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRot(m_ID, x, y, z, w); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetRotationEuler() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the rotation values + _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotationEuler(const Vector3 & rot) const { - if (Validate()) - _Func->SetVehicleRotEuler(m_ID, rot.x, rot.y, rot.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRotEuler(m_ID, rot.x, rot.y, rot.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotationEulerEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehicleRotEuler(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRotEuler(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetSpeed() const { + // Validate the managed identifier + Validate(); + // Clear previous speed information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehicleSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the speed values + _Func->GetVehicleSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->SetVehicleSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehicleSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->AddVehicleSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->AddVehicleSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetRelSpeed() const { + // Validate the managed identifier + Validate(); + // Clear previous relative speed information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehicleRelSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the relative speed values + _Func->GetVehicleRelSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRelSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->SetVehicleRelSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRelSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRelSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehicleRelSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRelSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddRelSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->AddVehicleRelSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleRelSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddRelSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->AddVehicleRelSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleRelSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetTurnSpeed() const { + // Validate the managed identifier + Validate(); + // Clear previous turn speed information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehicleTurnSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the turn speed values + _Func->GetVehicleTurnSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetTurnSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->SetVehicleTurnSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleTurnSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetTurnSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehicleTurnSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleTurnSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddTurnSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->AddVehicleTurnSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleTurnSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddTurnSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->AddVehicleTurnSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleTurnSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetRelTurnSpeed() const { + // Validate the managed identifier + Validate(); + // Clear previous relative turn speed information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehicleRelTurnSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); - + // Query the server for the relative turn speed values + _Func->GetVehicleRelTurnSpeed(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRelTurnSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->SetVehicleRelTurnSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRelTurnSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRelTurnSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehicleRelTurnSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRelTurnSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddRelTurnSpeed(const Vector3 & vel) const { - if (Validate()) - _Func->AddVehicleRelTurnSpeed(m_ID, vel.x, vel.y, vel.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleRelTurnSpeed(m_ID, vel.x, vel.y, vel.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::AddRelTurnSpeedEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->AddVehicleRelTurnSpeed(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->AddVehicleRelTurnSpeed(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ const Vector4 & CVehicle::GetSpawnPosition() const { + // Validate the managed identifier + Validate(); + // Clear previous spawn position information, if any s_Vector4.Clear(); - if (Validate()) - _Func->GetVehicleSpawnPos(m_ID, &s_Vector4.x, &s_Vector4.y, &s_Vector4.z, &s_Vector4.w); + // Query the server for the spawn position values + _Func->GetVehicleSpawnPos(m_ID, &s_Vector4.x, &s_Vector4.y, &s_Vector4.z, &s_Vector4.w); + // Return the requested information return s_Vector4; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpawnPosition(const Vector4 & pos) const { - if (Validate()) - _Func->SetVehicleSpawnPos(m_ID, pos.x, pos.y, pos.z, pos.w); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpawnPos(m_ID, pos.x, pos.y, pos.z, pos.w); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpawnPositionEx(Float32 x, Float32 y, Float32 z, Float32 w) const { - if (Validate()) - _Func->SetVehicleSpawnPos(m_ID, x, y, z, w); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpawnPos(m_ID, x, y, z, w); } +// ------------------------------------------------------------------------------------------------ const Quaternion & CVehicle::GetSpawnRotation() const { + // Validate the managed identifier + Validate(); + // Clear previous spawn rotation information, if any s_Quaternion.Clear(); - if (Validate()) - _Func->GetVehicleSpawnRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); + // Query the server for the spawn rotation values + _Func->GetVehicleSpawnRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); + // Return the requested information return s_Quaternion; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpawnRotation(const Quaternion & rot) const { - if (Validate()) - _Func->SetVehicleSpawnRot(m_ID, rot.x, rot.y, rot.z, rot.w); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpawnRot(m_ID, rot.x, rot.y, rot.z, rot.w); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpawnRotationEx(Float32 x, Float32 y, Float32 z, Float32 w) const { - if (Validate()) - _Func->SetVehicleSpawnRot(m_ID, x, y, z, w); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpawnRot(m_ID, x, y, z, w); } +// ------------------------------------------------------------------------------------------------ const Vector3 & CVehicle::GetSpawnRotationEuler() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.Clear(); - if (Validate()) - _Func->GetVehicleSpawnRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Query the server for the rotation values + _Func->GetVehicleSpawnRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, &s_Vector3.z); + // Return the requested information return s_Vector3; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpawnRotationEuler(const Vector3 & rot) const { - if (Validate()) - _Func->SetVehicleSpawnRotEuler(m_ID, rot.x, rot.y, rot.z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpawnRotEuler(m_ID, rot.x, rot.y, rot.z); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSpawnRotationEulerEx(Float32 x, Float32 y, Float32 z) const { - if (Validate()) - _Func->SetVehicleSpawnRotEuler(m_ID, x, y, z); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleSpawnRotEuler(m_ID, x, y, z); } +// ------------------------------------------------------------------------------------------------ Uint32 CVehicle::GetRespawnTimer() const { - if (Validate()) - return _Func->GetVehicleIdleRespawnTimer(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleIdleRespawnTimer(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRespawnTimer(Uint32 timer) const { - if (Validate()) - _Func->SetVehicleIdleRespawnTimer(m_ID, timer); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleIdleRespawnTimer(m_ID, timer); } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetHealth() const { - if (Validate()) - return _Func->GetVehicleHealth(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleHealth(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetHealth(Float32 amount) const { - if (Validate()) - _Func->SetVehicleHealth(m_ID, amount); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleHealth(m_ID, amount); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetPrimaryColor() const { + // Validate the managed identifier + Validate(); + // The color value Int32 primary = -1; - if (Validate()) - _Func->GetVehicleColour(m_ID, &primary, NULL); + // Query the server for the requested color + _Func->GetVehicleColour(m_ID, &primary, NULL); + // Return the requested information return primary; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPrimaryColor(Int32 col) const { - if (!Validate()) - return; + // Validate the managed identifier + Validate(); + // The unchanged color value Int32 secondary; + // Query the server for the unchanged color _Func->GetVehicleColour(m_ID, NULL, &secondary); + // Perform the requested operation _Func->SetVehicleColour(m_ID, col, secondary); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetSecondaryColor() const { + // Validate the managed identifier + Validate(); + // The color value Int32 secondary = -1; - if (Validate()) - _Func->GetVehicleColour(m_ID, NULL, &secondary); + // Query the server for the requested color + _Func->GetVehicleColour(m_ID, NULL, &secondary); + // Return the requested information return secondary; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetSecondaryColor(Int32 col) const { - if (!Validate()) - return; + // Validate the managed identifier + Validate(); + // The unchanged color value Int32 primary; + // Query the server for the unchanged color _Func->GetVehicleColour(m_ID, &primary, NULL); + // Perform the requested operation _Func->SetVehicleColour(m_ID, primary, col); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetColors(Int32 primary, Int32 secondary) const { - if (Validate()) - _Func->SetVehicleColour(m_ID, primary, secondary); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleColour(m_ID, primary, secondary); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::GetLocked() const { - if (Validate()) - return _Func->GetVehicleDoorsLocked(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleDoorsLocked(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetLocked(bool toggle) const { - if (Validate()) - _Func->SetVehicleDoorsLocked(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleDoorsLocked(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetPartStatus(Int32 part) const { - if (Validate()) - return _Func->GetVehiclePartStatus(m_ID, part); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehiclePartStatus(m_ID, part); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPartStatus(Int32 part, Int32 status) const { - if (Validate()) - _Func->SetVehiclePartStatus(m_ID, part, status); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehiclePartStatus(m_ID, part, status); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetTyreStatus(Int32 tyre) const { - if (Validate()) - return _Func->GetVehicleTyreStatus(m_ID, tyre); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleTyreStatus(m_ID, tyre); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetTyreStatus(Int32 tyre, Int32 status) const { - if (Validate()) - _Func->SetVehicleTyreStatus(m_ID, tyre, status); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleTyreStatus(m_ID, tyre, status); } +// ------------------------------------------------------------------------------------------------ Uint32 CVehicle::GetDamageData() const { - if (Validate()) - return _Func->GetVehicleDamageData(m_ID); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleDamageData(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetDamageData(Uint32 data) const { - if (Validate()) - _Func->SetVehicleDamageData(m_ID, data); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleDamageData(m_ID, data); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::GetAlarm() const { - if (Validate()) - return _Func->GetVehicleAlarm(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleAlarm(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetAlarm(bool toggle) const { - if (Validate()) - _Func->SetVehicleAlarm(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleAlarm(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::GetLights() const { - if (Validate()) - return _Func->GetVehicleLights(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleLights(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetLights(bool toggle) const { - if (Validate()) - _Func->SetVehicleLights(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleLights(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ Int32 CVehicle::GetRadio() const { - if (Validate()) - return _Func->GetVehicleRadio(m_ID); - return -1; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleRadio(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRadio(Int32 radio) const { - if (Validate()) - _Func->SetVehicleRadio(m_ID, radio); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRadio(m_ID, radio); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::GetRadioLocked() const { - if (Validate()) - return _Func->IsVehicleRadioLocked(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->IsVehicleRadioLocked(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRadioLocked(bool toggle) const { - if (Validate()) - _Func->SetVehicleRadioLocked(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleRadioLocked(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::GetGhostState() const { - if (Validate()) - return _Func->GetVehicleGhostState(m_ID); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetVehicleGhostState(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetGhostState(bool toggle) const { - if (Validate()) - _Func->SetVehicleGhostState(m_ID, toggle); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetVehicleGhostState(m_ID, toggle); } +// ------------------------------------------------------------------------------------------------ void CVehicle::ResetHandling() const { - if (Validate()) - _Func->ResetInstHandling(m_ID); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ResetInstHandling(m_ID); } +// ------------------------------------------------------------------------------------------------ void CVehicle::ResetHandling(Int32 rule) const { - if (Validate()) - _Func->ResetInstHandlingRule(m_ID, rule); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->ResetInstHandlingRule(m_ID, rule); } +// ------------------------------------------------------------------------------------------------ bool CVehicle::ExistsHandling(Int32 rule) const { - if (Validate()) - return _Func->ExistsInstHandlingRule(m_ID, rule); - return false; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->ExistsInstHandlingRule(m_ID, rule); } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetHandlingData(Int32 rule) const { - if (Validate()) - return _Func->GetInstHandlingRule(m_ID, rule); - return 0; + // Validate the managed identifier + Validate(); + // Return the requested information + return _Func->GetInstHandlingRule(m_ID, rule); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetHandlingData(Int32 rule, Float32 data) const { - if (Validate()) - _Func->SetInstHandlingRule(m_ID, rule, data); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->SetInstHandlingRule(m_ID, rule, data); } +// ------------------------------------------------------------------------------------------------ void CVehicle::Embark(CPlayer & player) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->PutPlayerInVehicle(player.GetID(), m_ID, 0, true, true); + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PutPlayerInVehicle(player.GetID(), m_ID, 0, true, true); } +// ------------------------------------------------------------------------------------------------ void CVehicle::Embark(CPlayer & player, Int32 slot, bool allocate, bool warp) const { + // Is the specified player even valid? if (!player.IsActive()) - SqThrow("Invalid player argument: null"); - else if (Validate()) - _Func->PutPlayerInVehicle(player.GetID(), m_ID, slot, allocate, warp); + SqThrowF("Invalid player argument: null"); + // Validate the managed identifier + Validate(); + // Perform the requested operation + _Func->PutPlayerInVehicle(player.GetID(), m_ID, slot, allocate, warp); } // ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetPosX() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetVehiclePos(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetVehiclePos(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetPosY() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetVehiclePos(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetVehiclePos(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetPosZ() const { + // Validate the managed identifier + Validate(); + // Clear previous position information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetVehiclePos(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetVehiclePos(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } // ------------------------------------------------------------------------------------------------ void CVehicle::SetPosX(Float32 x) const { - if (Validate()) - { - _Func->GetVehiclePos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->SetVehiclePos(m_ID, x, s_Vector3.y, s_Vector3.z, false); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehiclePos(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, x, s_Vector3.y, s_Vector3.z, false); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPosY(Float32 y) const { - if (Validate()) - { - _Func->GetVehiclePos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->SetVehiclePos(m_ID, s_Vector3.x, y, s_Vector3.z, false); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehiclePos(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, s_Vector3.x, y, s_Vector3.z, false); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetPosZ(Float32 z) const { - if (Validate()) - { - _Func->GetVehiclePos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->SetVehiclePos(m_ID, s_Vector3.z, s_Vector3.y, z, false); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehiclePos(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->SetVehiclePos(m_ID, s_Vector3.z, s_Vector3.y, z, false); } // ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetRotX() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.x = 0; - if (Validate()) - _Func->GetVehicleRot(m_ID, &s_Quaternion.x, NULL, NULL, NULL); + // Query the server for the requested component value + _Func->GetVehicleRot(m_ID, &s_Quaternion.x, NULL, NULL, NULL); + // Return the requested information return s_Quaternion.x; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetRotY() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.y = 0; - if (Validate()) - _Func->GetVehicleRot(m_ID, NULL, &s_Quaternion.y, NULL, NULL); + // Query the server for the requested component value + _Func->GetVehicleRot(m_ID, NULL, &s_Quaternion.y, NULL, NULL); + // Return the requested information return s_Quaternion.y; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetRotZ() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.z = 0; - if (Validate()) - _Func->GetVehicleRot(m_ID, NULL, NULL, &s_Quaternion.z, NULL); + // Query the server for the requested component value + _Func->GetVehicleRot(m_ID, NULL, NULL, &s_Quaternion.z, NULL); + // Return the requested information return s_Quaternion.z; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetRotW() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Quaternion.w = 0; - if (Validate()) - _Func->GetVehicleRot(m_ID, NULL, NULL, NULL, &s_Quaternion.w); + // Query the server for the requested component value + _Func->GetVehicleRot(m_ID, NULL, NULL, NULL, &s_Quaternion.w); + // Return the requested information return s_Quaternion.w; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotX(Float32 x) const { - if (Validate()) - { - _Func->GetVehicleRot(m_ID, NULL, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); - _Func->SetVehicleRot(m_ID, x, s_Quaternion.y, s_Quaternion.z, s_Quaternion.w); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRot(m_ID, NULL, &s_Quaternion.y, &s_Quaternion.z, &s_Quaternion.w); + // Perform the requested operation + _Func->SetVehicleRot(m_ID, x, s_Quaternion.y, s_Quaternion.z, s_Quaternion.w); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotY(Float32 y) const { - if (Validate()) - { - _Func->GetVehicleRot(m_ID, &s_Quaternion.x, NULL, &s_Quaternion.z, &s_Quaternion.w); - _Func->SetVehicleRot(m_ID, s_Quaternion.x, y, s_Quaternion.z, s_Quaternion.w); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRot(m_ID, &s_Quaternion.x, NULL, &s_Quaternion.z, &s_Quaternion.w); + // Perform the requested operation + _Func->SetVehicleRot(m_ID, s_Quaternion.x, y, s_Quaternion.z, s_Quaternion.w); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotZ(Float32 z) const { - if (Validate()) - { - _Func->GetVehicleRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, NULL, &s_Quaternion.w); - _Func->SetVehicleRot(m_ID, s_Quaternion.x, s_Quaternion.y, z, s_Quaternion.w); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, NULL, &s_Quaternion.w); + // Perform the requested operation + _Func->SetVehicleRot(m_ID, s_Quaternion.x, s_Quaternion.y, z, s_Quaternion.w); } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetRotW(Float32 w) const { - if (Validate()) - { - _Func->GetVehicleRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, NULL); - _Func->SetVehicleRot(m_ID, s_Quaternion.x, s_Quaternion.y, s_Quaternion.z, w); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRot(m_ID, &s_Quaternion.x, &s_Quaternion.y, &s_Quaternion.z, NULL); + // Perform the requested operation + _Func->SetVehicleRot(m_ID, s_Quaternion.x, s_Quaternion.y, s_Quaternion.z, w); } // ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetERotX() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.x = 0; - if (Validate()) - _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, NULL, NULL); + // Query the server for the requested component value + _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, NULL, NULL); + // Return the requested information return s_Vector3.x; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetERotY() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.y = 0; - if (Validate()) - _Func->GetVehicleRotEuler(m_ID, NULL, &s_Vector3.y, NULL); + // Query the server for the requested component value + _Func->GetVehicleRotEuler(m_ID, NULL, &s_Vector3.y, NULL); + // Return the requested information return s_Vector3.y; } +// ------------------------------------------------------------------------------------------------ Float32 CVehicle::GetERotZ() const { + // Validate the managed identifier + Validate(); + // Clear previous rotation information, if any s_Vector3.z = 0; - if (Validate()) - _Func->GetVehicleRotEuler(m_ID, NULL, NULL, &s_Vector3.z); + // Query the server for the requested component value + _Func->GetVehicleRotEuler(m_ID, NULL, NULL, &s_Vector3.z); + // Return the requested information return s_Vector3.z; } +// ------------------------------------------------------------------------------------------------ void CVehicle::SetERotX(Float32 x) const { - if (Validate()) - { - _Func->GetVehicleRotEuler(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); - _Func->SetVehicleRotEuler(m_ID, x, s_Vector3.y, s_Vector3.z); - } -} - -void CVehicle::SetERotY(Float32 y) const -{ - if (Validate()) - { - _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); - _Func->SetVehicleRotEuler(m_ID, s_Vector3.x, y, s_Vector3.z); - } -} - -void CVehicle::SetERotZ(Float32 z) const -{ - if (Validate()) - { - _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); - _Func->SetVehicleRotEuler(m_ID, s_Vector3.z, s_Vector3.y, z); - } + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRotEuler(m_ID, NULL, &s_Vector3.y, &s_Vector3.z); + // Perform the requested operation + _Func->SetVehicleRotEuler(m_ID, x, s_Vector3.y, s_Vector3.z); } // ------------------------------------------------------------------------------------------------ -static Object & CreateVehicleEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Float32 angle, +void CVehicle::SetERotY(Float32 y) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, NULL, &s_Vector3.z); + // Perform the requested operation + _Func->SetVehicleRotEuler(m_ID, s_Vector3.x, y, s_Vector3.z); +} + +// ------------------------------------------------------------------------------------------------ +void CVehicle::SetERotZ(Float32 z) const +{ + // Validate the managed identifier + Validate(); + // Retrieve the current values for unchanged components + _Func->GetVehicleRotEuler(m_ID, &s_Vector3.x, &s_Vector3.y, NULL); + // Perform the requested operation + _Func->SetVehicleRotEuler(m_ID, s_Vector3.z, s_Vector3.y, z); +} + +// ------------------------------------------------------------------------------------------------ +static Object & Vehicle_CreateEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Float32 angle, Int32 primary, Int32 secondary) { return _Core->NewVehicle(model, world, x, y, z, angle, primary, secondary, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateVehicleEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Float32 angle, +static Object & Vehicle_CreateEx(Int32 model, Int32 world, Float32 x, Float32 y, Float32 z, Float32 angle, Int32 primary, Int32 secondary, Int32 header, Object & payload) { return _Core->NewVehicle(model, world, x, y, z, angle, primary, secondary, @@ -863,14 +1205,14 @@ static Object & CreateVehicleEx(Int32 model, Int32 world, Float32 x, Float32 y, } // ------------------------------------------------------------------------------------------------ -static Object & CreateVehicle(Int32 model, Int32 world, const Vector3 & pos, Float32 angle, +static Object & Vehicle_Create(Int32 model, Int32 world, const Vector3 & pos, Float32 angle, Int32 primary, Int32 secondary) { return _Core->NewVehicle(model, world, pos.x, pos.y, pos.z, angle, primary, secondary, SQMOD_CREATE_DEFAULT, NullObject()); } -static Object & CreateVehicle(Int32 model, Int32 world, const Vector3 & pos, Float32 angle, +static Object & Vehicle_Create(Int32 model, Int32 world, const Vector3 & pos, Float32 angle, Int32 primary, Int32 secondary, Int32 header, Object & payload) { return _Core->NewVehicle(model, world, pos.x, pos.y, pos.z, angle, primary, secondary, @@ -882,22 +1224,24 @@ void Register_CVehicle(HSQUIRRELVM vm) { RootTable(vm).Bind(_SC("SqVehicle"), Class< CVehicle, NoConstructor< CVehicle > >(vm, _SC("SqVehicle")) - /* Metamethods */ + // Metamethods .Func(_SC("_cmp"), &CVehicle::Cmp) + .SquirrelFunc(_SC("_typename"), &CVehicle::Typename) .Func(_SC("_tostring"), &CVehicle::ToString) - /* Core Properties */ + // Static values + .SetStaticValue(_SC("MaxID"), CVehicle::Max) + // Core Properties .Prop(_SC("ID"), &CVehicle::GetID) .Prop(_SC("Tag"), &CVehicle::GetTag, &CVehicle::SetTag) .Prop(_SC("Data"), &CVehicle::GetData, &CVehicle::SetData) - .Prop(_SC("MaxID"), &CVehicle::GetMaxID) .Prop(_SC("Active"), &CVehicle::IsActive) - /* Core Functions */ + // Core Functions .Func(_SC("Bind"), &CVehicle::BindEvent) - /* Core Overloads */ + // Core Overloads .Overload< bool (CVehicle::*)(void) >(_SC("Destroy"), &CVehicle::Destroy) .Overload< bool (CVehicle::*)(Int32) >(_SC("Destroy"), &CVehicle::Destroy) .Overload< bool (CVehicle::*)(Int32, Object &) >(_SC("Destroy"), &CVehicle::Destroy) - /* Properties */ + // Properties .Prop(_SC("SyncSource"), &CVehicle::GetSyncSource) .Prop(_SC("SyncType"), &CVehicle::GetSyncType) .Prop(_SC("World"), &CVehicle::GetWorld, &CVehicle::SetWorld) @@ -946,7 +1290,7 @@ void Register_CVehicle(HSQUIRRELVM vm) .Prop(_SC("EX"), &CVehicle::GetERotX, &CVehicle::SetERotX) .Prop(_SC("EY"), &CVehicle::GetERotY, &CVehicle::SetERotY) .Prop(_SC("EZ"), &CVehicle::GetERotZ, &CVehicle::SetERotZ) - /* Functions */ + // Functions .Func(_SC("StreamedFor"), &CVehicle::IsStreamedFor) .Func(_SC("Occupant"), &CVehicle::GetOccupant) .Func(_SC("OccupantID"), &CVehicle::GetOccupantID) @@ -975,7 +1319,7 @@ void Register_CVehicle(HSQUIRRELVM vm) .Func(_SC("ExistsHandling"), &CVehicle::ExistsHandling) .Func(_SC("GetHandlingData"), &CVehicle::GetHandlingData) .Func(_SC("SetHandlingData"), &CVehicle::SetHandlingData) - /* Overloads */ + // Overloads .Overload< void (CVehicle::*)(const Vector3 &, bool) const > (_SC("SetPos"), &CVehicle::SetPositionEx) .Overload< void (CVehicle::*)(Float32, Float32, Float32) const > @@ -1012,17 +1356,16 @@ void Register_CVehicle(HSQUIRRELVM vm) (_SC("Embark"), &CVehicle::Embark) .Overload< void (CVehicle::*)(CPlayer &, Int32, bool, bool) const > (_SC("Embark"), &CVehicle::Embark) + // Static Overloads + .StaticOverload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Float32, Int32, Int32) > + (_SC("CreateEx"), &Vehicle_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Float32, Int32, Int32, Int32, Object &) > + (_SC("CreateEx"), &Vehicle_CreateEx) + .StaticOverload< Object & (*)(Int32, Int32, const Vector3 &, Float32, Int32, Int32) > + (_SC("Create"), &Vehicle_Create) + .StaticOverload< Object & (*)(Int32, Int32, const Vector3 &, Float32, Int32, Int32, Int32, Object &) > + (_SC("Create"), &Vehicle_Create) ); - - RootTable(vm) - .Overload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Float32, Int32, Int32) > - (_SC("CreateVehicleEx"), &CreateVehicleEx) - .Overload< Object & (*)(Int32, Int32, Float32, Float32, Float32, Float32, Int32, Int32, Int32, Object &) > - (_SC("CreateVehicleEx"), &CreateVehicleEx) - .Overload< Object & (*)(Int32, Int32, const Vector3 &, Float32, Int32, Int32) > - (_SC("CreateVehicle"), &CreateVehicle) - .Overload< Object & (*)(Int32, Int32, const Vector3 &, Float32, Int32, Int32, Int32, Object &) > - (_SC("CreateVehicle"), &CreateVehicle); } -} // Namespace:: SqMod \ No newline at end of file +} // Namespace:: SqMod diff --git a/source/Entity/Vehicle.hpp b/source/Entity/Vehicle.hpp index f6591a80..9536a7b2 100644 --- a/source/Entity/Vehicle.hpp +++ b/source/Entity/Vehicle.hpp @@ -8,7 +8,7 @@ namespace SqMod { /* ------------------------------------------------------------------------------------------------ - * Manages Vehicle instances. + * Manages a single vehicle entity. */ class CVehicle { @@ -22,20 +22,19 @@ private: static Vector4 s_Vector4; static Quaternion s_Quaternion; - /* -------------------------------------------------------------------------------------------- - * Cached identifiers for fast integer to string conversion. - */ - static SQChar s_StrID[SQMOD_VEHICLE_POOL][8]; - /* -------------------------------------------------------------------------------------------- * Identifier of the managed entity. */ Int32 m_ID; /* -------------------------------------------------------------------------------------------- - * User tag and data associated with this instance. + * User tag associated with this instance. */ String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * User data associated with this instance. + */ Object m_Data; /* -------------------------------------------------------------------------------------------- @@ -43,35 +42,45 @@ private: */ CVehicle(Int32 id); +public: + + /* -------------------------------------------------------------------------------------------- + * Maximum possible number that could represent an identifier for this entity type. + */ + static const Int32 Max; + /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ - CVehicle(const CVehicle &); + CVehicle(const CVehicle &) = delete; /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) + * Move constructor. (disabled) */ - CVehicle & operator = (const CVehicle &); - -public: - - // -------------------------------------------------------------------------------------------- - static const Int32 Max; + CVehicle(CVehicle &&) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~CVehicle(); + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + CVehicle & operator = (const CVehicle &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + CVehicle & operator = (CVehicle &&) = delete; + /* -------------------------------------------------------------------------------------------- * See whether this instance manages a valid entity. */ - bool Validate() const + void Validate() const { - if (VALID_ENTITY(m_ID)) - return true; - SqThrow("Invalid vehicle reference [%s]", m_Tag.c_str()); - return false; + if (INVALID_ENTITY(m_ID)) + SqThrowF("Invalid vehicle reference [%s]", m_Tag.c_str()); } /* -------------------------------------------------------------------------------------------- @@ -82,27 +91,33 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); /* -------------------------------------------------------------------------------------------- * Retrieve the identifier of the entity managed by this instance. */ - Int32 GetID() const { return m_ID; } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the maximum possible identifier to an entity of this type. - */ - Int32 GetMaxID() const { return SQMOD_VEHICLE_POOL; } + Int32 GetID() const + { + return m_ID; + } /* -------------------------------------------------------------------------------------------- * Check whether this instance manages a valid entity. */ - bool IsActive() const { return VALID_ENTITY(m_ID); } + bool IsActive() const + { + return VALID_ENTITY(m_ID); + } /* -------------------------------------------------------------------------------------------- * Retrieve the associated user tag. */ - CSStr GetTag() const; + const String & GetTag() const; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. @@ -119,126 +134,560 @@ public: */ void SetData(Object & data); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Destroy the managed vehicle entity. + */ + bool Destroy() + { + return Destroy(0, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed vehicle entity. + */ + bool Destroy(Int32 header) + { + return Destroy(header, NullObject()); + } + + /* -------------------------------------------------------------------------------------------- + * Destroy the managed vehicle entity. + */ bool Destroy(Int32 header, Object & payload); - bool Destroy() { return Destroy(0, NullObject()); } - bool Destroy(Int32 header) { return Destroy(header, NullObject()); } - // -------------------------------------------------------------------------------------------- - bool BindEvent(Int32 evid, Object & env, Function & func) const; + /* -------------------------------------------------------------------------------------------- + * Bind to an event supported by this entity type. + */ + void BindEvent(Int32 evid, Object & env, Function & func) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * See if the managed vehicle entity is streamed for the specified player. + */ bool IsStreamedFor(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the synchronization source of the managed vehicle entity. + */ Int32 GetSyncSource() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the synchronization type of the managed vehicle entity. + */ Int32 GetSyncType() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the world in which the managed vehicle entity exists. + */ Int32 GetWorld() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the world in which the managed vehicle entity exists. + */ void SetWorld(Int32 world) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the vehicle model of the managed vehicle entity. + */ Int32 GetModel() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the slot occupant from the managed vehicle entity. + */ Object & GetOccupant(Int32 slot) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the slot occupant identifier from the managed vehicle entity. + */ Int32 GetOccupantID(Int32 slot) const; + + /* -------------------------------------------------------------------------------------------- + * Respawn the managed vehicle entity. + */ void Respawn() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the immunity flags of the managed vehicle entity. + */ Int32 GetImmunity() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the immunity flags of the managed vehicle entity. + */ void SetImmunity(Int32 flags) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed vehicle entity is wrecked. + */ bool IsWrecked() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position of the managed vehicle entity. + */ const Vector3 & GetPosition() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed vehicle entity. + */ void SetPosition(const Vector3 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed vehicle entity. + */ void SetPositionEx(const Vector3 & pos, bool empty) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed vehicle entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position of the managed vehicle entity. + */ void SetPositionEx(Float32 x, Float32 y, Float32 z, bool empty) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation of the managed vehicle entity. + */ const Quaternion & GetRotation() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the rotation of the managed vehicle entity. + */ void SetRotation(const Quaternion & rot) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the rotation of the managed vehicle entity. + */ void SetRotationEx(Float32 x, Float32 y, Float32 z, Float32 w) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation of the managed vehicle entity. + */ const Vector3 & GetRotationEuler() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler rotation of the managed vehicle entity. + */ void SetRotationEuler(const Vector3 & rot) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler rotation of the managed vehicle entity. + */ void SetRotationEulerEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the speed of the managed vehicle entity. + */ const Vector3 & GetSpeed() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed vehicle entity. + */ void SetSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed vehicle entity. + */ void SetSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed vehicle entity. + */ void AddSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the speed of the managed vehicle entity. + */ void AddSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the relative speed of the managed vehicle entity. + */ const Vector3 & GetRelSpeed() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative speed of the managed vehicle entity. + */ void SetRelSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative speed of the managed vehicle entity. + */ void SetRelSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative speed of the managed vehicle entity. + */ void AddRelSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative speed of the managed vehicle entity. + */ void AddRelSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the turn speed of the managed vehicle entity. + */ const Vector3 & GetTurnSpeed() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the turn speed of the managed vehicle entity. + */ void SetTurnSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the turn speed of the managed vehicle entity. + */ void SetTurnSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the turn speed of the managed vehicle entity. + */ void AddTurnSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the turn speed of the managed vehicle entity. + */ void AddTurnSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the relative turn speed of the managed vehicle entity. + */ const Vector3 & GetRelTurnSpeed() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative turn speed of the managed vehicle entity. + */ void SetRelTurnSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative turn speed of the managed vehicle entity. + */ void SetRelTurnSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative turn speed of the managed vehicle entity. + */ void AddRelTurnSpeed(const Vector3 & vel) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the relative turn speed of the managed vehicle entity. + */ void AddRelTurnSpeedEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the spawn position of the managed vehicle entity. + */ const Vector4 & GetSpawnPosition() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the spawn position of the managed vehicle entity. + */ void SetSpawnPosition(const Vector4 & pos) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the spawn position of the managed vehicle entity. + */ void SetSpawnPositionEx(Float32 x, Float32 y, Float32 z, Float32 w) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the spawn rotation of the managed vehicle entity. + */ const Quaternion & GetSpawnRotation() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the spawn rotation of the managed vehicle entity. + */ void SetSpawnRotation(const Quaternion & rot) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the spawn rotation of the managed vehicle entity. + */ void SetSpawnRotationEx(Float32 x, Float32 y, Float32 z, Float32 w) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler spawn rotation of the managed vehicle entity. + */ const Vector3 & GetSpawnRotationEuler() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler spawn rotation of the managed vehicle entity. + */ void SetSpawnRotationEuler(const Vector3 & rot) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler spawn rotation of the managed vehicle entity. + */ void SetSpawnRotationEulerEx(Float32 x, Float32 y, Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the respawn timer of the managed vehicle entity. + */ Uint32 GetRespawnTimer() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the respawn timer of the managed vehicle entity. + */ void SetRespawnTimer(Uint32 timer) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the health of the managed vehicle entity. + */ Float32 GetHealth() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the health of the managed vehicle entity. + */ void SetHealth(Float32 amount) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the primary color of the managed vehicle entity. + */ Int32 GetPrimaryColor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the primary color of the managed vehicle entity. + */ void SetPrimaryColor(Int32 col) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the secondary color of the managed vehicle entity. + */ Int32 GetSecondaryColor() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the secondary color of the managed vehicle entity. + */ void SetSecondaryColor(Int32 col) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the primary and secondary colors of the managed vehicle entity. + */ void SetColors(Int32 primary, Int32 secondary) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed vehicle entity is locked. + */ bool GetLocked() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed vehicle entity is locked. + */ void SetLocked(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the part status of the managed vehicle entity. + */ Int32 GetPartStatus(Int32 part) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the part status of the managed vehicle entity. + */ void SetPartStatus(Int32 part, Int32 status) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the tyre status of the managed vehicle entity. + */ Int32 GetTyreStatus(Int32 tyre) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the tyre status of the managed vehicle entity. + */ void SetTyreStatus(Int32 tyre, Int32 status) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the damage data of the managed vehicle entity. + */ Uint32 GetDamageData() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the damage data of the managed vehicle entity. + */ void SetDamageData(Uint32 data) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed vehicle entity has alarm. + */ bool GetAlarm() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed vehicle entity has alarm. + */ void SetAlarm(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed vehicle entity has lights. + */ bool GetLights() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed vehicle entity has lights. + */ void SetLights(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the radio of the managed vehicle entity. + */ Int32 GetRadio() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the radio of the managed vehicle entity. + */ void SetRadio(Int32 radio) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed vehicle entity has radio locked. + */ bool GetRadioLocked() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed vehicle entity has radio locked. + */ void SetRadioLocked(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the managed vehicle entity is in ghost state. + */ bool GetGhostState() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the managed vehicle entity is in ghost state. + */ void SetGhostState(bool toggle) const; + + /* -------------------------------------------------------------------------------------------- + * Reset all the handling rules for the managed vehicle entity. + */ void ResetHandling() const; + + /* -------------------------------------------------------------------------------------------- + * Reset the specified handling rule for the managed vehicle entity. + */ void ResetHandling(Int32 rule) const; + + /* -------------------------------------------------------------------------------------------- + * See whether the specified handling ruleexists in the managed vehicle entity. + */ bool ExistsHandling(Int32 rule) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the handling data of the managed vehicle entity. + */ Float32 GetHandlingData(Int32 rule) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the handling data of the managed vehicle entity. + */ void SetHandlingData(Int32 rule, Float32 data) const; + + /* -------------------------------------------------------------------------------------------- + * Embark the specified player entity into the managed vehicle entity. + */ void Embark(CPlayer & player) const; + + /* -------------------------------------------------------------------------------------------- + * Embark the specified player entity into the managed vehicle entity. + */ void Embark(CPlayer & player, Int32 slot, bool allocate, bool warp) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the x axis of the managed vehicle entity. + */ Float32 GetPosX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the y axis of the managed vehicle entity. + */ Float32 GetPosY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the position on the z axis of the managed vehicle entity. + */ Float32 GetPosZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the x axis of the managed vehicle entity. + */ void SetPosX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the y axis of the managed vehicle entity. + */ void SetPosY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the position on the z axis of the managed vehicle entity. + */ void SetPosZ(Float32 z) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation on the x axis of the managed vehicle entity. + */ Float32 GetRotX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation on the y axis of the managed vehicle entity. + */ Float32 GetRotY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation on the z axis of the managed vehicle entity. + */ Float32 GetRotZ() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the rotation amount of the managed vehicle entity. + */ Float32 GetRotW() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the rotation on the x axis of the managed vehicle entity. + */ void SetRotX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the rotation on the y axis of the managed vehicle entity. + */ void SetRotY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the rotation on the z axis of the managed vehicle entity. + */ void SetRotZ(Float32 z) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the rotation amount of the managed vehicle entity. + */ void SetRotW(Float32 w) const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation on the x axis of the managed vehicle entity. + */ Float32 GetERotX() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation on the y axis of the managed vehicle entity. + */ Float32 GetERotY() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the euler rotation on the z axis of the managed vehicle entity. + */ Float32 GetERotZ() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler rotation on the x axis of the managed vehicle entity. + */ void SetERotX(Float32 x) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler rotation on the y axis of the managed vehicle entity. + */ void SetERotY(Float32 y) const; + + /* -------------------------------------------------------------------------------------------- + * Modify the euler rotation on the z axis of the managed vehicle entity. + */ void SetERotZ(Float32 z) const; }; diff --git a/source/Exports.cpp b/source/Exports.cpp index 86754fb5..18049d27 100644 --- a/source/Exports.cpp +++ b/source/Exports.cpp @@ -36,6 +36,16 @@ static HSQUIRRELVM GetSquirrelVM() return NULL; } +// ------------------------------------------------------------------------------------------------ +static SQRESULT SqEx_LoadScript(const SQChar * filepath) +{ + // Attempt to add the specified script to the load queue + if (_Core->LoadScript(filepath)) + return SQ_OK; // The script as added or already existed + // The path was invalied or was unable to pool the script + return SQ_ERROR; +} + // ------------------------------------------------------------------------------------------------ static SQRESULT SqEx_GetSLongValue(HSQUIRRELVM vm, SQInteger idx, Int64 * num) { @@ -210,11 +220,11 @@ void InitExports() static HSQEXPORTS sqexports = &g_SqExports; // Assign the functions that should be exported - g_SqExports.uStructSize = sizeof(SQEXPORTS); + g_SqExports.StructSize = sizeof(SQEXPORTS); g_SqExports.GetSquirrelAPI = GetSquirrelAPI; g_SqExports.GetSquirrelVM = GetSquirrelVM; - /*logging utilities*/ + //logging utilities g_SqExports.LogDbg = LogDbg; g_SqExports.LogUsr = LogUsr; g_SqExports.LogScs = LogScs; @@ -230,13 +240,16 @@ void InitExports() g_SqExports.LogSErr = LogSErr; g_SqExports.LogSFtl = LogSFtl; - /*long numbers*/ + //script loading + g_SqExports.LoadScript = SqEx_LoadScript; + + //long numbers g_SqExports.GetSLongValue = SqEx_GetSLongValue; g_SqExports.PushSLongObject = SqEx_PushSLongObject; g_SqExports.GetULongValue = SqEx_GetULongValue; g_SqExports.PushULongObject = SqEx_PushULongObject; - /*time utilities*/ + //time utilities g_SqExports.GetCurrentSysTime = GetCurrentSysTime; g_SqExports.GetEpochTimeMicro = GetEpochTimeMicro; g_SqExports.GetEpochTimeMilli = GetEpochTimeMilli; @@ -246,7 +259,7 @@ void InitExports() // Export them to the server _Func->ExportFunctions(_Info->nPluginId, (void **)(&sqexports), sizeof(SQEXPORTS)); - /*vm*/ + //vm g_SqAPI.open = sq_open; g_SqAPI.newthread = sq_newthread; g_SqAPI.seterrorhandler = sq_seterrorhandler; @@ -267,14 +280,14 @@ void InitExports() g_SqAPI.getvmstate = sq_getvmstate; g_SqAPI.getversion = sq_getversion; - /*compiler*/ + //compiler g_SqAPI.compile = sq_compile; g_SqAPI.compilebuffer = sq_compilebuffer; g_SqAPI.enabledebuginfo = sq_enabledebuginfo; g_SqAPI.notifyallexceptions = sq_notifyallexceptions; g_SqAPI.setcompilererrorhandler = sq_setcompilererrorhandler; - /*stack operations*/ + //stack operations g_SqAPI.push = sq_push; g_SqAPI.pop = sq_pop; g_SqAPI.poptop = sq_poptop; @@ -285,7 +298,7 @@ void InitExports() g_SqAPI.cmp = sq_cmp; g_SqAPI.move = sq_move; - /*object creation handling*/ + //object creation handling g_SqAPI.newuserdata = sq_newuserdata; g_SqAPI.newtable = sq_newtable; g_SqAPI.newtableex = sq_newtableex; @@ -340,7 +353,7 @@ void InitExports() g_SqAPI.getbyhandle = sq_getbyhandle; g_SqAPI.setbyhandle = sq_setbyhandle; - /*object manipulation*/ + //object manipulation g_SqAPI.pushroottable = sq_pushroottable; g_SqAPI.pushregistrytable = sq_pushregistrytable; g_SqAPI.pushconsttable = sq_pushconsttable; @@ -369,7 +382,7 @@ void InitExports() g_SqAPI.getweakrefval = sq_getweakrefval; g_SqAPI.clear = sq_clear; - /*calls*/ + //calls g_SqAPI.call = sq_call; g_SqAPI.resume = sq_resume; g_SqAPI.getlocal = sq_getlocal; @@ -380,7 +393,7 @@ void InitExports() g_SqAPI.reseterror = sq_reseterror; g_SqAPI.getlasterror = sq_getlasterror; - /*raw object handling*/ + //raw object handling g_SqAPI.getstackobj = sq_getstackobj; g_SqAPI.pushobject = sq_pushobject; g_SqAPI.addref = sq_addref; @@ -395,35 +408,35 @@ void InitExports() g_SqAPI.getobjtypetag = sq_getobjtypetag; g_SqAPI.getvmrefcount = sq_getvmrefcount; - /*GC*/ + //GC g_SqAPI.collectgarbage = sq_collectgarbage; g_SqAPI.resurrectunreachable = sq_resurrectunreachable; - /*serialization*/ + //serialization g_SqAPI.writeclosure = sq_writeclosure; g_SqAPI.readclosure = sq_readclosure; - /*mem allocation*/ + //mem allocation g_SqAPI.malloc = sq_malloc; g_SqAPI.realloc = sq_realloc; g_SqAPI.free = sq_free; - /*debug*/ + //debug g_SqAPI.stackinfos = sq_stackinfos; g_SqAPI.setdebughook = sq_setdebughook; g_SqAPI.setnativedebughook = sq_setnativedebughook; - /*compiler helpers*/ + //compiler helpers g_SqAPI.loadfile = sqstd_loadfile; g_SqAPI.dofile = sqstd_dofile; g_SqAPI.writeclosuretofile = sqstd_writeclosuretofile; - /*blob*/ + //blob g_SqAPI.createblob = sqstd_createblob; g_SqAPI.getblob = sqstd_getblob; g_SqAPI.getblobsize = sqstd_getblobsize; - /*string*/ + //string g_SqAPI.format = sqstd_format; } diff --git a/source/Library/Crypt.cpp b/source/Library/Crypt.cpp new file mode 100644 index 00000000..78942f41 --- /dev/null +++ b/source/Library/Crypt.cpp @@ -0,0 +1,239 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/Crypt.hpp" +#include "Base/Shared.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger AES256::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqAES"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + +// ------------------------------------------------------------------------------------------------ +AES256::AES256() + : m_Context(), m_Buffer() +{ + aes256_done(&m_Context); +} + +// ------------------------------------------------------------------------------------------------ +AES256::AES256(CSStr key) + : m_Context(), m_Buffer() +{ + Init(key); +} + +// ------------------------------------------------------------------------------------------------ +Int32 AES256::Cmp(const AES256 & o) const +{ + return memcmp(m_Buffer, o.m_Buffer, sizeof(m_Buffer)); +} + +// ------------------------------------------------------------------------------------------------ +CSStr AES256::ToString() const +{ + return ToStrF("%s", m_Buffer); +} + +// ------------------------------------------------------------------------------------------------ +CSStr AES256::GetKey() const +{ + return reinterpret_cast< CSStr >(m_Buffer); +} + +// ------------------------------------------------------------------------------------------------ +void AES256::Init(CSStr key) +{ + // Clear current key, if any + aes256_done(&m_Context); + // Is the specified key empty? + if (!key || *key == 0) + return; // Leave the context with an empty key + // Obtain the specified key size + const Uint32 size = (strlen(key) * sizeof(SQChar)); + // See if the key size is accepted + if (size > sizeof(m_Buffer)) + SqThrowF("The specified key is out of bounds: %u > %u", size, sizeof(m_Buffer)); + // Initialize the key buffer to 0 + memset(m_Buffer, 0, sizeof(m_Buffer)); + // Copy the key into the key buffer + memcpy(m_Buffer, key, size); + // Initialize the context with the specified key + aes256_init(&m_Context, m_Buffer); +} + +// ------------------------------------------------------------------------------------------------ +void AES256::Done() +{ + aes256_done(&m_Context); +} + +// ------------------------------------------------------------------------------------------------ +String AES256::Encrypt(CSStr data) +{ + // Is there any data to encrypt? + if (!data || *data == 0) + return String(); + // Copy the data into an editable string + String str(data); + // Make sure that we have a size with a multiple of 16 + if ((str.size() % 16) != 0) + str.resize(str.size() - (str.size() % 16) + 16); + // Encrypt in chunks of 16 characters + for (Uint32 n = 0; n < str.size(); n += 16) + aes256_encrypt_ecb(&m_Context, reinterpret_cast< Uint8 * >(&str[n])); + // Return ownership of the encrypted string + return std::move(str); +} + +// ------------------------------------------------------------------------------------------------ +String AES256::Decrypt(CSStr data) +{ + // Is there any data to decrypt? + if (!data || *data == 0) + return String(); + // Copy the data into an editable string + String str(data); + // Make sure that we have a size with a multiple of 16 + if ((str.size() % 16) != 0) + str.resize(str.size() - (str.size() % 16) + 16); + // Decrypt inc chunks of 16 characters + for (Uint32 n = 0; n < str.size(); n += 16) + aes256_decrypt_ecb(&m_Context, reinterpret_cast< Uint8 * >(&str[n])); + // Remove null characters in case the string was not a multiple of 16 when encrypted + while (!str.empty() && str.back() == 0) + str.pop_back(); + // Return ownership of the encrypted string + return std::move(str); +} + +/* ------------------------------------------------------------------------------------------------ + * Utility to avoid creating encoder instances for each call. +*/ +template < class T > struct BaseHash +{ + static T Algo; +}; + +// ------------------------------------------------------------------------------------------------ +template < class T > T BaseHash< T >::Algo; + +/* ------------------------------------------------------------------------------------------------ + * Hash the specified value or the result of a formatted string. +*/ +template < class T > static SQInteger HashF(HSQUIRRELVM vm) +{ + const Int32 top = sq_gettop(vm); + // Was the hash value specified? + if (top <= 1) + return sq_throwerror(vm, "Missing hash value"); + // Do we have enough values to call the format function? + else if (top > 2) + { + SStr val = NULL; + SQInteger len = 0; + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 2, &len, &val); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Hash the resulted string + String str(BaseHash< T >::Algo(val)); + // Push the string on the stack + sq_pushstring(vm, str.data(), str.size()); + } + else + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > val(vm, 2); + // See if the obtained value is a valid string + if (!val.value) + return sq_throwerror(vm, "Unable to retrieve the value"); + // Hash the resulted string + String str(BaseHash< T >::Algo(val.value)); + // Push the string on the stack + sq_pushstring(vm, str.data(), str.size()); + } + // At this point we have a valid string on the stack + return 1; +} + +// ================================================================================================ +template < class T > static void RegisterWrapper(Table & hashns, CCStr cname) +{ + typedef HashWrapper< T > Hash; + hashns.Bind(cname, Class< Hash >(hashns.GetVM(), cname) + /* Constructors */ + .Ctor() + /* Metamethods */ + .Func(_SC("_tostring"), &Hash::ToString) + /* Properties */ + .Prop(_SC("Hash"), &Hash::GetHash) + /* Functions */ + .Func(_SC("Reset"), &Hash::Reset) + .Func(_SC("Compute"), &Hash::Compute) + .Func(_SC("GetHash"), &Hash::GetHash) + .Func(_SC("Add"), &Hash::AddStr) + .Func(_SC("AddStr"), &Hash::AddStr) + ); +} + +// ================================================================================================ +void Register_Crypt(HSQUIRRELVM vm) +{ + Table hashns(vm); + + RegisterWrapper< CRC32 >(hashns, _SC("CRC32")); + RegisterWrapper< Keccak >(hashns, _SC("Keccak")); + RegisterWrapper< MD5 >(hashns, _SC("MD5")); + RegisterWrapper< SHA1 >(hashns, _SC("SHA1")); + RegisterWrapper< SHA256 >(hashns, _SC("SHA256")); + RegisterWrapper< SHA3 >(hashns, _SC("SHA3")); + + hashns.SquirrelFunc(_SC("GetCRC32"), &HashF< CRC32 >); + hashns.SquirrelFunc(_SC("GetKeccak"), &HashF< Keccak >); + hashns.SquirrelFunc(_SC("GetMD5"), &HashF< MD5 >); + hashns.SquirrelFunc(_SC("GetSHA1"), &HashF< SHA1 >); + hashns.SquirrelFunc(_SC("GetSHA256"), &HashF< SHA256 >); + hashns.SquirrelFunc(_SC("GetSHA3"), &HashF< SHA3 >); + + RootTable(vm).Bind(_SC("SqHash"), hashns); + + RootTable(vm).Bind("SqAES256", Class< AES256 >(vm, "SqAES256") + /* Constructors */ + .Ctor() + .Ctor< CSStr >() + /* Metamethods */ + .Func(_SC("_cmp"), &AES256::Cmp) + .SquirrelFunc(_SC("_typename"), &AES256::Typename) + .Func(_SC("_tostring"), &AES256::ToString) + /* Properties */ + .Prop(_SC("Key"), &AES256::GetKey) + /* Functions */ + .Func(_SC("Init"), &AES256::Init) + .Func(_SC("Done"), &AES256::Done) + .Func(_SC("Encrypt"), &AES256::Encrypt) + .Func(_SC("Decrypt"), &AES256::Decrypt) + ); +} + +} // Namespace:: SqMod diff --git a/source/Library/Crypt.hpp b/source/Library/Crypt.hpp new file mode 100644 index 00000000..8cb553cd --- /dev/null +++ b/source/Library/Crypt.hpp @@ -0,0 +1,200 @@ +#ifndef _LIBRARY_CRYPT_HPP_ +#define _LIBRARY_CRYPT_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "SqBase.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Simple class to maintain the state of an encoder. +*/ +template < class T > class HashWrapper +{ +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + HashWrapper() + : m_Encoder() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy operator. + */ + HashWrapper(const HashWrapper & o) + : m_Encoder(o.m_Encoder) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~HashWrapper() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + HashWrapper & operator = (const HashWrapper & o) + { + m_Encoder = o.m_Encoder; + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + String ToString() + { + return m_Encoder.getHash(); + } + + /* -------------------------------------------------------------------------------------------- + * Reset the encoder state. + */ + void Reset() + { + m_Encoder.reset(); + } + + /* -------------------------------------------------------------------------------------------- + * Compute the hash of the specified string. + */ + String Compute(const String & str) + { + return m_Encoder(str); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the hash value of the data hashed so far. + */ + String GetHash() + { + return m_Encoder.getHash(); + } + + /* -------------------------------------------------------------------------------------------- + * Add a string value to be hashed. + */ + void AddStr(const String & str) + { + m_Encoder.add(str.data(), str.length() * sizeof(String::value_type)); + } + +private: + + /* -------------------------------------------------------------------------------------------- + * The managed encoder state. + */ + T m_Encoder; +}; + +/* ------------------------------------------------------------------------------------------------ + * Simple wrapper around a the AES encryption context. +*/ +class AES256 +{ +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + AES256(); + + /* -------------------------------------------------------------------------------------------- + * Construct with an explicit key. + */ + AES256(CSStr key); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + AES256(const AES256 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + AES256(AES256 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~AES256() = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + AES256 & operator = (const AES256 & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + AES256 & operator = (AES256 && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const AES256 & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated key. + */ + CSStr GetKey() const; + + /* -------------------------------------------------------------------------------------------- + * Initialize the context key. + */ + void Init(CSStr key); + + /* -------------------------------------------------------------------------------------------- + * Reset the associated context. + */ + void Done(); + + /* -------------------------------------------------------------------------------------------- + * Encrypt the specified string. + */ + String Encrypt(CSStr data); + + /* -------------------------------------------------------------------------------------------- + * Decrypt the specified string. + */ + String Decrypt(CSStr data); + +private: + + /* -------------------------------------------------------------------------------------------- + * The managed encryption context. + */ + aes256_context m_Context; + + /* -------------------------------------------------------------------------------------------- + * The key used to encrypt data. + */ + Uint8 m_Buffer[32]{0}; +}; + +} // Namespace:: SqMod + +#endif // _LIBRARY_CRYPT_HPP_ diff --git a/source/Library/Hashing.cpp b/source/Library/Hashing.cpp deleted file mode 100644 index 4ee1c868..00000000 --- a/source/Library/Hashing.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/Hashing.hpp" -#include "Base/Shared.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -#include -#include -#include -#include -#include -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * ... -*/ -template < class T > struct BaseHash -{ - static T Algo; -}; - -// ------------------------------------------------------------------------------------------------ -template < class T > T BaseHash< T >::Algo; - -// ------------------------------------------------------------------------------------------------ -template < class T > static SQInteger HashF(HSQUIRRELVM vm) -{ - const Int32 top = sq_gettop(vm); - Object ret; - if (top <= 1) - SqThrow("Missing the hash string"); - else if (top == 2 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) - { - CCStr str = 0; - if (SQ_FAILED(sq_getstring(vm, -1, &str))) - SqThrow("Unable to retrieve the string"); - else - ret = MakeObject(vm, BaseHash< T >::Algo(str)); - sq_settop(vm, top); - } - else if (top > 2) - { - CStr str = NULL; - SQInteger len = 0; - if (SQ_FAILED(sqstd_format(vm, 2, &len, &str))) - SqThrow("Unable to generate the string [%s]", Error::Message(vm).c_str()); - else - ret = MakeObject(vm, BaseHash< T >::Algo(str)); - } - else - SqThrow("Unable to extract the hash string"); - Var< Object >::push(vm, ret); - return 1; -} - -// ================================================================================================ -template < class T > static void RegisterWrapper(Table & hashns, CCStr cname) -{ - typedef HashWrapper< T > Hash; - hashns.Bind(cname, Class< Hash >(hashns.GetVM(), cname) - /* Constructors */ - .Ctor() - /* Metamethods */ - .Func(_SC("_tostring"), &Hash::ToString) - /* Properties */ - .Prop(_SC("Hash"), &Hash::GetHash) - /* Functions */ - .Func(_SC("Reset"), &Hash::Reset) - .Func(_SC("Compute"), &Hash::Compute) - .Func(_SC("GetHash"), &Hash::GetHash) - .Func(_SC("Add"), &Hash::AddStr) - .Func(_SC("AddStr"), &Hash::AddStr) - ); -} - -// ================================================================================================ -void Register_Hash(HSQUIRRELVM vm) -{ - Table hashns(vm); - - RegisterWrapper< CRC32 >(hashns, _SC("CRC32")); - RegisterWrapper< Keccak >(hashns, _SC("Keccak")); - RegisterWrapper< MD5 >(hashns, _SC("MD5")); - RegisterWrapper< SHA1 >(hashns, _SC("SHA1")); - RegisterWrapper< SHA256 >(hashns, _SC("SHA256")); - RegisterWrapper< SHA3 >(hashns, _SC("SHA3")); - - hashns.SquirrelFunc(_SC("GetCRC32"), &HashF< CRC32 >); - hashns.SquirrelFunc(_SC("GetKeccak"), &HashF< Keccak >); - hashns.SquirrelFunc(_SC("GetMD5"), &HashF< MD5 >); - hashns.SquirrelFunc(_SC("GetSHA1"), &HashF< SHA1 >); - hashns.SquirrelFunc(_SC("GetSHA256"), &HashF< SHA256 >); - hashns.SquirrelFunc(_SC("GetSHA3"), &HashF< SHA3 >); - - RootTable(vm).Bind(_SC("SqHash"), hashns); -} - -} // Namespace:: SqMod diff --git a/source/Library/Hashing.hpp b/source/Library/Hashing.hpp deleted file mode 100644 index ed28f33c..00000000 --- a/source/Library/Hashing.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _LIBRARY_HASHING_HPP_ -#define _LIBRARY_HASHING_HPP_ - -// ------------------------------------------------------------------------------------------------ -#include "SqBase.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -template < class T > class HashWrapper -{ -public: - - // -------------------------------------------------------------------------------------------- - HashWrapper() - : m_Encoder() - { - - } - - // -------------------------------------------------------------------------------------------- - HashWrapper(const HashWrapper & o) - : m_Encoder(o.m_Encoder) - { - - } - - // -------------------------------------------------------------------------------------------- - ~HashWrapper() - { - - } - - // -------------------------------------------------------------------------------------------- - HashWrapper & operator = (const HashWrapper & o) - { - m_Encoder = o.m_Encoder; - return *this; - } - - // -------------------------------------------------------------------------------------------- - String ToString() { return m_Encoder.getHash(); } - void Reset() { m_Encoder.reset(); } - String Compute(const String & str) { return m_Encoder(str); } - String GetHash() { return m_Encoder.getHash(); } - void AddStr(const String & str) - { m_Encoder.add(str.data(), str.length() * sizeof(String::value_type)); } - -private: - - // -------------------------------------------------------------------------------------------- - T m_Encoder; -}; - -} // Namespace:: SqMod - -#endif // _LIBRARY_HASHING_HPP_ diff --git a/source/Library/Random.cpp b/source/Library/Random.cpp index 298773e6..4ee0b588 100644 --- a/source/Library/Random.cpp +++ b/source/Library/Random.cpp @@ -4,11 +4,12 @@ #include "Base/Buffer.hpp" // ------------------------------------------------------------------------------------------------ -#include +#include +#include +#include +#include // ------------------------------------------------------------------------------------------------ -#include -#include #ifdef SQMOD_OS_WINDOWS #include #else @@ -17,10 +18,45 @@ #endif // ------------------------------------------------------------------------------------------------ -RandomLib::Random g_RGen; +namespace SqMod { // ------------------------------------------------------------------------------------------------ -namespace SqMod { +static std::unique_ptr< std::mt19937 > RG32_MT19937 = + std::unique_ptr< std::mt19937 >(new std::mt19937(GenerateSeed())); + +static std::unique_ptr< std::mt19937_64 > RG64_MT19937 = + std::unique_ptr< std::mt19937_64 >(new std::mt19937_64(GenerateSeed())); + +// ------------------------------------------------------------------------------------------------ +static std::uniform_int_distribution< Int8 > Int8_Dist(std::numeric_limits< Int8 >::min(), + std::numeric_limits< Int8 >::max()); +static std::uniform_int_distribution< Uint8 > Uint8_Dist(std::numeric_limits< Uint8 >::min(), + std::numeric_limits< Uint8 >::max()); + +static std::uniform_int_distribution< Int16 > Int16_Dist(std::numeric_limits< Int16 >::min(), + std::numeric_limits< Int16 >::max()); +static std::uniform_int_distribution< Uint16 > Uint16_Dist(std::numeric_limits< Uint16 >::min(), + std::numeric_limits< Uint16 >::max()); + +static std::uniform_int_distribution< Int32 > Int32_Dist(std::numeric_limits< Int32 >::min(), + std::numeric_limits< Int32 >::max()); +static std::uniform_int_distribution< Uint32 > Uint32_Dist(std::numeric_limits< Uint32 >::min(), + std::numeric_limits< Uint32 >::max()); + +static std::uniform_int_distribution< Int64 > Int64_Dist(std::numeric_limits< Int64 >::min(), + std::numeric_limits< Int64 >::max()); +static std::uniform_int_distribution< Uint64 > Uint64_Dist(std::numeric_limits< Uint64 >::min(), + std::numeric_limits< Uint64 >::max()); + +static std::uniform_real_distribution Float32_Dist(std::numeric_limits< Float32 >::min(), + std::numeric_limits< Float32 >::max()); +static std::uniform_real_distribution Float64_Dist(std::numeric_limits< Float64 >::min(), + std::numeric_limits< Float64 >::max()); + +// ------------------------------------------------------------------------------------------------ +static std::uniform_int_distribution< String::value_type > + String_Dist(std::numeric_limits< String::value_type >::min(), + std::numeric_limits< String::value_type >::max()); // ------------------------------------------------------------------------------------------------ SizeT GenerateSeed() @@ -49,309 +85,296 @@ SizeT GenerateSeed() // ------------------------------------------------------------------------------------------------ void ReseedRandom() { - g_RGen.Reseed(); + RG32_MT19937.reset(new std::mt19937(GenerateSeed())); + RG64_MT19937.reset(new std::mt19937_64(GenerateSeed())); } void ReseedRandom(Uint32 n) { - g_RGen.Reseed(n); + RG32_MT19937.reset(new std::mt19937(n)); + RG64_MT19937.reset(new std::mt19937_64(n)); +} + +// ------------------------------------------------------------------------------------------------ +void ReseedRandom32() +{ + RG32_MT19937.reset(new std::mt19937(GenerateSeed())); +} + +void ReseedRandom32(Uint32 n) +{ + RG32_MT19937.reset(new std::mt19937(n)); +} + +// ------------------------------------------------------------------------------------------------ +void ReseedRandom64() +{ + RG64_MT19937.reset(new std::mt19937_64(GenerateSeed())); +} + +void ReseedRandom64(Uint32 n) +{ + RG64_MT19937.reset(new std::mt19937_64(n)); } // ------------------------------------------------------------------------------------------------ Int8 GetRandomInt8() { - return g_RGen.Integer< Int8 >(); + return Int8_Dist(*RG32_MT19937); } Int8 GetRandomInt8(Int8 n) { - return g_RGen.Integer< Int8 >(n); + return std::uniform_int_distribution< Int8 >(0, n)(*RG32_MT19937); } Int8 GetRandomInt8(Int8 m, Int8 n) { - return g_RGen.IntegerC< Int8 >(m, n); + return std::uniform_int_distribution< Int8 >(m, n)(*RG32_MT19937); } // ------------------------------------------------------------------------------------------------ Uint8 GetRandomUint8() { - return g_RGen.Integer< Uint8 >(); + return Uint8_Dist(*RG32_MT19937); } Uint8 GetRandomUint8(Uint8 n) { - return g_RGen.Integer< Uint8 >(n); + return std::uniform_int_distribution< Uint8 >(0, n)(*RG32_MT19937); } Uint8 GetRandomUint8(Uint8 m, Uint8 n) { - return g_RGen.IntegerC< Uint8 >(m, n); + return std::uniform_int_distribution< Uint8 >(m, n)(*RG32_MT19937); } - // ------------------------------------------------------------------------------------------------ Int16 GetRandomInt16() { - return g_RGen.Integer< Int16 >(); + return Int16_Dist(*RG32_MT19937); } Int16 GetRandomInt16(Int16 n) { - return g_RGen.Integer< Int16 >(n); + return std::uniform_int_distribution< Int16 >(0, n)(*RG32_MT19937); } Int16 GetRandomInt16(Int16 m, Int16 n) { - return g_RGen.IntegerC< Int16 >(m, n); + return std::uniform_int_distribution< Int16 >(m, n)(*RG32_MT19937); } - // ------------------------------------------------------------------------------------------------ Uint16 GetRandomUint16() { - return g_RGen.Integer< Uint16 >(); + return Uint16_Dist(*RG32_MT19937); } Uint16 GetRandomUint16(Uint16 n) { - return g_RGen.Integer< Uint16 >(n); + return std::uniform_int_distribution< Uint16 >(0, n)(*RG32_MT19937); } Uint16 GetRandomUint16(Uint16 m, Uint16 n) { - return g_RGen.IntegerC< Uint16 >(m, n); + return std::uniform_int_distribution< Uint16 >(m, n)(*RG32_MT19937); } - // ------------------------------------------------------------------------------------------------ Int32 GetRandomInt32() { - return g_RGen.Integer< Int32 >(); + return Int32_Dist(*RG32_MT19937); } Int32 GetRandomInt32(Int32 n) { - return g_RGen.Integer< Int32 >(n); + return std::uniform_int_distribution< Int32 >(0, n)(*RG32_MT19937); } Int32 GetRandomInt32(Int32 m, Int32 n) { - return g_RGen.IntegerC< Int32 >(m, n); + return std::uniform_int_distribution< Int32 >(m, n)(*RG32_MT19937); } // ------------------------------------------------------------------------------------------------ Uint32 GetRandomUint32() { - return g_RGen.Integer< Uint32 >(); + return Int32_Dist(*RG32_MT19937); } Uint32 GetRandomUint32(Uint32 n) { - return g_RGen.Integer< Uint32 >(n); + return std::uniform_int_distribution< Int32 >(0, n)(*RG32_MT19937); } Uint32 GetRandomUint32(Uint32 m, Uint32 n) { - return g_RGen.IntegerC< Uint32 >(m, n); + return std::uniform_int_distribution< Int32 >(m, n)(*RG32_MT19937); } // ------------------------------------------------------------------------------------------------ Int64 GetRandomInt64() { - return g_RGen.Integer< Int64 >(); + return Int64_Dist(*RG64_MT19937); } Int64 GetRandomInt64(Int64 n) { - return g_RGen.Integer< Int64 >(n); + return std::uniform_int_distribution< Int64 >(0, n)(*RG64_MT19937); } Int64 GetRandomInt64(Int64 m, Int64 n) { - return g_RGen.IntegerC< Int64 >(m, n); + return std::uniform_int_distribution< Int64 >(m, n)(*RG64_MT19937); } // ------------------------------------------------------------------------------------------------ Uint64 GetRandomUint64() { - return g_RGen.Integer< Uint64 >(); + return Uint64_Dist(*RG64_MT19937); } Uint64 GetRandomUint64(Uint64 n) { - return g_RGen.Integer< Uint64 >(n); + return std::uniform_int_distribution< Uint64 >(0, n)(*RG64_MT19937); } Uint64 GetRandomUint64(Uint64 m, Uint64 n) { - return g_RGen.IntegerC< Uint64 >(m, n); + return std::uniform_int_distribution< Uint64 >(m, n)(*RG64_MT19937); } // ------------------------------------------------------------------------------------------------ Float32 GetRandomFloat32() { - static const Float32 m = NumLimit::Min, n = NumLimit::Max; - return (n - m) * (Float32(g_RGen.IntegerC< Int16 >(0, NumLimit< Int16 >::Max)) / Float32(RAND_MAX)) + m; + return Float32_Dist(*RG32_MT19937); } Float32 GetRandomFloat32(Float32 n) { - return Float32(g_RGen.IntegerC< Int16 >(0, NumLimit< Int16 >::Max)) / Float32(RAND_MAX/n); + return std::uniform_real_distribution< Float32 >(0, n)(*RG32_MT19937); } Float32 GetRandomFloat32(Float32 m, Float32 n) { - return (n - m) * (Float32(g_RGen.IntegerC< Int16 >(0, NumLimit< Int16 >::Max)) / Float32(RAND_MAX)) + m; + return std::uniform_real_distribution< Float32 >(m, n)(*RG32_MT19937); } // ------------------------------------------------------------------------------------------------ Float64 GetRandomFloat64() { - static const Float64 m = NumLimit::Min, n = NumLimit::Max; - return (n - m) * (Float64(g_RGen.IntegerC< Int16 >(0, NumLimit< Int16 >::Max)) / Float64(RAND_MAX)) + m; + return Float64_Dist(*RG64_MT19937); } Float64 GetRandomFloat64(Float64 n) { - return Float64(g_RGen.IntegerC< Int16 >(0, NumLimit< Int16 >::Max)) / Float64(RAND_MAX/n); + return std::uniform_real_distribution< Float64 >(0, n)(*RG64_MT19937); } Float64 GetRandomFloat64(Float64 m, Float64 n) { - return (n - m) * (Float64(g_RGen.IntegerC< Int16 >(0, NumLimit< Int16 >::Max)) / Float64(RAND_MAX)) + m; + return std::uniform_real_distribution< Float64 >(m, n)(*RG64_MT19937); } // ------------------------------------------------------------------------------------------------ void GetRandomString(String & str, String::size_type len) { + // Reserve the requested size + the null terminator str.reserve(len+1); + // Resize to the requested size and fill with 0 str.resize(len); - for (String::iterator itr = str.begin(); itr != str.end(); ++itr) - { - *itr = g_RGen.Integer< String::value_type >(); - } + // Generate the requested amount of characters + for (auto & c : str) + c = String_Dist(*RG32_MT19937); + // Append the null terminator str.push_back(0); } void GetRandomString(String & str, String::size_type len, String::value_type n) { + // Reserve the requested size + the null terminator str.reserve(len+1); + // Resize to the requested size and fill with 0 str.resize(len); - for (String::iterator itr = str.begin(); itr != str.end(); ++itr) - { - *itr = g_RGen.Integer< String::value_type >(n); - } + // Create the custom distribution + std::uniform_int_distribution< String::value_type > dist(1, n); + // Generate the requested amount of characters + for (auto & c : str) + c = dist(*RG32_MT19937); + // Append the null terminator str.push_back(0); } void GetRandomString(String & str, String::size_type len, String::value_type m, String::value_type n) { + // Reserve the requested size + the null terminator str.reserve(len+1); + // Resize to the requested size and fill with 0 str.resize(len); - for (String::iterator itr = str.begin(); itr != str.end(); ++itr) - { - *itr = g_RGen.IntegerC< String::value_type >(m, n); - } + // Create the custom distribution + std::uniform_int_distribution< String::value_type > dist(m, n); + // Generate the requested amount of characters + for (auto & c : str) + c = dist(*RG32_MT19937); + // Append the null terminator str.push_back(0); } // ------------------------------------------------------------------------------------------------ bool GetRandomBool() { - return g_RGen.Boolean(); + return std::bernoulli_distribution()(*RG32_MT19937); +} + +bool GetRandomBool(SQFloat p) +{ + return std::bernoulli_distribution(p)(*RG32_MT19937); } // ------------------------------------------------------------------------------------------------ -template < typename T > static T RandomValue() -{ - return RandomVal< T >::Get(); -} - -template < typename T > static T RandomValue(T n) -{ - return RandomVal< T >::Get(n); -} - -template < typename T > static T RandomValue(T m, T n) -{ - return RandomVal< T >::Get(m, n); -} - -// ------------------------------------------------------------------------------------------------ -static CSStr RandomString(Int32 len) +static String RandomString(Int32 len) { + // Is there anything to generate? if (len <= 0) - { return _SC(""); - } - Buffer b(len+1); - SStr s = b.Get< SQChar >(); - for (Int32 n = 0; n <= len; ++n, ++s) - { - *s = g_RGen.Integer< SQChar >(); - } - b.At< SQChar >(len) = 0; - return b.Get< SQChar >(); + // Prepare the string buffer + String str; + // Request the random fill + GetRandomString(str, len); + // Return ownership of the string + return std::move(str); } // ------------------------------------------------------------------------------------------------ -static CSStr RandomString(Int32 len, SQChar n) +static String RandomString(Int32 len, SQChar n) { + // Is there anything to generate? if (len <= 0) - { return _SC(""); - } - Buffer b(len+1); - SStr s = b.Get< SQChar >(); - for (Int32 i = 0; i <= len; ++i, ++s) - { - *s = g_RGen.Integer< SQChar >(n); - } - b.At< SQChar >(len) = 0; - return b.Get< SQChar >(); + // Prepare the string buffer + String str; + // Request the random fill + GetRandomString(str, len, n); + // Return ownership of the string + return std::move(str); } // ------------------------------------------------------------------------------------------------ -static CSStr RandomString(Int32 len, SQChar m, SQChar n) +static String RandomString(Int32 len, SQChar m, SQChar n) { + // Is there anything to generate? if (len <= 0) - { return _SC(""); - } - Buffer b(len+1); - SStr s = b.Get< SQChar >(); - for (Int32 i = 0; i <= len; ++i, ++s) - { - *s = g_RGen.IntegerC< SQChar >(m, n); - } - b.At< SQChar >(len) = 0; - return b.Get< SQChar >(); -} - -// ------------------------------------------------------------------------------------------------ -static bool RandomProbI(SQInteger p) -{ - return g_RGen.Prob(p); -} - -static bool RandomProbI(SQInteger m, SQInteger n) -{ - return g_RGen.Prob(m, n); -} - -// ------------------------------------------------------------------------------------------------ -static bool RandomProbF(SQFloat p) -{ - return g_RGen.Prob(p); -} - -static bool RandomProbF(SQFloat m, SQFloat n) -{ - return g_RGen.Prob(m, n); + // Prepare the string buffer + String str; + // Request the random fill + GetRandomString(str, len, m, n); + // Return ownership of the string + return std::move(str); } // ------------------------------------------------------------------------------------------------ @@ -361,20 +384,36 @@ void Register_Random(HSQUIRRELVM vm) .Func(_SC("GenSeed"), &GenerateSeed) .Overload< void (*)(void) >(_SC("Reseed"), &ReseedRandom) .Overload< void (*)(Uint32) >(_SC("Reseed"), &ReseedRandom) - .Overload< SQInteger (*)(void) >(_SC("Integer"), &RandomValue< SQInteger >) - .Overload< SQInteger (*)(SQInteger) >(_SC("Integer"), &RandomValue< SQInteger >) - .Overload< SQInteger (*)(SQInteger, SQInteger) >(_SC("Integer"), &RandomValue< SQInteger >) - .Overload< SQFloat (*)(void) >(_SC("Float"), &RandomValue< SQFloat >) - .Overload< SQFloat (*)(SQFloat) >(_SC("Float"), &RandomValue< SQFloat >) - .Overload< SQFloat (*)(SQFloat, SQFloat) >(_SC("Float"), &RandomValue< SQFloat >) - .Overload< CSStr (*)(Int32) >(_SC("String"), &RandomString) - .Overload< CSStr (*)(Int32, SQChar) >(_SC("String"), &RandomString) - .Overload< CSStr (*)(Int32, SQChar, SQChar) >(_SC("String"), &RandomString) - .Func(_SC("Bool"), &GetRandomBool) - .Overload< bool (*)(SQInteger) >(_SC("ProbI"), &RandomProbI) - .Overload< bool (*)(SQInteger, SQInteger) >(_SC("ProbI"), &RandomProbI) - .Overload< bool (*)(SQFloat) >(_SC("ProbF"), &RandomProbF) - .Overload< bool (*)(SQFloat, SQFloat) >(_SC("ProbF"), &RandomProbF) + .Overload< void (*)(void) >(_SC("Reseed32"), &ReseedRandom32) + .Overload< void (*)(Uint32) >(_SC("Reseed32"), &ReseedRandom32) + .Overload< void (*)(void) >(_SC("Reseed64"), &ReseedRandom64) + .Overload< void (*)(Uint32) >(_SC("Reseed64"), &ReseedRandom64) + +#ifdef _SQ64 + .Overload< SQInteger (*)(void) >(_SC("Integer"), &GetRandomInt64) + .Overload< SQInteger (*)(SQInteger) >(_SC("Integer"), &GetRandomInt64) + .Overload< SQInteger (*)(SQInteger, SQInteger) >(_SC("Integer"), &GetRandomInt64) +#else + .Overload< SQInteger (*)(void) >(_SC("Integer"), &GetRandomInt32) + .Overload< SQInteger (*)(SQInteger) >(_SC("Integer"), &GetRandomInt32) + .Overload< SQInteger (*)(SQInteger, SQInteger) >(_SC("Integer"), &GetRandomInt32) +#endif // _SQ64 + +#ifdef SQUSEDOUBLE + .Overload< SQFloat (*)(void) >(_SC("Float"), &GetRandomFloat64) + .Overload< SQFloat (*)(SQFloat) >(_SC("Float"), &GetRandomFloat64) + .Overload< SQFloat (*)(SQFloat, SQFloat) >(_SC("Float"), &GetRandomFloat64) +#else + .Overload< SQFloat (*)(void) >(_SC("Float"), &GetRandomFloat32) + .Overload< SQFloat (*)(SQFloat) >(_SC("Float"), &GetRandomFloat32) + .Overload< SQFloat (*)(SQFloat, SQFloat) >(_SC("Float"), &GetRandomFloat32) +#endif // SQUSEDOUBLE + + .Overload< String (*)(Int32) >(_SC("String"), &RandomString) + .Overload< String (*)(Int32, SQChar) >(_SC("String"), &RandomString) + .Overload< String (*)(Int32, SQChar, SQChar) >(_SC("String"), &RandomString) + .Overload< bool (*)(void) >(_SC("Bool"), &GetRandomBool) + .Overload< bool (*)(SQFloat) >(_SC("Bool"), &GetRandomBool) ); } diff --git a/source/Library/String.cpp b/source/Library/String.cpp index 5f01d63c..90e3a4ed 100644 --- a/source/Library/String.cpp +++ b/source/Library/String.cpp @@ -7,10 +7,10 @@ #include // ------------------------------------------------------------------------------------------------ -#include -#include -#include -#include +#include +#include +#include +#include // ------------------------------------------------------------------------------------------------ #include @@ -21,137 +21,117 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ CSStr LeftStr(CSStr t, SQChar f, Uint32 w) { - // Allocate a buffer with the requested width - Buffer b(w * sizeof(SQChar)); - Uint32 n = !t ? 0 : strlen(t); - // Populate the entire buffer with the fill character - memset(b.Data(), f, w * sizeof(SQChar)); // Is the specified width valid? - if (w >= b.Size< SQChar >()) - { - SqThrow("Invalid width specified: %d > %d", w, b.Size< SQChar >()); - w = 0; - } + if (!w) + return _SC(""); + // Allocate a buffer with the requested width + Buffer b(w); // Is the specified string valid? - else if (n == 0) - { - SqThrow("Invalid string length: %d < 0", n); - } - // Is the specified string within width range? - else if (n > w) - { - SqThrow("String is out of bounds: %d > %d", n, w); - } - // Insert the specified string + if (!t || *t == 0) + // Insert only the fill character + memset(b.Data(), f, w); else { + // Calculate the string length + const Uint32 n = strlen(t); + // Insert only the fill character first + memset(b.Data(), f, w); + // Overwrite with the specified string strncpy(b.Data(), t, n); } // End the resulted string - b.At< SQChar >(w) = 0; + b.At(w) = 0; // Return the resulted string return b.Get< SQChar >(); } CSStr LeftStr(CSStr t, SQChar f, Uint32 w, Uint32 o) { - // Allocate a buffer with the requested width - Buffer b(w * sizeof(SQChar)); - Uint32 n = !t ? 0 : strlen(t); - // Populate the entire buffer with the fill character - memset(b.Data(), f, w * sizeof(SQChar)); // Is the specified width valid? - if (w >= b.Size< SQChar >()) - { - SqThrow("Invalid width specified: %d > %d", w, b.Size< SQChar >()); - w = 0; - } + if (!w) + return _SC(""); + // Is the specified offset within width range? + else if (o > w) + SqThrowF("Offset is out of bounds"); + // Allocate a buffer with the requested width + Buffer b(w); // Is the specified string valid? - else if (n == 0) - { - SqThrow("Invalid string length: %d < 0", n); - } - // Is the specified string within width range? - else if ((o+n) > w) - { - SqThrow("String is out of bounds: (%d+%d) > %d", o, n, w); - } - // Insert the specified string + if (!t || *t == 0) + // Insert only the fill character + memset(b.Data(), f, w); else { - strncpy(b.Get< SQChar >() + o, t, n); + // Clculate the string length + const Uint32 n = strlen(t); + // Insert the fill character first + memset(b.Data(), f, w); + // Overwrite with the specified string + strncpy(b.Data() + o, t, w - n); } // End the resulted string - b.At< SQChar >(w) = 0; + b.At(w) = 0; // Return the resulted string - return b.Get< SQChar >(); + return b.Get(); } // ------------------------------------------------------------------------------------------------ CSStr RightStr(CSStr t, SQChar f, Uint32 w) { - // Allocate a buffer with the requested width - Buffer b(w * sizeof(SQChar)); - Uint32 n = !t ? 0 : strlen(t); - // Populate the entire buffer with the fill character - memset(b.Data(), f, w * sizeof(SQChar)); // Is the specified width valid? - if (w >= b.Size< SQChar >()) - { - SqThrow("Invalid width specified: %d > %d", w, b.Size< SQChar >()); - w = 0; - } + if (!w) + return _SC(""); + // Allocate a buffer with the requested width + Buffer b(w); // Is the specified string valid? - else if (n == 0) - { - SqThrow("Invalid string length: %d < 0", n); - } - // Is the specified string within width range? - else if (n > w) - { - SqThrow("String is out of bounds: %d > %d", n, w); - } - // Insert the specified string + if (!t || *t == 0) + // Insert only the fill character + memset(b.Data(), f, w); else { - strncpy(b.Get< SQChar >() + (w-n), t, n); + // Calculate the string length + const Uint32 n = strlen(t); + // Insert the fill character first + memset(b.Data(), f, w); + // Overwrite with the specified string + if (n >= w) + strncpy(b.Data(), t, w); + else + strncpy(b.Data() + (w - n), t, n); } // End the resulted string - b.At< SQChar >(w) = 0; + b.At(w) = 0; // Return the resulted string return b.Get< SQChar >(); } CSStr RightStr(CSStr t, SQChar f, Uint32 w, Uint32 o) { - // Allocate a buffer with the requested width - Buffer b(w * sizeof(SQChar)); - Uint32 n = !t ? 0 : strlen(t); - // Populate the entire buffer with the fill character - memset(b.Data(), f, w * sizeof(SQChar)); // Is the specified width valid? - if (w >= b.Size< SQChar >()) - { - SqThrow("Invalid width specified: %d > %d", w, b.Size< SQChar >()); - w = 0; - } + if (!w) + return _SC(""); + // Is the specified offset within width range? + else if (o > w) + SqThrowF("Offset is out of bounds"); + // Allocate a buffer with the requested width + Buffer b(w); // Is the specified string valid? - else if (n == 0) - { - SqThrow("Invalid string length: %d < 0", n); - } - // Is the specified string within width range? - else if ((n+o) > w) - { - SqThrow("String is out of bounds: (%d+%d) > %d", n, o, w); - } - // Insert the specified string + if (!t || *t == 0) + // Insert only the fill character + memset(b.Data(), f, w); else { - strncpy(b.Get< SQChar >() + ((w-n)-o), t, n); + // Calculate the string length + const Uint32 n = strlen(t); + // Insert the fill character first + memset(b.Data(), f, w); + // Overwrite with the specified string + if (n >= w || (n + o) >= w) + strncpy(b.Data(), t, w - o); + else + strncpy(b.Data() + ((w - n) - o), t, n); } // End the resulted string - b.At< SQChar >(w) = 0; + b.At(w) = 0; // Return the resulted string return b.Get< SQChar >(); } @@ -159,34 +139,26 @@ CSStr RightStr(CSStr t, SQChar f, Uint32 w, Uint32 o) // ------------------------------------------------------------------------------------------------ CSStr CenterStr(CSStr t, SQChar f, Uint32 w) { - // Allocate a buffer with the requested width - Buffer b(w * sizeof(SQChar)); - Uint32 n = !t ? 0 : strlen(t); - // Populate the entire buffer with the fill character - memset(b.Data(), f, w * sizeof(SQChar)); // Is the specified width valid? - if (w >= b.Size< SQChar >()) - { - SqThrow("Invalid width specified: %d > %d", w, b.Size< SQChar >()); - w = 0; - } + if (!w) + return _SC(""); + // Allocate a buffer with the requested width + Buffer b(w); // Is the specified string valid? - else if (n == 0) - { - SqThrow("Invalid string length: %d < 0", n); - } - // Is the specified string within width range? - else if (n > w) - { - SqThrow("String is out of bounds: %d > %d", n, w); - } - // Insert the specified string + if (!t || *t == 0) + // Insert only the fill character + memset(b.Data(), f, w); else { - strncpy(b.Get< SQChar >() + (w/2 - n/2), t, n); + // Calculate the string length + const Uint32 n = strlen(t); + // Insert only the fill character first + memset(b.Data(), f, w); + // Overwrite with the specified string + strncpy(b.Data() + ((w/2) - (n/2)), t, n); } // End the resulted string - b.At< SQChar >(w) = 0; + b.At(w) = 0; // Return the resulted string return b.Get< SQChar >(); } @@ -194,12 +166,11 @@ CSStr CenterStr(CSStr t, SQChar f, Uint32 w) // ------------------------------------------------------------------------------------------------ CSStr StrJustAlphaNum(CSStr str) { - Uint32 size = 0; // See if we actually have something to search for - if(!str || (size = strlen(str)) <= 0) - { + if(!str || *str == 0) return _SC(""); - } + // Calculate the string length + Uint32 size = strlen(str); // Obtain a temporary buffer Buffer b(size); // Resulted string size @@ -211,13 +182,11 @@ CSStr StrJustAlphaNum(CSStr str) { // Is this an alpha-numeric character? if (isalnum(c) != 0) - { // Save it and move to the next one - b.At< SQChar >(n++) = c; - } + b.At(n++) = c; } // End the resulted string - b.At< SQChar >(n) = 0; + b.At(n) = 0; // Return the string return b.Get< SQChar >(); } @@ -225,12 +194,11 @@ CSStr StrJustAlphaNum(CSStr str) // ------------------------------------------------------------------------------------------------ CSStr StrToLowercase(CSStr str) { - Uint32 size = 0; // See if we actually have something to search for - if(!str || (size = strlen(str)) <= 0) - { + if(!str || *str == 0) return _SC(""); - } + // Calculate the string length + Uint32 size = strlen(str); // Obtain a temporary buffer Buffer b(size); // Resulted string size @@ -239,12 +207,10 @@ CSStr StrToLowercase(CSStr str) SQChar c = 0; // Process characters while ((c = *(str++)) != 0) - { // Convert it and move to the next one - b.At< SQChar >(n++) = tolower(c); - } + b.At(n++) = tolower(c); // End the resulted string - b.At< SQChar >(n) = 0; + b.At(n) = 0; // Return the string return b.Get< SQChar >(); } @@ -252,12 +218,11 @@ CSStr StrToLowercase(CSStr str) // ------------------------------------------------------------------------------------------------ CSStr StrToUppercase(CSStr str) { - Uint32 size = 0; // See if we actually have something to search for - if(!str || (size = strlen(str)) <= 0) - { + if(!str || *str == 0) return _SC(""); - } + // Calculate the string length + Uint32 size = strlen(str); // Obtain a temporary buffer Buffer b(size); // Resulted string size @@ -266,12 +231,10 @@ CSStr StrToUppercase(CSStr str) SQChar c = 0; // Process characters while ((c = *(str++)) != 0) - { // Convert it and move to the next one - b.At< SQChar >(n++) = toupper(c); - } + b.At(n++) = toupper(c); // End the resulted string - b.At< SQChar >(n) = 0; + b.At(n) = 0; // Return the string return b.Get< SQChar >(); } @@ -280,18 +243,16 @@ CSStr StrToUppercase(CSStr str) static CSStr FromArray(Array & arr) { // Determine array size - const Int32 length = (Int32)arr.Length(); + const Int32 length = static_cast< Int32 >(arr.Length()); // Obtain a temporary buffer Buffer b(length * sizeof(Int32)); // Get array elements as integers arr.GetArray< Int32 >(b.Get< Int32 >(), length); // Overwrite integers with characters for (Int32 n = 0; n < length; ++n) - { - b.At< SQChar >(n) = (SQChar)b.At< Int32 >(n); - } + b.At(n) = static_cast< SQChar >(b.At< Int32 >(n)); // Terminate the resulted string - b.At< SQChar >(length) = 0; + b.At(length) = 0; // Return the string return b.Get< SQChar >(); } @@ -301,9 +262,14 @@ static SQInteger StdPrintF(HSQUIRRELVM vm) { CStr msg = NULL; SQInteger length = 0; - if(SQ_FAILED(sqstd_format(vm, 2, &length, &msg))) - return -1; + // Attempt to run the specified format and save the result + const SQRESULT res = sqstd_format(vm, 2, &length, &msg); + // Validate the result for errors and propagate them to the VM + if(SQ_FAILED(res)) + return res; + // Send the resulted string to console as a user message LogUsr("%s", msg); + // This function doesn't return anything return 0; } diff --git a/source/Logger.cpp b/source/Logger.cpp index 001355c8..36781418 100644 --- a/source/Logger.cpp +++ b/source/Logger.cpp @@ -147,22 +147,6 @@ void Logger::Message(Uint8 type, bool sub, CCStr fmt, ...) va_end(args); } -// ------------------------------------------------------------------------------------------------ -void Logger::Throw(CCStr fmt, ...) -{ - va_list args; - va_start(args, fmt); - m_Buffer.WriteF(0, fmt, args); - va_end(args); - Error::Throw(DefaultVM::Get(), m_Buffer.Data()); -} - -void Logger::Throw(CCStr fmt, va_list args) -{ - m_Buffer.WriteF(0, fmt, args); - Error::Throw(DefaultVM::Get(), m_Buffer.Data()); -} - // ------------------------------------------------------------------------------------------------ void Logger::Debug(CCStr fmt, ...) { @@ -382,18 +366,6 @@ SQMOD_CLOG(cLogSWrn, LL_WRN, true) SQMOD_CLOG(cLogSErr, LL_ERR, true) SQMOD_CLOG(cLogSFtl, LL_FTL, true) -// ------------------------------------------------------------------------------------------------ -void SqThrow(CCStr fmt, ...) -{ - va_list args; - va_start(args, fmt); - if (_Log) - _Log->Throw(fmt, args); - else - vprintf(fmt, args); - va_end(args); -} - // -------------------------------------------------------------------------------------------- void OutputMessageImpl(const char * msg, va_list args) { diff --git a/source/Logger.hpp b/source/Logger.hpp index a5453385..3aad1d8d 100644 --- a/source/Logger.hpp +++ b/source/Logger.hpp @@ -74,8 +74,6 @@ public: void Message(Uint8 type, bool sub, CCStr fmt, ...); // -------------------------------------------------------------------------------------------- - void Throw(CCStr fmt, ...); - void Throw(CCStr fmt, va_list args); void Debug(CCStr fmt, ...); void Debug(CCStr fmt, va_list args); diff --git a/source/Misc.cpp b/source/Misc.cpp index 69ff0932..a9bd1063 100644 --- a/source/Misc.cpp +++ b/source/Misc.cpp @@ -88,29 +88,34 @@ void Register_Core(HSQUIRRELVM vm) template < Uint8 L, bool S > static SQInteger LogBasicMessage(HSQUIRRELVM vm) { const Int32 top = sq_gettop(vm); + // Was the message value specified? if (top <= 1) - SqThrow("The log message was not specified"); - else if (top == 2 && ((sq_gettype(vm, -1) == OT_STRING) || !SQ_FAILED(sq_tostring(vm, -1)))) - { - CCStr msg = NULL; - if (SQ_FAILED(sq_getstring(vm, -1, &msg))) - SqThrow("Unable to retrieve the log message"); - else - _Log->Message(L, S, "%s", msg); - sq_settop(vm, top); - } + return sq_throwerror(vm, "Missing message value"); + // Do we have enough values to call the format function? else if (top > 2) { - CStr msg = NULL; + SStr msg = NULL; SQInteger len = 0; - if (SQ_FAILED(sqstd_format(vm, 2, &len, &msg))) - SqThrow("Unable to generate the log message [%s]", Error::Message(vm).c_str()); - else - _Log->Message(L, S, "%s", msg); + // Attempt to generate the specified string format + SQRESULT ret = sqstd_format(vm, 2, &len, &msg); + // Did the format failed? + if (SQ_FAILED(ret)) + return ret; // Propagate the exception + // Log the resulted string value + _Log->Message(L, S, "%s", msg); } else - SqThrow("Unable to extract the log message"); - return 0; + { + // Attempt to retrieve the value from the stack as a string + Var< CSStr > msg(vm, 2); + // See if the obtained value is a valid string + if (!msg.value) + return sq_throwerror(vm, "Unable to retrieve the value"); + // Log the resulted string value + _Log->Message(L, S, "%s", msg.value); + } + // This function does not return a value + return 1; } // ================================================================================================ diff --git a/source/Misc/Player.cpp b/source/Misc/Player.cpp index 05ed0113..5affd04c 100644 --- a/source/Misc/Player.cpp +++ b/source/Misc/Player.cpp @@ -739,10 +739,9 @@ Object & FindPlayer(Object & by) Int32 id = _Func->GetPlayerIDFromName(&str[0]); if (VALID_ENTITYEX(id, SQMOD_PLAYER_POOL)) _Core->GetPlayer(id).mObj; - } - break; + } break; default: - SqThrow("Unsupported search identifier"); + SqThrowF("Unsupported search identifier"); } return NullObject(); } diff --git a/source/Misc/World.cpp b/source/Misc/World.cpp index ea40761e..4b813516 100644 --- a/source/Misc/World.cpp +++ b/source/Misc/World.cpp @@ -155,14 +155,18 @@ bool EnabledChatTagsByDefault(void) // ------------------------------------------------------------------------------------------------ void CreateExplosion(Int32 world, Int32 type, const Vector3 & pos, CPlayer & source, Uint32 level) { - if (source.Validate()) - _Func->CreateExplosion(world, type, pos.x, pos.y, pos.z, source.GetID(), level); + // Validate the specified player + source.Validate(); + // Perform the requested operation + _Func->CreateExplosion(world, type, pos.x, pos.y, pos.z, source.GetID(), level); } void CreateExplosionEx(Int32 world, Int32 type, Float32 x, Float32 y, Float32 z, CPlayer & source, Uint32 level) { - if (source.Validate()) - _Func->CreateExplosion(world, type, x, y, z, source.GetID(), level); + // Validate the specified player + source.Validate(); + // Perform the requested operation + _Func->CreateExplosion(world, type, x, y, z, source.GetID(), level); } // ------------------------------------------------------------------------------------------------ diff --git a/source/Register.cpp b/source/Register.cpp index 304e654a..74d48ae9 100644 --- a/source/Register.cpp +++ b/source/Register.cpp @@ -34,7 +34,7 @@ extern void Register_CVehicle(HSQUIRRELVM vm); extern void Register_Entity(HSQUIRRELVM vm); // ------------------------------------------------------------------------------------------------ -extern void Register_Hash(HSQUIRRELVM vm); +extern void Register_Crypt(HSQUIRRELVM vm); extern void Register_Numeric(HSQUIRRELVM vm); extern void Register_Random(HSQUIRRELVM vm); extern void Register_String(HSQUIRRELVM vm); @@ -76,7 +76,7 @@ bool RegisterAPI(HSQUIRRELVM vm) Register_CTextdraw(vm); Register_CVehicle(vm); - Register_Hash(vm); + Register_Crypt(vm); Register_Random(vm); Register_Numeric(vm); Register_String(vm); diff --git a/source/Routine.cpp b/source/Routine.cpp index 1aca9e7d..133b5560 100644 --- a/source/Routine.cpp +++ b/source/Routine.cpp @@ -15,60 +15,134 @@ Routine::Time Routine::s_Prev = 0; Routine::Queue Routine::s_Queue; Routine::Buckets Routine::s_Buckets; +// ------------------------------------------------------------------------------------------------ +void Routine::Attach(Routine * routine, Interval interval) +{ + // Do we have a valid routine and interval bucket to attach? + if (!routine || ! interval) + return; + // Attempt to locate the bucket with the specified interval + Buckets::iterator itr = std::find_if(s_Buckets.begin(), s_Buckets.end(), IntrvFunc(interval)); + // Does this bucket exist? + if (itr == s_Buckets.end()) + { + // Then create it + s_Buckets.emplace_back(interval); + // And attach this routine + s_Buckets.back().mRoutines.push_back(routine); + } + // Is this routine already attached to this bucket? + else if (std::find(itr->mRoutines.begin(), itr->mRoutines.end(), routine) != itr->mRoutines.end()) + // Then let's attach it now + itr->mRoutines.push_back(routine); +} + +// ------------------------------------------------------------------------------------------------ +void Routine::Detach(Routine * routine, Interval interval) +{ + // Do we have a valid routine and interval to detach? + if (!routine || ! interval) + return; + // Attempt to locate the bucket with this interval + Buckets::iterator bitr = std::find_if(s_Buckets.begin(), s_Buckets.end(), IntrvFunc(interval)); + // Was there a bucket with this interval? + if (bitr == s_Buckets.end()) + return; // Nothing to detach from! + // Attempt to find this routine in the associated bucket + Routines::iterator ritr = std::find(bitr->mRoutines.begin(), bitr->mRoutines.end(), routine); + // Was this routine even attached? + if (ritr != bitr->mRoutines.end()) + // Then erase it and move on + bitr->mRoutines.erase(ritr); + // Any reason to keep this bucket? + if (bitr->mRoutines.empty()) + // Remove the bucket as well + s_Buckets.erase(bitr); +} + +// ------------------------------------------------------------------------------------------------ +void Routine::ProcQueue() +{ + // Do we have any queued commands that must be performed when unlocked? + if (s_Queue.empty() || s_Lock) + return; // We're done here! + // Process all commands in the queue + for (const auto & cmd : s_Queue) + { + // Are we supposed to detach the associated routine? + if (cmd.mCommand == CMD_DETACH) + Detach(cmd.mRoutine, cmd.mInterval); + // Are we supposed to attach the associated routine? + else if (cmd.mCommand == CMD_ATTACH) + Attach(cmd.mRoutine, cmd.mInterval); + } + // Clear processed commands + s_Queue.clear(); +} + // ------------------------------------------------------------------------------------------------ void Routine::Process() { - s_Lock = false; /* In case an exception prevented the unlock last time */ - if (!s_Queue.empty()) - { - for (Queue::iterator itr = s_Queue.begin(); itr != s_Queue.end(); ++itr) - { - if (itr->first && itr->second) - itr->second->Attach(); - else if (itr->second) - itr->second->Terminate(); - } - s_Queue.clear(); - } + // In case an exception prevented the unlock last time + s_Lock = false; + // Normally there shouldn't be any but just in case the above happened + ProcQueue(); // Is this the first call? if (s_Last == 0) { s_Last = GetCurrentSysTime(); + // We'll do it text time return; } + // Lock the buckets s_Lock = true; + // Backup the last known time-stamp s_Prev = s_Last; + // Get the current time-stamp s_Last = GetCurrentSysTime(); + // Calculate the elapsed time Int32 delta = Int32((s_Last - s_Prev) / 1000L); - for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket) + // Process all available buckets + for (auto & bucket : s_Buckets) { - bucket->mElapsed += delta; - if (bucket->mElapsed < bucket->mInterval) - continue; - Routines::iterator itr = bucket->mRoutines.begin(); - Routines::iterator end = bucket->mRoutines.end(); - for (; itr != end; ++itr) - (*itr)->Execute(); - bucket->mElapsed = 0; + // Update the bucket elapsed time + bucket.mElapsed += delta; + // Have we completed the bucket interval? + if (bucket.mElapsed < bucket.mInterval) + continue; // Move to the next one + // Attempt to execute bucket routines, if any + for (auto & routine : bucket.mRoutines) + routine->Execute(); + // Reset the bucket elapsed time + bucket.mElapsed = 0; } + // Unlock the buckets s_Lock = false; + // Process operations that couldn't be performed while buckets were locked + ProcQueue(); } // ------------------------------------------------------------------------------------------------ void Routine::TerminateAll() { - for (Buckets::iterator bucket = s_Buckets.begin(); bucket != s_Buckets.end(); ++bucket) + // Let's make sure no pending commands are left + ProcQueue(); + // Process all buckets + for (auto & bucket : s_Buckets) { - Routines::iterator itr = bucket->mRoutines.begin(); - Routines::iterator end = bucket->mRoutines.end(); - for (; itr != end; ++itr) + // Process all routines in this bucket + for (auto & routine : bucket.mRoutines) { - (*itr)->Release(); - (*itr)->m_Terminated = true; + // Release all resources + routine->Release(); + // Mark it as terminated + routine->m_Terminated = true; } } - // Clear all references + // Clear all references to routines s_Buckets.clear(); + // Clear the last time-stamp in case of a reload + s_Last = 0; } // ------------------------------------------------------------------------------------------------ @@ -167,8 +241,13 @@ Routine::Routine(Object & env, Function & func, Interval interval, Iterate itera // ------------------------------------------------------------------------------------------------ Routine::~Routine() { - if (!m_Terminated) - Terminate(); + // Was the routine already terminated? + if (m_Terminated) + return; + // Detach from the associated bucket + Detach(); + // Release script resources + Release(); } // ------------------------------------------------------------------------------------------------ @@ -182,6 +261,7 @@ Int32 Routine::Cmp(const Routine & o) const return -1; } +// ------------------------------------------------------------------------------------------------ CSStr Routine::ToString() const { return ToStrF(_PRINT_INT_FMT, m_Interval); @@ -190,27 +270,22 @@ CSStr Routine::ToString() const // ------------------------------------------------------------------------------------------------ void Routine::Terminate() { + // Was the routine already terminated? if (m_Terminated) - SqThrow("Routine was already terminated"); - else if (s_Lock) - s_Queue.push_back(Queue::value_type(false, this)); - else - { - Detach(); - Release(); - m_Terminated = true; - } + SqThrowF("Routine was already terminated"); + // Detach from the associated bucket + Detach(); + // Release script resources and mark it as terminated + Release(); } // ------------------------------------------------------------------------------------------------ void Routine::SetArg(Uint8 num, Object & val) { + // Was the routine terminated? if (m_Terminated) - { - SqThrow("Routine was terminated"); - return; - } - + SqThrowF("Routine was terminated"); + // Identify which argument was requested switch (num) { case 1: m_Arg1 = val; break; @@ -227,18 +302,16 @@ void Routine::SetArg(Uint8 num, Object & val) case 12: m_Arg12 = val; break; case 13: m_Arg13 = val; break; case 14: m_Arg14 = val; break; - default: SqThrow("Argument is out of range: %d", num); + default: SqThrowF("Argument is out of range: %d", num); } } Object & Routine::GetArg(Uint8 num) { + // Was the routine terminated? if (m_Terminated) - { - SqThrow("Routine was terminated"); - return NullObject(); - } - + SqThrowF("Routine was terminated"); + // Identify which argument was requested switch (num) { case 1: return m_Arg1; @@ -255,9 +328,9 @@ Object & Routine::GetArg(Uint8 num) case 12: return m_Arg12; case 13: return m_Arg13; case 14: return m_Arg14; - default: SqThrow("Argument is out of range: %d", num); + default: SqThrowF("Argument is out of range: %d", num); } - + // Shouldn't really reach this point return NullObject(); } @@ -269,16 +342,18 @@ Routine::Interval Routine::GetInterval() const void Routine::SetInterval(Interval interval) { + // Was the routine terminated? if (m_Terminated) - SqThrow("Routine was terminated"); + SqThrowF("Routine was terminated"); + // Is the specified interval valid? else if (!interval) - SqThrow("Invalid routine interval"); - else - { - Detach(); - m_Interval = interval; - Attach(); - } + SqThrowF("Invalid routine interval"); + // Detach from the current bucket + Detach(); + // Update the interval + m_Interval = interval; + // Attach to the new bucket + Attach(); } // ------------------------------------------------------------------------------------------------ @@ -289,10 +364,11 @@ Routine::Iterate Routine::GetIterations() const void Routine::SetIterations(Iterate iterations) { + // Was the routine terminated? if (m_Terminated) - SqThrow("Routine was terminated"); - else - m_Iterations = iterations; + SqThrowF("Routine was terminated"); + // Perform the requested operation + m_Iterations = iterations; } // ------------------------------------------------------------------------------------------------ @@ -303,12 +379,14 @@ Uint8 Routine::GetArguments() const void Routine::SetArguments(Uint8 num) { + // Was the routine terminated? if (m_Terminated) - SqThrow("Routine was terminated"); + SqThrowF("Routine was terminated"); + // Is the specified argument count valid? else if (num > 14) - SqThrow("Argument is out of range: %d", num); - else - m_Arguments = num; + SqThrowF("Argument is out of range: %d", num); + // Perform the requested operation + m_Arguments = num; } // ------------------------------------------------------------------------------------------------ @@ -319,10 +397,11 @@ bool Routine::GetSuspended() const void Routine::SetSuspended(bool toggle) { + // Was the routine terminated? if (m_Terminated) - SqThrow("Routine was terminated"); - else - m_Suspended = toggle; + SqThrowF("Routine was terminated"); + // Perform the requested operation + m_Suspended = toggle; } // ------------------------------------------------------------------------------------------------ @@ -334,28 +413,33 @@ bool Routine::GetTerminated() const // ------------------------------------------------------------------------------------------------ Function & Routine::GetCallback() { + // Was the routine terminated? if (m_Terminated) - SqThrow("Routine was terminated"); - else - return m_Callback; - return NullFunction(); + SqThrowF("Routine was terminated"); + // Return the requested information + return m_Callback; } void Routine::SetCallback(Object & env, Function & func) { + // Was the routine terminated? if (m_Terminated) - SqThrow("Routine was terminated"); - else - m_Callback = Function(env.GetVM(), env, func.GetFunc()); + SqThrowF("Routine was terminated"); + // Perform the requested operation + m_Callback = Function(env.GetVM(), env, func.GetFunc()); } // ------------------------------------------------------------------------------------------------ void Routine::Release() { + // Was the routine terminated? if (m_Terminated) return; + // Mark it as terminated m_Terminated = true; + // Release the callback m_Callback.ReleaseGently(); + // Release the arguments m_Arg1.Release(); m_Arg2.Release(); m_Arg3.Release(); @@ -375,64 +459,53 @@ void Routine::Release() // ------------------------------------------------------------------------------------------------ void Routine::Create() { + // Was the routine terminated? if (!m_Interval) - SqThrow("Invalid routine interval"); + SqThrowF("Invalid routine interval"); + // Is the specified callback valid? else if (m_Callback.IsNull()) - SqThrow("Invalid routine callback"); - else - { - Attach(); - return; - } - Release(); + SqThrowF("Invalid routine callback"); + // Attempt to attach the routine + Attach(); } +// ------------------------------------------------------------------------------------------------ void Routine::Attach() { + // Do we have a valid interval? if (!m_Interval) - return; + return; // Nothing to attach to! + // Are the buckets locked? else if (s_Lock) - { - s_Queue.push_back(Queue::value_type(true, this)); - return; - } - Buckets::iterator itr = std::find_if(s_Buckets.begin(), s_Buckets.end(), IntrvFunc(m_Interval)); - if (itr == s_Buckets.end()) - { - s_Buckets.push_back(Buckets::value_type(m_Interval)); - s_Buckets.back().mRoutines.push_back(this); - } - else if (std::find(itr->mRoutines.begin(), itr->mRoutines.end(), this) != itr->mRoutines.end()) - return; + // Queue a command to attach this routine when the bucket is unlocked + s_Queue.emplace_back(this, m_Interval, CMD_ATTACH); + // Attempt to attach the the routine now else - itr->mRoutines.push_back(this); + Attach(this, m_Interval); } +// ------------------------------------------------------------------------------------------------ void Routine::Detach() { + // Do we have a valid interval? if (!m_Interval) - return; + return; // Nothing to detach from! + // Are the buckets locked? else if (s_Lock) - { - s_Queue.push_back(Queue::value_type(false, this)); - return; - } - Buckets::iterator bitr = std::find_if(s_Buckets.begin(), s_Buckets.end(), IntrvFunc(m_Interval)); - if (bitr == s_Buckets.end()) - return; - Routines::iterator ritr = std::find(bitr->mRoutines.begin(), bitr->mRoutines.end(), this); - if (ritr != bitr->mRoutines.end()) - bitr->mRoutines.erase(ritr); - // Any reason to keep this bucket? - if (bitr->mRoutines.empty()) - s_Buckets.erase(bitr); + // Queue a command to detach this routine when the bucket is unlocked + s_Queue.emplace_back(this, m_Interval, CMD_DETACH); + // Attempt to detach the the routine now + else + Detach(this, m_Interval); } // ------------------------------------------------------------------------------------------------ void Routine::Execute() { + // Is this routine suspended or has nothing to call? if (m_Suspended || m_Callback.IsNull()) - return; + return; // We're done here! + // Attempt to identify how many arguments should be passed switch (m_Arguments) { case 0: m_Callback.Execute(); @@ -473,14 +546,11 @@ void Routine::Execute() m_Arg8, m_Arg9, m_Arg10, m_Arg11, m_Arg12, m_Arg13, m_Arg14); break; default: - SqThrow("Unknown argument count: %d", m_Arguments); + SqThrowF("Unknown argument count: %d", m_Arguments); } - + // Decrease the number of iterations if necessary if (m_Iterations && (--m_Iterations) == 0) - { - Terminate(); - } - + Terminate(); // This routine reached the end of it's life } /* ------------------------------------------------------------------------------------------------ diff --git a/source/Routine.hpp b/source/Routine.hpp index 3348444d..2a2544e3 100644 --- a/source/Routine.hpp +++ b/source/Routine.hpp @@ -5,8 +5,8 @@ #include "Base/Shared.hpp" // ------------------------------------------------------------------------------------------------ -#include #include +#include // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -37,6 +37,16 @@ public: protected: + /* -------------------------------------------------------------------------------------------- + * Commands that can be performed when the buckets are unlocked. + */ + enum + { + CMD_REMOVE = 1, + CMD_DETACH = 2, + CMD_ATTACH = 3 + }; + /* -------------------------------------------------------------------------------------------- * Group of routines that have the same interval. */ @@ -48,7 +58,7 @@ protected: Routines mRoutines; /* Routines to trigger on completion. */ /* ---------------------------------------------------------------------------------------- - * Base constructor. + * Default constructor. */ Bucket(Interval interval) : mInterval(interval), mElapsed(0), mRoutines() @@ -59,36 +69,78 @@ protected: /* ---------------------------------------------------------------------------------------- * Copy constructor. */ - Bucket(const Bucket & o) - : mInterval(o.mInterval), mElapsed(o.mElapsed), mRoutines(o.mRoutines) - { - /* ... */ - } + Bucket(const Bucket & o) = default; + + /* ---------------------------------------------------------------------------------------- + * Move constructor. + */ + Bucket(Bucket && o) = default; /* ---------------------------------------------------------------------------------------- * Destructor. */ - ~Bucket() + ~Bucket() = default; + + /* ---------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Bucket & operator = (const Bucket & o) = default; + + /* ---------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Bucket & operator = (Bucket && o) = default; + }; + + /* -------------------------------------------------------------------------------------------- + * A command to perform certain actions when the buckets are unlocked. + */ + struct Cmd + { + // ---------------------------------------------------------------------------------------- + Routine* mRoutine; /* The routine to which this command applies */ + Interval mInterval; /* The bucket where this routine is stored. */ + Uint16 mCommand; /* The command that must be performed. */ + + /* ---------------------------------------------------------------------------------------- + * Base constructor. + */ + Cmd(Routine * routine, Interval interval, Uint16 command) + : mRoutine(routine), mInterval(interval), mCommand(command) { /* ... */ } + /* ---------------------------------------------------------------------------------------- + * Copy constructor. + */ + Cmd(const Cmd & o) = default; + + /* ---------------------------------------------------------------------------------------- + * Move constructor. + */ + Cmd(Cmd && o) = default; + + /* ---------------------------------------------------------------------------------------- + * Destructor. + */ + ~Cmd() = default; + /* ---------------------------------------------------------------------------------------- * Copy assignment operator. */ - Bucket & operator = (const Bucket & o) - { - mInterval = o.mInterval; - mElapsed = o.mElapsed; - mRoutines = o.mRoutines; - return *this; - } + Cmd & operator = (const Cmd & o) = default; + + /* ---------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Cmd & operator = (Cmd && o) = default; }; // -------------------------------------------------------------------------------------------- - typedef Int64 Time; - typedef std::vector< Bucket > Buckets; - typedef std::vector< std::pair< bool, Routine * > > Queue; + typedef Int64 Time; + typedef std::vector< Cmd > Queue; + typedef std::vector< Bucket > Buckets; /* -------------------------------------------------------------------------------------------- * Functor used to search for buckets with a certain interval. @@ -98,7 +150,7 @@ protected: private: // ---------------------------------------------------------------------------------------- - Interval m_Interval; /* The interval to be matched. */ + const Interval m_Interval; /* The interval to be matched. */ public: @@ -118,6 +170,14 @@ protected: { return (elem.mInterval == m_Interval); } + + /* ---------------------------------------------------------------------------------------- + * Function call operator. + */ + bool operator () (Buckets::const_reference elem) const + { + return (elem.mInterval == m_Interval); + } }; // -------------------------------------------------------------------------------------------- @@ -127,6 +187,21 @@ protected: static Queue s_Queue; /* Actions to be performed when the buckets aren't locked */ static Buckets s_Buckets; /* Buckets of routines grouped by similar intervals. */ + /* -------------------------------------------------------------------------------------------- + * Attach a routine to a certain bucket. + */ + static void Attach(Routine * routine, Interval interval); + + /* -------------------------------------------------------------------------------------------- + * Detach a routine from a certain bucket. + */ + static void Detach(Routine * routine, Interval interval); + + /* -------------------------------------------------------------------------------------------- + * Process queue commands. + */ + static void ProcQueue(); + private: /* -------------------------------------------------------------------------------------------- @@ -215,7 +290,7 @@ public: CSStr ToString() const; /* -------------------------------------------------------------------------------------------- - * Terminate this routine by releasing all resources and sscheduling it for detachment. + * Terminate this routine by releasing all resources and scheduling it for detachment. */ void Terminate(); diff --git a/source/SqBase.hpp b/source/SqBase.hpp index ea268b75..9b23e77f 100644 --- a/source/SqBase.hpp +++ b/source/SqBase.hpp @@ -119,6 +119,16 @@ #define SQMOD_VERSION_MINOR 0 #define SQMOD_VERSION_PATCH 1 +/* ------------------------------------------------------------------------------------------------ + * SQUIRREL FORWARD DECLARATIONS +*/ +extern "C" { + typedef struct tagSQObject SQObject; + struct SQVM; + typedef struct SQVM* HSQUIRRELVM; + typedef SQObject HSQOBJECT; +} /*extern "C"*/ + /* ------------------------------------------------------------------------------------------------ * SQRAT FORWARD DECLARATIONS */ @@ -394,19 +404,38 @@ enum CmdArgType // ------------------------------------------------------------------------------------------------ enum CmdError { + // The command failed for unknown reasons CMDERR_UNKNOWN = 0, + // The command failed to execute because there was nothing to execute CMDERR_EMPTY_COMMAND, + // The command failed to execute because the command name was invalid after processing CMDERR_INVALID_COMMAND, + // The command failed to execute because there was a syntax error in the arguments CMDERR_SYNTAX_ERROR, + // The command failed to execute because there was no such command CMDERR_UNKNOWN_COMMAND, + // The command failed to execute because there was no callback to handle the execution CMDERR_MISSING_EXECUTER, + // The command failed to execute because the invoker does not have the proper authority CMDERR_INSUFFICIENT_AUTH, + // The command was unable to execute because the argument limit was not reached CMDERR_INCOMPLETE_ARGS, + // The command was unable to execute because the argument limit was exceeded CMDERR_EXTRANEOUS_ARGS, + // Command was unable to execute due to argument type mismatch CMDERR_UNSUPPORTED_ARG, - CMDERR_EXECUTION_FAILED, + // The command arguments contained more data than the internal buffer can handle CMDERR_BUFFER_OVERFLOW, - CMDERR_MAX, + // The command failed to complete execution due to a runtime exception + CMDERR_EXECUTION_FAILED, + // The command completed the execution but returned a negative result + CMDERR_EXECUTION_ABORTED, + // The post execution callback failed to execute due to a runtime exception + CMDERR_POST_PROCESSING_FAILED, + // The callback that was supposed to deal with the failure also failed due to a runtime exception + CMDERR_UNRESOLVED_FAILURE, + // Maximum command error identifier + CMDERR_MAX }; } // Namespace:: SqMod