summaryrefslogtreecommitdiff
path: root/indra/llcommon/lldefs.h
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-10-17 16:56:21 +0300
committerGitHub <noreply@github.com>2024-10-17 16:56:21 +0300
commit0ef7a9b39cf72da1211039ab22bdf8f9f6a2c984 (patch)
tree6f51ef179497265b5bff2a355471ae5dc9643ad2 /indra/llcommon/lldefs.h
parent9e24b300d02e5627ea0d304d412cb683ec2de3a4 (diff)
parentd3d349ae0f17a72481f30b9354b9367b1cd3b639 (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.h219
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));
}