1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-17 01:12:23 +02:00

Add LENGTH_OF() macro.

Determining the length of arrays that could be calculated at compile time was a bit piecemeal, with special macros used sometimes and with the math done directly other times.

This macro makes the task easier, uses less space, and automatically adjusts when the type changes.
This commit is contained in:
David Steele
2022-04-07 19:00:15 -04:00
parent 8be11d32e4
commit 571dceefec
29 changed files with 60 additions and 59 deletions

View File

@ -857,7 +857,7 @@ bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
// Add defaults
if (varLstSize(kvKeyList(optionalCmdRuleType)) > 0)
{
for (unsigned int ruleIdx = 0; ruleIdx < sizeof(ruleList) / sizeof(Variant *); ruleIdx++)
for (unsigned int ruleIdx = 0; ruleIdx < LENGTH_OF(ruleList); ruleIdx++)
{
if (kvKeyExists(optionalCmdRuleType, ruleList[ruleIdx]))
kvAdd(optionalCmdRule, VARSTR(optCmd->name), kvGet(optionalCmdRuleType, ruleList[ruleIdx]));

View File

@ -35,8 +35,7 @@ cmdLocal(ProtocolServer *server)
MEM_CONTEXT_TEMP_BEGIN()
{
protocolServerProcess(
server, cfgCommandJobRetry(), commandLocalHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandLocalHandlerList));
protocolServerProcess(server, cfgCommandJobRetry(), commandLocalHandlerList, LENGTH_OF(commandLocalHandlerList));
}
MEM_CONTEXT_TEMP_END();

View File

@ -71,10 +71,7 @@ cmdRemote(ProtocolServer *const server)
// If not successful we'll just exit
if (success)
{
protocolServerProcess(
server, NULL, commandRemoteHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandRemoteHandlerList));
}
protocolServerProcess(server, NULL, commandRemoteHandlerList, LENGTH_OF(commandRemoteHandlerList));
}
MEM_CONTEXT_TEMP_END();

View File

@ -101,9 +101,6 @@ static const struct CompressHelperLocal
},
};
#define COMPRESS_LIST_SIZE \
(sizeof(compressHelperLocal) / sizeof(struct CompressHelperLocal))
/**********************************************************************************************************************************/
CompressType
compressTypeEnum(const StringId type)
@ -116,13 +113,13 @@ compressTypeEnum(const StringId type)
CompressType result = compressTypeNone;
for (; result < COMPRESS_LIST_SIZE; result++)
for (; result < LENGTH_OF(compressHelperLocal); result++)
{
if (type == compressHelperLocal[result].typeId)
break;
}
if (result == COMPRESS_LIST_SIZE)
if (result == LENGTH_OF(compressHelperLocal))
THROW_FMT(AssertError, "invalid compression type '%s'", strZ(strIdToStr(type)));
FUNCTION_TEST_RETURN(result);
@ -136,7 +133,7 @@ compressTypePresent(CompressType type)
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_END();
ASSERT(type < COMPRESS_LIST_SIZE);
ASSERT(type < LENGTH_OF(compressHelperLocal));
if (type != compressTypeNone && compressHelperLocal[type].compressNew == NULL)
THROW_FMT(OptionInvalidValueError, PROJECT_NAME " not compiled with %s support", strZ(compressHelperLocal[type].type));
@ -152,7 +149,7 @@ compressTypeStr(CompressType type)
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_END();
ASSERT(type < COMPRESS_LIST_SIZE);
ASSERT(type < LENGTH_OF(compressHelperLocal));
FUNCTION_TEST_RETURN(compressHelperLocal[type].type);
}
@ -167,13 +164,13 @@ compressTypeFromName(const String *name)
CompressType result = compressTypeNone + 1;
for (; result < COMPRESS_LIST_SIZE; result++)
for (; result < LENGTH_OF(compressHelperLocal); result++)
{
if (strEndsWith(name, compressHelperLocal[result].ext))
break;
}
if (result == COMPRESS_LIST_SIZE)
if (result == LENGTH_OF(compressHelperLocal))
result = compressTypeNone;
FUNCTION_TEST_RETURN(result);
@ -187,7 +184,7 @@ compressLevelDefault(CompressType type)
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_END();
ASSERT(type < COMPRESS_LIST_SIZE);
ASSERT(type < LENGTH_OF(compressHelperLocal));
compressTypePresent(type);
FUNCTION_TEST_RETURN(compressHelperLocal[type].levelDefault);
@ -202,7 +199,7 @@ compressFilter(CompressType type, int level)
FUNCTION_TEST_PARAM(INT, level);
FUNCTION_TEST_END();
ASSERT(type < COMPRESS_LIST_SIZE);
ASSERT(type < LENGTH_OF(compressHelperLocal));
ASSERT(type != compressTypeNone);
compressTypePresent(type);
@ -224,7 +221,7 @@ compressFilterPack(const StringId filterType, const Pack *const filterParam)
MEM_CONTEXT_TEMP_BEGIN()
{
for (CompressType compressIdx = compressTypeNone + 1; compressIdx < COMPRESS_LIST_SIZE; compressIdx++)
for (CompressType compressIdx = compressTypeNone + 1; compressIdx < LENGTH_OF(compressHelperLocal); compressIdx++)
{
const struct CompressHelperLocal *compress = &compressHelperLocal[compressIdx];
@ -255,7 +252,7 @@ decompressFilter(CompressType type)
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_END();
ASSERT(type < COMPRESS_LIST_SIZE);
ASSERT(type < LENGTH_OF(compressHelperLocal));
ASSERT(type != compressTypeNone);
compressTypePresent(type);
@ -270,7 +267,7 @@ compressExtStr(CompressType type)
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_END();
ASSERT(type < COMPRESS_LIST_SIZE);
ASSERT(type < LENGTH_OF(compressHelperLocal));
FUNCTION_TEST_RETURN(compressHelperLocal[type].ext);
}

View File

@ -10,6 +10,7 @@ Error Handler
#include <string.h>
#include "common/error.h"
#include "common/macro.h"
#include "common/stackTrace.h"
/***********************************************************************************************************************************

View File

@ -32,13 +32,13 @@ httpDateToTime(const String *lastModified)
const char *month = strZ(strSubN(lastModified, 8, 3));
unsigned int monthIdx = 0;
for (; monthIdx < sizeof(httpCommonMonthList) / sizeof(char *); monthIdx++)
for (; monthIdx < LENGTH_OF(httpCommonMonthList); monthIdx++)
{
if (strcmp(month, httpCommonMonthList[monthIdx]) == 0)
break;
}
if (monthIdx == sizeof(httpCommonMonthList) / sizeof(char *))
if (monthIdx == LENGTH_OF(httpCommonMonthList))
THROW_FMT(FormatError, "invalid month '%s'", month);
// Convert to time_t

View File

@ -99,4 +99,17 @@ This is useful for determining how to correctly align a type in a buffer that is
***********************************************************************************************************************************/
#define ALIGN_OFFSET(type, bytes) (ALIGN_OF(type) - ((bytes) % ALIGN_OF(type)))
/***********************************************************************************************************************************
Determine the length of an array that can be determined at compile time
For this macro to work correctly the array must be declared like:
int intList[] = {0, 1};
It will not work for an array declared like:
int *intList;
***********************************************************************************************************************************/
#define LENGTH_OF(array) (sizeof(array) / sizeof((array)[0]))
#endif

View File

@ -14,6 +14,7 @@ Stack Trace Handler
#include "common/assert.h"
#include "common/error.h"
#include "common/macro.h"
#include "common/stackTrace.h"
/***********************************************************************************************************************************

View File

@ -12,6 +12,7 @@ Convert C Types
#include <time.h>
#include "common/debug.h"
#include "common/macro.h"
#include "common/type/convert.h"
/***********************************************************************************************************************************

View File

@ -210,8 +210,6 @@ static const PackTypeMapData packTypeMapData[] =
},
};
#define PACK_TYPE_MAP_SIZE (sizeof(packTypeMapData) / sizeof(PackTypeMapData))
/***********************************************************************************************************************************
Object types
***********************************************************************************************************************************/
@ -549,7 +547,7 @@ pckReadTagNext(PackRead *this)
this->tagNextTypeMap = (unsigned int)pckReadU64Internal(this) + 0xF;
CHECK(
FormatError, this->tagNextTypeMap < PACK_TYPE_MAP_SIZE && packTypeMapData[this->tagNextTypeMap].type != 0,
FormatError, this->tagNextTypeMap < LENGTH_OF(packTypeMapData) && packTypeMapData[this->tagNextTypeMap].type != 0,
"invalid tag type");
// If the value can contain multiple bits (e.g. integer)

View File

@ -292,16 +292,16 @@ varBoolForce(const Variant *this)
const char *string = strZ(varStr(this));
unsigned int boolIdx;
for (boolIdx = 0; boolIdx < sizeof(boolString) / sizeof(char *); boolIdx++)
for (boolIdx = 0; boolIdx < LENGTH_OF(boolString); boolIdx++)
if (strcasecmp(string, boolString[boolIdx]) == 0)
break;
// If string was not found then not a boolean
if (boolIdx == sizeof(boolString) / sizeof(char *))
if (boolIdx == LENGTH_OF(boolString))
THROW_FMT(FormatError, "unable to convert str '%s' to bool", string);
// False if in first half of list, true if in second half
result = boolIdx / (sizeof(boolString) / sizeof(char *) / 2);
result = boolIdx / (LENGTH_OF(boolString) / 2);
break;
}

View File

@ -58,7 +58,7 @@ main(int argListSize, const char *argList[])
{
// Set stack trace and mem context error cleanup handlers
static const ErrorHandlerFunction errorHandlerList[] = {stackTraceClean, memContextClean};
errorHandlerSet(errorHandlerList, sizeof(errorHandlerList) / sizeof(ErrorHandlerFunction));
errorHandlerSet(errorHandlerList, LENGTH_OF(errorHandlerList));
// Set storage helpers
static const StorageHelper storageHelperList[] =

View File

@ -200,9 +200,6 @@ static const PgInterface pgInterface[] =
},
};
// Total PostgreSQL versions in pgInterface
#define PG_INTERFACE_SIZE (sizeof(pgInterface) / sizeof(PgInterface))
/***********************************************************************************************************************************
These pg_control fields are common to all versions of PostgreSQL, so we can use them to generate error messages when the pg_control
version cannot be found.
@ -226,7 +223,7 @@ pgInterfaceVersion(unsigned int pgVersion)
const PgInterface *result = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < LENGTH_OF(pgInterface); interfaceIdx++)
{
if (pgInterface[interfaceIdx].version == pgVersion)
{
@ -276,7 +273,7 @@ pgControlFromBuffer(const Buffer *controlFile)
// Search for the version of PostgreSQL that uses this control file
const PgInterface *interface = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < LENGTH_OF(pgInterface); interfaceIdx++)
{
if (pgInterface[interfaceIdx].controlIs(bufPtrConst(controlFile)))
{
@ -375,7 +372,7 @@ pgWalFromBuffer(const Buffer *walBuffer)
// Search for the version of PostgreSQL that uses this WAL magic
const PgInterface *interface = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < LENGTH_OF(pgInterface); interfaceIdx++)
{
if (pgInterface[interfaceIdx].walIs(bufPtrConst(walBuffer)))
{

View File

@ -127,7 +127,7 @@ protocolClientNew(const String *name, const String *service, IoRead *read, IoWri
PROTOCOL_GREETING_VERSION_STR, STRDEF(PROJECT_VERSION),
};
for (unsigned int expectedIdx = 0; expectedIdx < sizeof(expected) / sizeof(char *) / 2; expectedIdx++)
for (unsigned int expectedIdx = 0; expectedIdx < LENGTH_OF(expected) / 2; expectedIdx++)
{
const String *expectedKey = expected[expectedIdx * 2];
const String *expectedValue = expected[expectedIdx * 2 + 1];

View File

@ -30,8 +30,6 @@ typedef struct ProtocolServerHandler
ProtocolServerCommandHandler handler; // Function that handles the protocol command
} ProtocolServerHandler;
#define PROTOCOL_SERVER_HANDLER_LIST_SIZE(list) (sizeof(list) / sizeof(ProtocolServerHandler))
/***********************************************************************************************************************************
Constructors
***********************************************************************************************************************************/

View File

@ -173,7 +173,7 @@ hrnPgInterfaceVersion(unsigned int pgVersion)
const HrnPgInterface *result = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(hrnPgInterface) / sizeof(HrnPgInterface); interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < LENGTH_OF(hrnPgInterface); interfaceIdx++)
{
if (hrnPgInterface[interfaceIdx].version == pgVersion)
{

View File

@ -110,7 +110,7 @@ testRun(void)
// Install local command handler shim
static const ProtocolServerHandler testLocalHandlerList[] = {PROTOCOL_SERVER_HANDLER_ARCHIVE_GET_LIST};
hrnProtocolLocalShimInstall(testLocalHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(testLocalHandlerList));
hrnProtocolLocalShimInstall(testLocalHandlerList, LENGTH_OF(testLocalHandlerList));
// Arguments that must be included
StringList *argBaseList = strLstNew();

View File

@ -608,7 +608,7 @@ testRun(void)
// Install local command handler shim
static const ProtocolServerHandler testLocalHandlerList[] = {PROTOCOL_SERVER_HANDLER_ARCHIVE_PUSH_LIST};
hrnProtocolLocalShimInstall(testLocalHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(testLocalHandlerList));
hrnProtocolLocalShimInstall(testLocalHandlerList, LENGTH_OF(testLocalHandlerList));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("command must be run on the pg host");

View File

@ -611,7 +611,7 @@ testRun(void)
// Install local command handler shim
static const ProtocolServerHandler testLocalHandlerList[] = {PROTOCOL_SERVER_HANDLER_BACKUP_LIST};
hrnProtocolLocalShimInstall(testLocalHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(testLocalHandlerList));
hrnProtocolLocalShimInstall(testLocalHandlerList, LENGTH_OF(testLocalHandlerList));
// The tests expect the timezone to be UTC
setenv("TZ", "UTC", true);

View File

@ -176,7 +176,7 @@ testRun(void)
// Install local command handler shim
static const ProtocolServerHandler testLocalHandlerList[] = {PROTOCOL_SERVER_HANDLER_RESTORE_LIST};
hrnProtocolLocalShimInstall(testLocalHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(testLocalHandlerList));
hrnProtocolLocalShimInstall(testLocalHandlerList, LENGTH_OF(testLocalHandlerList));
// Create default storage object for testing
Storage *storageTest = storagePosixNewP(TEST_PATH_STR, .write = true);

View File

@ -23,7 +23,7 @@ testRun(void)
// Install local command handler shim
static const ProtocolServerHandler testLocalHandlerList[] = {PROTOCOL_SERVER_HANDLER_VERIFY_LIST};
hrnProtocolLocalShimInstall(testLocalHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(testLocalHandlerList));
hrnProtocolLocalShimInstall(testLocalHandlerList, LENGTH_OF(testLocalHandlerList));
StringList *argListBase = strLstNew();
hrnCfgArgRawZ(argListBase, cfgOptStanza, "db");

View File

@ -134,7 +134,7 @@ testRun(void)
TEST_TITLE("set error handler");
static const ErrorHandlerFunction testErrorHandlerList[] = {testErrorHandler};
errorHandlerSet(testErrorHandlerList, sizeof(testErrorHandlerList) / sizeof(ErrorHandlerFunction));
errorHandlerSet(testErrorHandlerList, LENGTH_OF(testErrorHandlerList));
assert(errorContext.handlerList[0] == testErrorHandler);
assert(errorContext.handlerTotal == 1);

View File

@ -614,7 +614,7 @@ testRun(void)
TEST_TITLE("option resolve list contains an entry for every option");
TEST_RESULT_INT(
sizeof(optionResolveOrder) / sizeof(ConfigOption), CFG_OPTION_TOTAL,
LENGTH_OF(optionResolveOrder), CFG_OPTION_TOTAL,
"check that the option resolve list contains an entry for every option");
// -------------------------------------------------------------------------------------------------------------------------

View File

@ -35,7 +35,7 @@ testRun(void)
STRDEF("test"), STRDEF("config"), HRN_FORK_CHILD_READ(), HRN_FORK_CHILD_WRITE());
static const ProtocolServerHandler commandHandler[] = {PROTOCOL_SERVER_HANDLER_OPTION_LIST};
protocolServerProcess(server, NULL, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler));
protocolServerProcess(server, NULL, commandHandler, LENGTH_OF(commandHandler));
}
HRN_FORK_CHILD_END();

View File

@ -112,8 +112,7 @@ testRun(void)
};
TEST_RESULT_VOID(
protocolServerProcess(server, NULL, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler)),
"run process loop");
protocolServerProcess(server, NULL, commandHandler, LENGTH_OF(commandHandler)), "run process loop");
TEST_RESULT_VOID(protocolServerFree(server), "free server");
}
HRN_FORK_CHILD_END();

View File

@ -183,7 +183,7 @@ testRun(void)
STRDEF("storage test server"), STRDEF("test"), HRN_FORK_CHILD_READ(), HRN_FORK_CHILD_WRITE());
static const ProtocolServerHandler commandHandler[] = {PROTOCOL_SERVER_HANDLER_STORAGE_REMOTE_LIST};
protocolServerProcess(server, NULL, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler));
protocolServerProcess(server, NULL, commandHandler, LENGTH_OF(commandHandler));
}
HRN_FORK_CHILD_END();

View File

@ -518,22 +518,21 @@ testRun(void)
const ProtocolServerHandler commandHandler[] = {TEST_PROTOCOL_SERVER_HANDLER_LIST};
TEST_ERROR(
protocolServerProcess(server, NULL, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler)),
ProtocolError, "invalid command 'BOGUS' (0x38eacd271)");
protocolServerProcess(server, NULL, commandHandler, LENGTH_OF(commandHandler)), ProtocolError,
"invalid command 'BOGUS' (0x38eacd271)");
// -----------------------------------------------------------------------------------------------------------------
TEST_TITLE("server restart and assert");
// This does not run in a TEST* macro because tests are run by the command handlers
TEST_ERROR(
protocolServerProcess(server, NULL, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler)),
AssertError, "ERR_MESSAGE");
protocolServerProcess(server, NULL, commandHandler, LENGTH_OF(commandHandler)), AssertError, "ERR_MESSAGE");
// -----------------------------------------------------------------------------------------------------------------
TEST_TITLE("server restart");
// This does not run in a TEST* macro because tests are run by the command handlers
protocolServerProcess(server, NULL, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler));
protocolServerProcess(server, NULL, commandHandler, LENGTH_OF(commandHandler));
// -----------------------------------------------------------------------------------------------------------------
TEST_TITLE("server with retries");
@ -547,7 +546,7 @@ testRun(void)
"new server");
// This does not run in a TEST* macro because tests are run by the command handlers
protocolServerProcess(server, retryList, commandHandler, PROTOCOL_SERVER_HANDLER_LIST_SIZE(commandHandler));
protocolServerProcess(server, retryList, commandHandler, LENGTH_OF(commandHandler));
}
HRN_FORK_CHILD_END();

View File

@ -28,7 +28,7 @@ testRun(void)
PROTOCOL_SERVER_HANDLER_STORAGE_REMOTE_LIST
};
hrnProtocolRemoteShimInstall(testRemoteHandlerList, PROTOCOL_SERVER_HANDLER_LIST_SIZE(testRemoteHandlerList));
hrnProtocolRemoteShimInstall(testRemoteHandlerList, LENGTH_OF(testRemoteHandlerList));
// Test storage
Storage *storageTest = storagePosixNewP(TEST_PATH_STR, .write = true);

View File

@ -25,6 +25,7 @@ The test code is included directly so it can freely interact with the included C
#ifdef HRN_FEATURE_ERROR
#include "common/error.h"
#include "common/macro.h"
#endif
#ifdef HRN_FEATURE_DEBUG
@ -162,7 +163,7 @@ main(int argListSize, const char *argList[])
#endif
};
errorHandlerSet(handlerList, sizeof(handlerList) / sizeof(ErrorHandlerFunction));
errorHandlerSet(handlerList, LENGTH_OF(handlerList));
#endif
// Initialize statistics