diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-10-17 16:56:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-17 16:56:21 +0300 |
commit | 0ef7a9b39cf72da1211039ab22bdf8f9f6a2c984 (patch) | |
tree | 6f51ef179497265b5bff2a355471ae5dc9643ad2 /indra/llcommon/lldefs.h | |
parent | 9e24b300d02e5627ea0d304d412cb683ec2de3a4 (diff) | |
parent | d3d349ae0f17a72481f30b9354b9367b1cd3b639 (diff) |
Merge pull request #2856 from secondlife/marchcat/c-develop
Develop → Maint C sync
Diffstat (limited to 'indra/llcommon/lldefs.h')
-rw-r--r-- | indra/llcommon/lldefs.h | 219 |
1 files changed, 134 insertions, 85 deletions
diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 0ba756d472..96b48c1532 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -28,67 +28,68 @@ #define LL_LLDEFS_H #include "stdtypes.h" +#include <cassert> #include <type_traits> // Often used array indices -const U32 VX = 0; -const U32 VY = 1; -const U32 VZ = 2; -const U32 VW = 3; -const U32 VS = 3; - -const U32 VRED = 0; -const U32 VGREEN = 1; -const U32 VBLUE = 2; -const U32 VALPHA = 3; - -const U32 INVALID_DIRECTION = 0xFFFFFFFF; -const U32 EAST = 0; -const U32 NORTH = 1; -const U32 WEST = 2; -const U32 SOUTH = 3; - -const U32 NORTHEAST = 4; -const U32 NORTHWEST = 5; -const U32 SOUTHWEST = 6; -const U32 SOUTHEAST = 7; -const U32 MIDDLE = 8; - -const U8 EAST_MASK = 0x1<<EAST; -const U8 NORTH_MASK = 0x1<<NORTH; -const U8 WEST_MASK = 0x1<<WEST; -const U8 SOUTH_MASK = 0x1<<SOUTH; - -const U8 NORTHEAST_MASK = NORTH_MASK | EAST_MASK; -const U8 NORTHWEST_MASK = NORTH_MASK | WEST_MASK; -const U8 SOUTHWEST_MASK = SOUTH_MASK | WEST_MASK; -const U8 SOUTHEAST_MASK = SOUTH_MASK | EAST_MASK; - -const U32 gDirOpposite[8] = {2, 3, 0, 1, 6, 7, 4, 5}; -const U32 gDirAdjacent[8][2] = { - {4, 7}, - {4, 5}, - {5, 6}, - {6, 7}, - {0, 1}, - {1, 2}, - {2, 3}, - {0, 3} - }; +constexpr U32 VX = 0; +constexpr U32 VY = 1; +constexpr U32 VZ = 2; +constexpr U32 VW = 3; +constexpr U32 VS = 3; + +constexpr U32 VRED = 0; +constexpr U32 VGREEN = 1; +constexpr U32 VBLUE = 2; +constexpr U32 VALPHA = 3; + +constexpr U32 INVALID_DIRECTION = 0xFFFFFFFF; +constexpr U32 EAST = 0; +constexpr U32 NORTH = 1; +constexpr U32 WEST = 2; +constexpr U32 SOUTH = 3; + +constexpr U32 NORTHEAST = 4; +constexpr U32 NORTHWEST = 5; +constexpr U32 SOUTHWEST = 6; +constexpr U32 SOUTHEAST = 7; +constexpr U32 MIDDLE = 8; + +constexpr U8 EAST_MASK = 0x1<<EAST; +constexpr U8 NORTH_MASK = 0x1<<NORTH; +constexpr U8 WEST_MASK = 0x1<<WEST; +constexpr U8 SOUTH_MASK = 0x1<<SOUTH; + +constexpr U8 NORTHEAST_MASK = NORTH_MASK | EAST_MASK; +constexpr U8 NORTHWEST_MASK = NORTH_MASK | WEST_MASK; +constexpr U8 SOUTHWEST_MASK = SOUTH_MASK | WEST_MASK; +constexpr U8 SOUTHEAST_MASK = SOUTH_MASK | EAST_MASK; + +constexpr U32 gDirOpposite[8] = {2, 3, 0, 1, 6, 7, 4, 5}; +constexpr U32 gDirAdjacent[8][2] = { + {4, 7}, + {4, 5}, + {5, 6}, + {6, 7}, + {0, 1}, + {1, 2}, + {2, 3}, + {0, 3} + }; // Magnitude along the x and y axis -const S32 gDirAxes[8][2] = { - { 1, 0}, // east - { 0, 1}, // north - {-1, 0}, // west - { 0,-1}, // south - { 1, 1}, // ne - {-1, 1}, // nw - {-1,-1}, // sw - { 1,-1}, // se - }; +constexpr S32 gDirAxes[8][2] = { + { 1, 0}, // east + { 0, 1}, // north + {-1, 0}, // west + { 0,-1}, // south + { 1, 1}, // ne + {-1, 1}, // nw + {-1,-1}, // sw + { 1,-1}, // se + }; -const S32 gDirMasks[8] = { +constexpr S32 gDirMasks[8] = { EAST_MASK, NORTH_MASK, WEST_MASK, @@ -117,22 +118,22 @@ const S32 gDirMasks[8] = { // | / -6- | / // |/ / |/ // +------------------+ -const U32 NO_SIDE = 0; -const U32 FRONT_SIDE = 1; -const U32 BACK_SIDE = 2; -const U32 LEFT_SIDE = 3; -const U32 RIGHT_SIDE = 4; -const U32 TOP_SIDE = 5; -const U32 BOTTOM_SIDE = 6; - -const U8 LL_SOUND_FLAG_NONE = 0x0; -const U8 LL_SOUND_FLAG_LOOP = 1<<0; -const U8 LL_SOUND_FLAG_SYNC_MASTER = 1<<1; -const U8 LL_SOUND_FLAG_SYNC_SLAVE = 1<<2; -const U8 LL_SOUND_FLAG_SYNC_PENDING = 1<<3; -const U8 LL_SOUND_FLAG_QUEUE = 1<<4; -const U8 LL_SOUND_FLAG_STOP = 1<<5; -const U8 LL_SOUND_FLAG_SYNC_MASK = LL_SOUND_FLAG_SYNC_MASTER | LL_SOUND_FLAG_SYNC_SLAVE | LL_SOUND_FLAG_SYNC_PENDING; +constexpr U32 NO_SIDE = 0; +constexpr U32 FRONT_SIDE = 1; +constexpr U32 BACK_SIDE = 2; +constexpr U32 LEFT_SIDE = 3; +constexpr U32 RIGHT_SIDE = 4; +constexpr U32 TOP_SIDE = 5; +constexpr U32 BOTTOM_SIDE = 6; + +constexpr U8 LL_SOUND_FLAG_NONE = 0x0; +constexpr U8 LL_SOUND_FLAG_LOOP = 1<<0; +constexpr U8 LL_SOUND_FLAG_SYNC_MASTER = 1<<1; +constexpr U8 LL_SOUND_FLAG_SYNC_SLAVE = 1<<2; +constexpr U8 LL_SOUND_FLAG_SYNC_PENDING = 1<<3; +constexpr U8 LL_SOUND_FLAG_QUEUE = 1<<4; +constexpr U8 LL_SOUND_FLAG_STOP = 1<<5; +constexpr U8 LL_SOUND_FLAG_SYNC_MASK = LL_SOUND_FLAG_SYNC_MASTER | LL_SOUND_FLAG_SYNC_SLAVE | LL_SOUND_FLAG_SYNC_PENDING; // // *NOTE: These values may be used as hard-coded numbers in scanf() variants. @@ -141,17 +142,17 @@ const U8 LL_SOUND_FLAG_SYNC_MASK = LL_SOUND_FLAG_SYNC_MASTER | LL_SOUND_FLAG_SYN // DO NOT CHANGE. // -------------- // -const U32 LL_MAX_PATH = 1024; // buffer size of maximum path + filename string length +constexpr U32 LL_MAX_PATH = 1024; // buffer size of maximum path + filename string length // For strings we send in messages -const U32 STD_STRING_BUF_SIZE = 255; // Buffer size -const U32 STD_STRING_STR_LEN = 254; // Length of the string (not including \0) +constexpr U32 STD_STRING_BUF_SIZE = 255; // Buffer size +constexpr U32 STD_STRING_STR_LEN = 254; // Length of the string (not including \0) // *NOTE: This value is used as hard-coded numbers in scanf() variants. // DO NOT CHANGE. -const U32 MAX_STRING = STD_STRING_BUF_SIZE; // Buffer size +constexpr U32 MAX_STRING = STD_STRING_BUF_SIZE; // Buffer size -const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luck +constexpr U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luck // C++ is our friend. . . use template functions to make life easier! @@ -169,37 +170,85 @@ const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 f // llclampb(a) // clamps a to [0 .. 255] // +// llless(d0, d1) safely compares d0 < d1 even if one is signed and the other +// is unsigned. A simple (d0 < d1) expression converts the signed operand to +// unsigned before comparing. If the signed operand is negative, that flips +// the negative value to a huge positive value, producing the wrong answer! +// llless() specifically addresses that case. +template <typename T0, typename T1> +constexpr bool llless(T0 d0, T1 d1) +{ + if constexpr (std::is_signed_v<T0> && ! std::is_signed_v<T1>) + { + // T0 signed, T1 unsigned: negative d0 is less than any unsigned d1 + if (d0 < 0) + return true; + // both are non-negative: explicitly cast to avoid C4018 + return std::make_unsigned_t<T0>(d0) < d1; + } + else if constexpr (! std::is_signed_v<T0> && std::is_signed_v<T1>) + { + // T0 unsigned, T1 signed: any unsigned d0 is greater than negative d1 + if (d1 < 0) + return false; + // both are non-negative: explicitly cast to avoid C4018 + return d0 < std::make_unsigned_t<T1>(d1); + } + else + { + // both T0 and T1 are signed, or both are unsigned: + // straightforward comparison works + return d0 < d1; + } +} + // recursion tail template <typename T> -inline auto llmax(T data) +constexpr auto llmax(T data) { return data; } template <typename T0, typename T1, typename... Ts> -inline auto llmax(T0 d0, T1 d1, Ts... rest) +constexpr auto llmax(T0 d0, T1 d1, Ts... rest) { auto maxrest = llmax(d1, rest...); - return (d0 > maxrest)? d0 : maxrest; + return llless(maxrest, d0)? d0 : maxrest; } // recursion tail template <typename T> -inline auto llmin(T data) +constexpr auto llmin(T data) { return data; } template <typename T0, typename T1, typename... Ts> -inline auto llmin(T0 d0, T1 d1, Ts... rest) +constexpr auto llmin(T0 d0, T1 d1, Ts... rest) { auto minrest = llmin(d1, rest...); - return (d0 < minrest) ? d0 : minrest; + return llless(d0, minrest) ? d0 : minrest; } template <typename A, typename MIN, typename MAX> -inline A llclamp(A a, MIN minval, MAX maxval) +constexpr A llclamp(A a, MIN minval, MAX maxval) { + // The only troublesome case is if A is unsigned and either minval or + // maxval is both signed and negative. Casting a negative number to + // unsigned flips it to a huge positive number, making this llclamp() call + // ineffective. + if constexpr (! std::is_signed_v<A>) + { + if constexpr (std::is_signed_v<MIN>) + { + assert(minval >= 0); + } + if constexpr (std::is_signed_v<MAX>) + { + assert(maxval >= 0); + } + } + A aminval{ static_cast<A>(minval) }, amaxval{ static_cast<A>(maxval) }; if ( a < aminval ) { @@ -213,13 +262,13 @@ inline A llclamp(A a, MIN minval, MAX maxval) } template <class LLDATATYPE> -inline LLDATATYPE llclampf(LLDATATYPE a) +constexpr LLDATATYPE llclampf(LLDATATYPE a) { return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(1)); } template <class LLDATATYPE> -inline LLDATATYPE llclampb(LLDATATYPE a) +constexpr LLDATATYPE llclampb(LLDATATYPE a) { return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(255)); } |