From 98e204552a79826178b8d634fd6bc472a74ee825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Mon, 14 Dec 2015 23:46:36 +0100 Subject: [PATCH] countof with type safety For reference see http://www.g-truc.net/post-0708.html and http://lxr.free-electrons.com/source/include/linux/kernel.h#L54 This will provide a type-safe mechanism for counting elements of array. If you try passing something which cannot be counted, compiler will frown at you right away. --- projects/openrct2.vcxproj | 1 + src/audio/mixer.cpp | 19 ++++++++++--------- src/audio/mixer.h | 4 ++-- src/core/Util.hpp | 20 ++++++++++++++++++++ src/network/network.cpp | 5 +++-- src/platform/posix.c | 4 ++-- src/rct2.h | 25 ++++++++++++++++++++++++- 7 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 src/core/Util.hpp diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 13d1c0ff54..901c0793c3 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -208,6 +208,7 @@ + diff --git a/src/audio/mixer.cpp b/src/audio/mixer.cpp index 1edda91bc7..8df91e49c9 100644 --- a/src/audio/mixer.cpp +++ b/src/audio/mixer.cpp @@ -27,6 +27,7 @@ extern "C" { } #include "mixer.h" #include +#include "../core/Util.hpp" Mixer gMixer; @@ -434,10 +435,10 @@ Mixer::Mixer() { effectbuffer = 0; volume = 1; - for (int i = 0; i < countof(css1sources); i++) { + for (size_t i = 0; i < Util::CountOf(css1sources); i++) { css1sources[i] = 0; } - for (int i = 0; i < countof(musicsources); i++) { + for (size_t i = 0; i < Util::CountOf(musicsources); i++) { musicsources[i] = 0; } } @@ -458,7 +459,7 @@ void Mixer::Init(const char* device) format.channels = have.channels; format.freq = have.freq; const char* filename = get_file_path(PATH_ID_CSS1); - for (int i = 0; i < countof(css1sources); i++) { + for (size_t i = 0; i < Util::CountOf(css1sources); i++) { Source_Sample* source_sample = new Source_Sample; if (source_sample->LoadCSS1(filename, i)) { source_sample->Convert(format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional @@ -481,13 +482,13 @@ void Mixer::Close() } Unlock(); SDL_CloseAudioDevice(deviceid); - for (int i = 0; i < countof(css1sources); i++) { + for (size_t i = 0; i < Util::CountOf(css1sources); i++) { if (css1sources[i] && css1sources[i] != &source_null) { delete css1sources[i]; css1sources[i] = 0; } } - for (int i = 0; i < countof(musicsources); i++) { + for (size_t i = 0; i < Util::CountOf(musicsources); i++) { if (musicsources[i] && musicsources[i] != &source_null) { delete musicsources[i]; musicsources[i] = 0; @@ -530,9 +531,9 @@ void Mixer::Stop(Channel& channel) Unlock(); } -bool Mixer::LoadMusic(int pathId) +bool Mixer::LoadMusic(size_t pathId) { - if (pathId >= countof(musicsources)) { + if (pathId >= Util::CountOf(musicsources)) { return false; } if (!musicsources[pathId]) { @@ -797,14 +798,14 @@ void Mixer_Init(const char* device) gMixer.Init(device); } -void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone) +void* Mixer_Play_Effect(size_t id, int loop, int volume, float pan, double rate, int deleteondone) { if (gOpenRCT2Headless) return 0; if (!gConfigSound.sound) { return 0; } - if (id >= countof(gMixer.css1sources)) { + if (id >= Util::CountOf(gMixer.css1sources)) { return 0; } gMixer.Lock(); diff --git a/src/audio/mixer.h b/src/audio/mixer.h index 4b2aeccbac..5d1e8a59b9 100644 --- a/src/audio/mixer.h +++ b/src/audio/mixer.h @@ -166,7 +166,7 @@ public: void Unlock(); Channel* Play(Source& source, int loop, bool deleteondone, bool deletesourceondone); void Stop(Channel& channel); - bool LoadMusic(int pathid); + bool LoadMusic(size_t pathid); void SetVolume(float volume); Source* css1sources[SOUND_MAXID]; @@ -201,7 +201,7 @@ extern "C" #endif void Mixer_Init(const char* device); -void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone); +void* Mixer_Play_Effect(size_t id, int loop, int volume, float pan, double rate, int deleteondone); void Mixer_Stop_Channel(void* channel); void Mixer_Channel_Volume(void* channel, int volume); void Mixer_Channel_Pan(void* channel, float pan); diff --git a/src/core/Util.hpp b/src/core/Util.hpp new file mode 100644 index 0000000000..4a8df1ce1c --- /dev/null +++ b/src/core/Util.hpp @@ -0,0 +1,20 @@ +#ifndef _UTIL_HPP_ +#define _UTIL_HPP_ + +#include + +/** + * Common utility functions. + */ +namespace Util { + +// Based on http://www.g-truc.net/post-0708.html +template +constexpr size_t CountOf(T const (&)[N]) noexcept +{ + return N; +} + +} // namespace Util + +#endif // _UTIL_HPP_ diff --git a/src/network/network.cpp b/src/network/network.cpp index 3f6f58ddf6..81d087295f 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -36,6 +36,7 @@ extern "C" { #include #include #include +#include "../core/Util.hpp" extern "C" { #include "../config.h" #include "../game.h" @@ -844,10 +845,10 @@ std::string Network::GenerateAdvertiseKey() static char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char key[17]; for (int i = 0; i < 16; i++) { - int hexCharIndex = util_rand() % countof(hexChars); + int hexCharIndex = util_rand() % Util::CountOf(hexChars); key[i] = hexChars[hexCharIndex]; } - key[countof(key) - 1] = 0; + key[Util::CountOf(key) - 1] = 0; return key; } diff --git a/src/platform/posix.c b/src/platform/posix.c index c56b77ee78..e276911307 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -554,10 +554,10 @@ void platform_resolve_user_data_path() char buffer[MAX_PATH]; buffer[0] = '\0'; log_verbose("buffer = '%s'", buffer); - + const char *homedir = getpwuid(getuid())->pw_dir; platform_posix_sub_user_data_path(buffer, homedir, separator); - + log_verbose("OpenRCT2 user data directory = '%s'", buffer); int len = strnlen(buffer, MAX_PATH); wchar_t *w_buffer = regular_to_wchar(buffer); diff --git a/src/rct2.h b/src/rct2.h index ded705f7b5..fdf89ea8b6 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -81,7 +81,30 @@ typedef utf16* utf16string; // Rounds an integer down to the given power of 2. y must be a power of 2. #define floor2(x, y) ((x) & (~((y) - 1))) -#define countof(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) + +#ifndef __cplusplus +// in C++ you should be using Util::CountOf +#ifdef __GNUC__ +/** + * Force a compilation error if condition is true, but also produce a + * result (of value 0 and type size_t), so the expression can be used + * e.g. in a structure initializer (or where-ever else comma expressions + * aren't permitted). + */ +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) + +/* &a[0] degrades to a pointer: a different type from an array */ +#define __must_be_array(a) \ + BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0]))) + +// based on http://lxr.free-electrons.com/source/include/linux/kernel.h#L54 +#define countof(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) +#elif defined (_MSC_VER) + #define countof(arr) _countof(arr) +#else + #define countof(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif // __GNUC__ +#endif // __cplusplus #ifndef _MSC_VER // use similar struct packing as MSVC for our structs