From 593a14958c3b627a4e6ec30cf97f65b1adfcb35f Mon Sep 17 00:00:00 2001 From: RealTimeChris <40668522+RealTimeChris@users.noreply.github.com> Date: Sun, 17 Sep 2023 18:51:36 -0400 Subject: [PATCH 1/3] Updating to fix the clamping behavior of the AVX-512 implementation. Realized that I had done this wrong in the previous implementation. Also edited the name of a variable. Also, just edited the loads to use aligned loads instead of unaligned. --- include/dpp/isa_detection.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/include/dpp/isa_detection.h b/include/dpp/isa_detection.h index 233baedb7f..0c5fe7b398 100644 --- a/include/dpp/isa_detection.h +++ b/include/dpp/isa_detection.h @@ -155,11 +155,11 @@ namespace dpp { * @return An AVX512 register containing gathered values. */ template inline static avx_512_float gather_values(value_type* values) { - float new_array[byte_blocks_per_register]{}; + alignas(64) float new_array[byte_blocks_per_register]{}; for (size_t x = 0; x < byte_blocks_per_register; ++x) { new_array[x] = static_cast(values[x]); } - return _mm512_loadu_ps(new_array); + return _mm512_load_ps(new_array); } /** @@ -177,9 +177,13 @@ namespace dpp { _mm512_mul_ps(_mm512_set1_ps(increment), _mm512_set_ps(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f)))) }; - current_samples_new = _mm512_mask_blend_ps(_mm512_cmp_ps_mask(current_samples_new, _mm512_set1_ps(0.0f), _CMP_GE_OQ), - _mm512_max_ps(current_samples_new, _mm512_set1_ps(static_cast(std::numeric_limits::min()))), - _mm512_min_ps(current_samples_new, _mm512_set1_ps(static_cast(std::numeric_limits::max())))); + __m512 lower_limit = _mm512_set1_ps(static_cast(std::numeric_limits::min())); + __m512 upper_limit = _mm512_set1_ps(static_cast(std::numeric_limits::max())); + + __mmask16 mask_ge = _mm512_cmp_ps_mask(current_samples_new, _mm512_set1_ps(0.0f), _CMP_GE_OQ); + + current_samples_new = _mm512_mask_max_ps(current_samples_new, mask_ge, current_samples_new, lower_limit); + current_samples_new = _mm512_mask_min_ps(current_samples_new, ~mask_ge, current_samples_new, upper_limit); store_values(_mm512_cvtps_epi32(current_samples_new), data_out); } @@ -228,11 +232,11 @@ namespace dpp { * @return An AVX2 register containing gathered values. */ template inline static avx_2_float gather_values(value_type* values) { - float new_array[byte_blocks_per_register]{}; + alignas(32) float new_array[byte_blocks_per_register]{}; for (size_t x = 0; x < byte_blocks_per_register; ++x) { new_array[x] = static_cast(values[x]); } - return _mm256_loadu_ps(new_array); + return _mm256_load_ps(new_array); } /** @@ -302,11 +306,11 @@ namespace dpp { * @return An AVX register containing gathered values. */ template inline static avx_float gather_values(value_type* values) { - float new_array[byte_blocks_per_register]{}; + alignas(16) float new_array[byte_blocks_per_register]{}; for (size_t x = 0; x < byte_blocks_per_register; ++x) { new_array[x] = static_cast(values[x]); } - return _mm_loadu_ps(new_array); + return _mm_load_ps(new_array); } /** @@ -365,8 +369,8 @@ namespace dpp { */ inline static void collect_single_register(int32_t* data_in, int16_t* data_out, float current_gain, float increment) { for (uint64_t x = 0; x < byte_blocks_per_register; ++x) { - auto increment_neww = increment * x; - auto current_gain_new = current_gain + increment_neww; + auto increment_new = increment * x; + auto current_gain_new = current_gain + increment_new; auto current_sample_new = data_in[x] * current_gain_new; if (current_sample_new >= std::numeric_limits::max()) { current_sample_new = std::numeric_limits::max(); From 889435ade1b4976f38040cd5d4facad82c90fe32 Mon Sep 17 00:00:00 2001 From: RealTimeChris <40668522+RealTimeChris@users.noreply.github.com> Date: Tue, 19 Sep 2023 20:20:57 -0400 Subject: [PATCH 2/3] Enhancement: Improving the efficiency of the AVX-implementations, as well as encapsulating some of their functions. Can't believe I didn't notice this before. --- include/dpp/isa/avx.h | 110 ++++++++++++++-------------------- include/dpp/isa/avx2.h | 120 ++++++++++++++----------------------- include/dpp/isa/avx512.h | 97 ++++++++++++++---------------- include/dpp/isa/fallback.h | 7 +-- 4 files changed, 138 insertions(+), 196 deletions(-) diff --git a/include/dpp/isa/avx.h b/include/dpp/isa/avx.h index 9f1d8b025e..9dc66b0d2b 100644 --- a/include/dpp/isa/avx.h +++ b/include/dpp/isa/avx.h @@ -23,80 +23,22 @@ #if defined _MSC_VER || defined __GNUC__ || defined __clang__ #include - -#ifdef max - #undef max -#endif -#ifdef min - #undef min -#endif +#include namespace dpp { using avx_float = __m128; - using avx_int = __m128i; - - /* - * @brief Extracts a 32-bit integer from a 128-bit AVX register. - * @param value The AVX register containing packed 32-bit integers. - * @param index The index of the 32-bit integer to extract (0-3). - * @return The extracted 32-bit integer. - */ - inline int32_t extract_int32_from_avx(const avx_int& value, int64_t index) { - switch (index) { - case 0: { - return _mm_extract_epi32(value, 0); - } - case 1: { - return _mm_extract_epi32(value, 1); - } - case 2: { - return _mm_extract_epi32(value, 2); - } - case 3: { - return _mm_extract_epi32(value, 3); - } - default: { - return _mm_extract_epi32(value, 0); - } - } - } - + /** * @brief A class for audio mixing operations using AVX instructions. */ class audio_mixer { public: - /* - * @brief The number of 32-bit values per CPU register. - */ - inline static constexpr int32_t byte_blocks_per_register{ 4 }; - - /* - * @brief Stores values from a 128-bit AVX vector to a storage location. - * @tparam value_type The target value type for storage. - * @param values_to_store The 128-bit AVX vector containing values to store. - * @param storage_location Pointer to the storage location. - */ - template inline static void store_values(const avx_int& values_to_store, value_type* storage_location) { - for (int64_t x = 0; x < byte_blocks_per_register; ++x) { - storage_location[x] = static_cast(extract_int32_from_avx(values_to_store, x)); - } - } /** - * @brief Specialization for gathering non-float values into an AVX register. - * @tparam value_type The type of values being gathered. - * @tparam Indices Parameter pack of indices for gathering values. - * @return An AVX register containing gathered values. + * @brief The number of 32-bit values per CPU register. */ - template inline static avx_float gather_values(value_type* values) { - alignas(16) float new_array[byte_blocks_per_register]{}; - for (size_t x = 0; x < byte_blocks_per_register; ++x) { - new_array[x] = static_cast(values[x]); - } - return _mm_load_ps(new_array); - } + inline static constexpr int32_t byte_blocks_per_register{ 4 }; /** * @brief Collect a single register worth of data from data_in, apply gain and increment, and store the result in data_out. @@ -115,7 +57,7 @@ namespace dpp { _mm_min_ps(current_samples_new, _mm_set1_ps(static_cast(std::numeric_limits::max()))), _mm_cmp_ps(current_samples_new, _mm_set1_ps(0.0f), _CMP_GE_OQ)); - store_values(_mm_cvtps_epi32(current_samples_new), data_out); + store_values(current_samples_new, data_out); } /** @@ -126,9 +68,49 @@ namespace dpp { * @param decoded_data Pointer to the array of int16_t values. */ inline static void combine_samples(int32_t* up_sampled_vector, const int16_t* decoded_data) { - auto newValues{ _mm_cvtps_epi32(_mm_add_ps(gather_values(up_sampled_vector), gather_values(decoded_data))) }; + auto newValues{ _mm_add_ps(gather_values(up_sampled_vector), gather_values(decoded_data)) }; store_values(newValues, up_sampled_vector); } + + protected: + + /** + * @brief Stores values from a 128-bit AVX vector to a storage location. + * @tparam value_type The target value type for storage. + * @param values_to_store The 128-bit AVX vector containing values to store. + * @param storage_location Pointer to the storage location. + */ + template inline static void store_values(const avx_float& values_to_store, value_type* storage_location) { + for (int64_t x = 0; x < byte_blocks_per_register; ++x) { + storage_location[x] = static_cast(extract_float_from_avx(values_to_store, x)); + } + } + + /** + * @brief Specialization for gathering non-float values into an AVX register. + * @tparam value_type The type of values being gathered. + * @tparam Indices Parameter pack of indices for gathering values. + * @return An AVX register containing gathered values. + */ + template inline static avx_float gather_values(value_type* values) { + alignas(16) float new_array[byte_blocks_per_register]{}; + for (uint64_t x = 0; x < byte_blocks_per_register; ++x) { + new_array[x] = static_cast(values[x]); + } + return _mm256_load_ps(new_array); + } + + /** + * @brief Extracts a 32-bit integer from a 128-bit AVX register. + * @param value The AVX register containing packed 32-bit integers. + * @param index The index of the 32-bit integer to extract (0-3). + * @return The extracted 32-bit integer. + */ + inline static float extract_float_from_avx(const avx_float& value, int64_t index) { + alignas(16) float new_array[4]{}; + _mm_store_ps(new_array, value); + return new_array[index]; + } }; } // namespace dpp diff --git a/include/dpp/isa/avx2.h b/include/dpp/isa/avx2.h index 8f89cb9509..de53274293 100644 --- a/include/dpp/isa/avx2.h +++ b/include/dpp/isa/avx2.h @@ -23,92 +23,22 @@ #if defined _MSC_VER || defined __GNUC__ || defined __clang__ #include - -#ifdef max - #undef max -#endif -#ifdef min - #undef min -#endif +#include namespace dpp { using avx_2_float = __m256; - using avx_2_int = __m256i; - - /* - * @brief Extracts a 32-bit integer from a 256-bit AVX2 register. - * @param value The AVX2 register containing packed 32-bit integers. - * @param index The index of the 32bit integer to extract (0-7). - * @return The extracted 32-bit integer. - */ - inline int32_t extract_int32_from_avx2(const avx_2_int& value, int64_t index) { - switch (index) { - case 0: { - return _mm256_extract_epi32(value, 0); - } - case 1: { - return _mm256_extract_epi32(value, 1); - } - case 2: { - return _mm256_extract_epi32(value, 2); - } - case 3: { - return _mm256_extract_epi32(value, 3); - } - case 4: { - return _mm256_extract_epi32(value, 4); - } - case 5: { - return _mm256_extract_epi32(value, 5); - } - case 6: { - return _mm256_extract_epi32(value, 6); - } - case 7: { - return _mm256_extract_epi32(value, 7); - } - default: { - return _mm256_extract_epi32(value, 0); - } - } - } /** * @brief A class for audio mixing operations using AVX2 instructions. */ class audio_mixer { public: - /* - * @brief The number of 32-bit values per CPU register. - */ - inline static constexpr int32_t byte_blocks_per_register{ 8 }; - - /* - * @brief Stores values from a 256-bit AVX2 vector to a storage location. - * @tparam value_type The target value type for storage. - * @param values_to_store The 256-bit AVX2 vector containing values to store. - * @param storage_location Pointer to the storage location. - */ - template inline static void store_values(const avx_2_int& values_to_store, value_type* storage_location) { - for (int64_t x = 0; x < byte_blocks_per_register; ++x) { - storage_location[x] = static_cast(extract_int32_from_avx2(values_to_store, x)); - } - } /** - * @brief Specialization for gathering non-float values into an AVX2 register. - * @tparam value_type The type of values being gathered. - * @tparam Indices Parameter pack of indices for gathering values. - * @return An AVX2 register containing gathered values. + * @brief The number of 32-bit values per CPU register. */ - template inline static avx_2_float gather_values(value_type* values) { - alignas(32) float new_array[byte_blocks_per_register]{}; - for (size_t x = 0; x < byte_blocks_per_register; ++x) { - new_array[x] = static_cast(values[x]); - } - return _mm256_load_ps(new_array); - } + inline static constexpr int32_t byte_blocks_per_register{ 8 }; /** * @brief Collect a single register worth of data from data_in, apply gain and increment, and store the result in data_out. @@ -129,7 +59,7 @@ namespace dpp { _mm256_min_ps(current_samples_new, _mm256_set1_ps(static_cast(std::numeric_limits::max()))), _mm256_cmp_ps(current_samples_new, _mm256_set1_ps(0.0f), _CMP_GE_OQ)); - store_values(_mm256_cvtps_epi32(current_samples_new), data_out); + store_values(current_samples_new, data_out); } /** @@ -141,9 +71,49 @@ namespace dpp { * @param x Index to select a specific set of elements to combine. */ inline static void combine_samples(int32_t* up_sampled_vector, const int16_t* decoded_data) { - auto newValues{ _mm256_cvtps_epi32(_mm256_add_ps(gather_values(up_sampled_vector), gather_values(decoded_data))) }; + auto newValues{ _mm256_add_ps(gather_values(up_sampled_vector), gather_values(decoded_data)) }; store_values(newValues, up_sampled_vector); } + + protected: + + /** + * @brief Stores values from a 256-bit AVX2 vector to a storage location. + * @tparam value_type The target value type for storage. + * @param values_to_store The 256-bit AVX2 vector containing values to store. + * @param storage_location Pointer to the storage location. + */ + template inline static void store_values(const avx_2_float& values_to_store, value_type* storage_location) { + for (int64_t x = 0; x < byte_blocks_per_register; ++x) { + storage_location[x] = static_cast(extract_float_from_avx_2(values_to_store, x)); + } + } + + /** + * @brief Specialization for gathering non-float values into an AVX2 register. + * @tparam value_type The type of values being gathered. + * @tparam Indices Parameter pack of indices for gathering values. + * @return An AVX2 register containing gathered values. + */ + template inline static avx_2_float gather_values(value_type* values) { + alignas(32) float new_array[byte_blocks_per_register]{}; + for (uint64_t x = 0; x < byte_blocks_per_register; ++x) { + new_array[x] = static_cast(values[x]); + } + return _mm256_load_ps(new_array); + } + + /** + * @brief Extracts a 32-bit integer from a 256-bit AVX2 register. + * @param value The AVX2 register containing packed 32-bit integers. + * @param index The index of the 32-bit integer to extract (0-7). + * @return The extracted 32-bit integer. + */ + inline static float extract_float_from_avx_2(const avx_2_float& value, int64_t index) { + alignas(32) float new_array[byte_blocks_per_register]{}; + _mm256_store_ps(new_array, value); + return new_array[index]; + } }; } // namespace dpp diff --git a/include/dpp/isa/avx512.h b/include/dpp/isa/avx512.h index b691242b9f..3fa9b31096 100644 --- a/include/dpp/isa/avx512.h +++ b/include/dpp/isa/avx512.h @@ -23,67 +23,22 @@ #if defined _MSC_VER || defined __GNUC__ || defined __clang__ #include - -#ifdef max - #undef max -#endif -#ifdef min - #undef min -#endif - +#include namespace dpp { using avx_512_float = __m512; - using avx_512_int = __m512i; - - /* - * @brief Extracts a 32-bit integer from a 512-bit AVX-512 register. - * @param value The AVX-512 register containing packed 32-bit integers. - * @param index The index of the 32-bit integer to extract (0-15). - * @return The extracted 32-bit integer. - */ - inline int32_t extract_int32_from_avx512(const avx_512_int& value, int64_t index) { - alignas(64) int32_t result[32]; - _mm512_store_si512(result, value); - return result[index]; - } - + /** * @brief A class for audio mixing operations using AVX512 instructions. */ class audio_mixer { public: - /* - * @brief The number of 32-bit values per CPU register. - */ - inline static constexpr int32_t byte_blocks_per_register{ 16 }; - - /* - * @brief Stores values from a 512-bit AVX512 vector to a storage location. - * @tparam value_type The target value type for storage. - * @param values_to_store The 512-bit AVX512 vector containing values to store. - * @param storage_location Pointer to the storage location. - */ - template inline static void store_values(const avx_512_int& values_to_store, value_type* storage_location) { - for (int64_t x = 0; x < byte_blocks_per_register; ++x) { - storage_location[x] = static_cast(extract_int32_from_avx512(values_to_store, x)); - } - } /** - * @brief Specialization for gathering non-float values into an AVX512 register. - * @tparam value_type The type of values being gathered. - * @tparam Indices Parameter pack of indices for gathering values. - * @return An AVX512 register containing gathered values. + * @brief The number of 32-bit values per CPU register. */ - template inline static avx_512_float gather_values(value_type* values) { - alignas(64) float new_array[byte_blocks_per_register]{}; - for (size_t x = 0; x < byte_blocks_per_register; ++x) { - new_array[x] = static_cast(values[x]); - } - return _mm512_load_ps(new_array); - } + inline static constexpr int32_t byte_blocks_per_register{ 16 }; /** * @brief Collect a single register worth of data from data_in, apply gain and increment, and store the result in data_out. @@ -108,7 +63,7 @@ namespace dpp { current_samples_new = _mm512_mask_max_ps(current_samples_new, mask_ge, current_samples_new, lower_limit); current_samples_new = _mm512_mask_min_ps(current_samples_new, ~mask_ge, current_samples_new, upper_limit); - store_values(_mm512_cvtps_epi32(current_samples_new), data_out); + store_values(current_samples_new, data_out); } /** @@ -119,9 +74,49 @@ namespace dpp { * @param decoded_data Pointer to the array of int16_t values. */ inline static void combine_samples(int32_t* up_sampled_vector, const int16_t* decoded_data) { - auto newValues{ _mm512_cvtps_epi32(_mm512_add_ps(gather_values(up_sampled_vector), gather_values(decoded_data))) }; + auto newValues{ _mm512_add_ps(gather_values(up_sampled_vector), gather_values(decoded_data)) }; store_values(newValues, up_sampled_vector); } + + protected: + + /** + * @brief Stores values from a 512-bit AVX512 vector to a storage location. + * @tparam value_type The target value type for storage. + * @param values_to_store The 512-bit AVX512 vector containing values to store. + * @param storage_location Pointer to the storage location. + */ + template inline static void store_values(const avx_512_float& values_to_store, value_type* storage_location) { + for (int64_t x = 0; x < byte_blocks_per_register; ++x) { + storage_location[x] = static_cast(extract_float_from_avx_512(values_to_store, x)); + } + } + + /** + * @brief Specialization for gathering non-float values into an AVX512 register. + * @tparam value_type The type of values being gathered. + * @tparam Indices Parameter pack of indices for gathering values. + * @return An AVX512 register containing gathered values. + */ + template inline static avx_512_float gather_values(value_type* values) { + alignas(64) float new_array[byte_blocks_per_register]{}; + for (uint64_t x = 0; x < byte_blocks_per_register; ++x) { + new_array[x] = static_cast(values[x]); + } + return _mm512_load_ps(new_array); + } + + /** + * @brief Extracts a 32-bit integer from a 512-bit AVX512 register. + * @param value The AVX512 register containing packed 32-bit integers. + * @param index The index of the 32-bit integer to extract (0-15). + * @return The extracted 32-bit integer. + */ + inline static float extract_float_from_avx_512(const avx_512_float& value, int64_t index) { + alignas(64) float new_array[byte_blocks_per_register]{}; + _mm512_store_ps(new_array, value); + return new_array[index]; + } }; } // namespace dpp diff --git a/include/dpp/isa/fallback.h b/include/dpp/isa/fallback.h index 2ce44c4464..147ff51d0a 100644 --- a/include/dpp/isa/fallback.h +++ b/include/dpp/isa/fallback.h @@ -20,12 +20,7 @@ ************************************************************************************/ #pragma once -#ifdef max - #undef max -#endif -#ifdef min - #undef min -#endif +#include namespace dpp { From 9012b615ea427ab62acabb2209e079dc0d290d1f Mon Sep 17 00:00:00 2001 From: RealTimeChris <40668522+RealTimeChris@users.noreply.github.com> Date: Thu, 21 Sep 2023 15:33:01 -0400 Subject: [PATCH 3/3] Enhancement: Reducing memory usage by removing the vtable in managed. Have applied the CRTP to keep the interfaces identical, as well as added snowflakes to the necessary classes. --- include/dpp/appcommand.h | 8 +++++-- include/dpp/application.h | 3 ++- include/dpp/automod.h | 2 +- include/dpp/cache.h | 3 +-- include/dpp/channel.h | 9 ++++++-- include/dpp/collector.h | 4 +++- include/dpp/emoji.h | 8 +++++-- include/dpp/guild.h | 13 ++++++++--- include/dpp/integration.h | 4 +++- include/dpp/managed.h | 35 +++++++++++++++++------------- include/dpp/message.h | 12 +++++++--- include/dpp/role.h | 6 ++++- include/dpp/scheduled_event.h | 3 ++- include/dpp/stage_instance.h | 4 +++- include/dpp/user.h | 4 +++- include/dpp/webhook.h | 4 +++- src/dpp/cache.cpp | 3 +-- src/dpp/managed.cpp | 41 ----------------------------------- src/unittest/test.cpp | 4 ++-- src/unittest/test.h | 5 +++-- 20 files changed, 90 insertions(+), 85 deletions(-) delete mode 100644 src/dpp/managed.cpp diff --git a/include/dpp/appcommand.h b/include/dpp/appcommand.h index 7cae5d28ad..e65b98bbde 100644 --- a/include/dpp/appcommand.h +++ b/include/dpp/appcommand.h @@ -675,7 +675,7 @@ void from_json(const nlohmann::json& j, autocomplete_interaction& ai); * into the events on_form_submit, on_slashcommand, on_user_context_menu, * on_button_click, on_select_menu, etc. */ -class DPP_EXPORT interaction : public managed, public json_interface { +class DPP_EXPORT interaction : public managed, public json_interface { /** * @brief Get a resolved object from the resolved set @@ -705,6 +705,7 @@ class DPP_EXPORT interaction : public managed, public json_interface { +class DPP_EXPORT slashcommand : public managed, public json_interface { public: /** * @brief Application id (usually matches your bots id) */ snowflake application_id; + /** Unique identifier */ + snowflake id; + /** * @brief Context menu type, defaults to dpp::ctxm_chat_input */ diff --git a/include/dpp/application.h b/include/dpp/application.h index 24a0b49442..ea80069883 100644 --- a/include/dpp/application.h +++ b/include/dpp/application.h @@ -116,7 +116,7 @@ class DPP_EXPORT app_team { /** * @brief The application class represents details of a bot application */ -class DPP_EXPORT application : public managed, public json_interface { +class DPP_EXPORT application : public managed, public json_interface { public: std::string name; //!< the name of the app utility::iconhash icon; //!< the icon hash of the app (may be empty) @@ -139,6 +139,7 @@ class DPP_EXPORT application : public managed, public json_interface { /** * @brief Represents an automod rule */ -class DPP_EXPORT automod_rule : public managed, public json_interface { +class DPP_EXPORT automod_rule : public managed, public json_interface { public: /** * @brief the id of this rule diff --git a/include/dpp/cache.h b/include/dpp/cache.h index 5895af576d..57af947364 100644 --- a/include/dpp/cache.h +++ b/include/dpp/cache.h @@ -29,8 +29,7 @@ #include namespace dpp { - -extern DPP_EXPORT std::unordered_map deletion_queue; +extern DPP_EXPORT std::unordered_map deletion_queue; extern DPP_EXPORT std::mutex deletion_mutex; /** forward declaration */ diff --git a/include/dpp/channel.h b/include/dpp/channel.h index afa09823d9..0b5cb57c7d 100644 --- a/include/dpp/channel.h +++ b/include/dpp/channel.h @@ -197,13 +197,15 @@ struct DPP_EXPORT thread_member /** * @brief Represents a tag that is able to be applied to a thread in a forum or media channel */ -struct DPP_EXPORT forum_tag : public managed, public json_interface { +struct DPP_EXPORT forum_tag : public managed, public json_interface { /** The name of the tag (0-20 characters) */ std::string name; /** The emoji of the tag. Contains either nothing, the id of a guild's custom emoji or the unicode character of the emoji */ std::variant emoji; /** Whether this tag can only be added to or removed from threads by a member with the `MANAGE_THREADS` permission */ bool moderated; + /** id of the channel the message was sent in */ + snowflake id; /** Constructor */ forum_tag(); @@ -254,11 +256,14 @@ typedef std::unordered_map thread_member_map; * There are one of these for every channel type except threads. Threads are * special snowflakes. Get it? A Discord pun. Hahaha. .... I'll get my coat. */ -class DPP_EXPORT channel : public managed, public json_interface { +class DPP_EXPORT channel : public managed, public json_interface { public: /** Channel name (1-100 characters) */ std::string name; + /** Unique identifier */ + snowflake id; + /** Channel topic (0-4096 characters for forum and media channels, 0-1024 characters for all others) */ std::string topic; diff --git a/include/dpp/collector.h b/include/dpp/collector.h index 4e388971c4..cef5ead464 100644 --- a/include/dpp/collector.h +++ b/include/dpp/collector.h @@ -151,8 +151,10 @@ template class collector * @brief Represents a reaction. * Can be filled for use in a collector */ -class collected_reaction : public managed { +class collected_reaction : public managed { public: + /// Unique identifier. + snowflake id; /// Reacting user user react_user; /// Reacting guild diff --git a/include/dpp/emoji.h b/include/dpp/emoji.h index ab95736595..35235a5fd9 100644 --- a/include/dpp/emoji.h +++ b/include/dpp/emoji.h @@ -50,12 +50,16 @@ enum emoji_flags : uint8_t { /** * @brief Represents an emoji for a dpp::guild */ -class DPP_EXPORT emoji : public managed, public json_interface { +class DPP_EXPORT emoji : public managed, public json_interface { public: /** * @brief Emoji name */ std::string name{}; + /** + * @brief Unique identifier. + */ + snowflake id{}; /** * @brief User id who uploaded the emoji */ @@ -100,7 +104,7 @@ class DPP_EXPORT emoji : public managed, public json_interface { /** * @brief Destroy the emoji object */ - ~emoji() override = default; + ~emoji() = default; /** * @brief Copy assignment operator, copies another emoji's data diff --git a/include/dpp/guild.h b/include/dpp/guild.h index dd002319dc..41c3701a5c 100644 --- a/include/dpp/guild.h +++ b/include/dpp/guild.h @@ -587,7 +587,7 @@ typedef std::unordered_map members_container; /** * @brief Represents a guild on Discord (AKA a server) */ -class DPP_EXPORT guild : public managed, public json_interface { +class DPP_EXPORT guild : public managed, public json_interface { public: /** Guild name */ std::string name; @@ -609,6 +609,9 @@ class DPP_EXPORT guild : public managed, public json_interface { /** List of channels on this server */ std::vector channels; + /** Unique identifier */ + snowflake id{}; + /** List of threads on this server */ std::vector threads; @@ -1158,12 +1161,14 @@ enum onboarding_prompt_flags: uint8_t { /** * @brief Represents an onboarding prompt option */ -struct DPP_EXPORT onboarding_prompt_option: public managed, public json_interface { +struct DPP_EXPORT onboarding_prompt_option: public managed, public json_interface { std::vector channel_ids; //!< IDs for channels a member is added to when the option is selected std::vector role_ids; //!< IDs for roles assigned to a member when the option is selected dpp::emoji emoji; //!< Emoji of the option std::string title; //!< Title of the option std::string description; //!< Description of the option + /** Unique identifier */ + snowflake id; /** * @brief Construct a new onboarding prompt option object @@ -1219,11 +1224,13 @@ struct DPP_EXPORT onboarding_prompt_option: public managed, public json_interfac /** * @brief Represents an onboarding prompt */ -struct DPP_EXPORT onboarding_prompt: public managed, public json_interface { +struct DPP_EXPORT onboarding_prompt: public managed, public json_interface { onboarding_prompt_type type; //!< Type of prompt (defaults to dpp::opt_multiple_choice) std::vector options; //!< Options available within the prompt std::string title; //!< Title of the prompt uint8_t flags; //!< A set of flags built from the bitmask defined by dpp::onboarding_prompt_flags + /** Unique identifier */ + snowflake id; /** * @brief Construct a new onboarding prompt object diff --git a/include/dpp/integration.h b/include/dpp/integration.h index b26d40f630..4c7b334e5e 100644 --- a/include/dpp/integration.h +++ b/include/dpp/integration.h @@ -80,8 +80,10 @@ struct DPP_EXPORT integration_app { /** * @brief Represents an integration on a guild, e.g. a connection to twitch. */ -class DPP_EXPORT integration : public managed, public json_interface { +class DPP_EXPORT integration : public managed, public json_interface { public: + //** Unique identifier */ + snowflake id; /** Integration name */ std::string name; /** Integration type */ diff --git a/include/dpp/managed.h b/include/dpp/managed.h index 5e79953517..67c24967c9 100644 --- a/include/dpp/managed.h +++ b/include/dpp/managed.h @@ -26,26 +26,25 @@ namespace dpp { + class managed_base {}; + /** @brief The managed class is the base class for various types that can * be stored in a cache that are identified by a dpp::snowflake id. */ - class DPP_EXPORT managed { + template class managed : public managed_base { public: - /** - * @brief Unique ID of object set by Discord. - * This value contains a timestamp, worker ID, internal server ID, and an incrementing value. - * Only the timestamp is relevant to us as useful metadata. - */ - snowflake id; + /* + * @brief Default constructor. + */ + inline managed() noexcept = default; + /** * @brief Constructor, initialises ID * @param nid ID to set */ - managed(const snowflake nid = 0); - /** - * @brief Destroy the managed object - */ - virtual ~managed() = default; + inline managed(const snowflake nid) { + static_cast(this)->id = nid; + } /** * @brief Get the creation time of this object according to Discord. @@ -53,7 +52,9 @@ namespace dpp { * @return double creation time inferred from the snowflake ID. * The minimum possible value is the first second of 2015. */ - double get_creation_time() const; + inline double get_creation_time() const { + return static_cast(this)->id.get_creation_time(); + } /** * @brief Comparison operator for comparing two managed objects by id @@ -62,7 +63,9 @@ namespace dpp { * @return true objects are the same id * @return false objects are not the same id */ - bool operator==(const managed& other) const noexcept; + inline bool operator==(const managed& other) const noexcept { + return static_cast(this)->id == static_cast(&other)->id; + } /** * @brief Comparison operator for comparing two managed objects by id @@ -71,7 +74,9 @@ namespace dpp { * @return true objects are not the same id * @return false objects are the same id */ - bool operator!=(const managed& other) const noexcept; + inline bool operator!=(const managed& other) const noexcept { + return static_cast(this)->id != static_cast(&other)->id; + } }; } // namespace dpp diff --git a/include/dpp/message.h b/include/dpp/message.h index 422722fb0c..dfe5912f62 100644 --- a/include/dpp/message.h +++ b/include/dpp/message.h @@ -874,7 +874,7 @@ enum sticker_format : uint8_t { /** * @brief Represents stickers received in messages */ -struct DPP_EXPORT sticker : public managed, public json_interface { +struct DPP_EXPORT sticker : public managed, public json_interface { /** Optional: for standard stickers, id of the pack the sticker is from */ snowflake pack_id; @@ -893,6 +893,8 @@ struct DPP_EXPORT sticker : public managed, public json_interface { * here in the library. */ std::string asset; + /** Unique identifier */ + snowflake id; /** The type of sticker */ sticker_type type; /// type of sticker format @@ -957,7 +959,7 @@ struct DPP_EXPORT sticker : public managed, public json_interface { /** * @brief Represents a sticker pack (the built in groups of stickers that all nitro users get to use) */ -struct DPP_EXPORT sticker_pack : public managed, public json_interface { +struct DPP_EXPORT sticker_pack : public managed, public json_interface { /// the stickers in the pack std::map stickers; /// name of the sticker pack @@ -970,6 +972,8 @@ struct DPP_EXPORT sticker_pack : public managed, public json_interface { + /** Unique identifier */ + snowflake id; /** id of the channel the message was sent in */ snowflake channel_id; /** Optional: id of the guild the message was sent in */ diff --git a/include/dpp/role.h b/include/dpp/role.h index 01351b8eb7..cea6796c38 100644 --- a/include/dpp/role.h +++ b/include/dpp/role.h @@ -49,7 +49,7 @@ enum role_flags : uint8_t { * ID as the guild's ID. This is the base permission set applied to all users where no other role or override * applies, and is the starting value of the bit mask looped through to calculate channel permissions. */ -class DPP_EXPORT role : public managed, public json_interface { +class DPP_EXPORT role : public managed, public json_interface { public: /** * @brief Role name @@ -60,6 +60,10 @@ class DPP_EXPORT role : public managed, public json_interface { * @brief Guild ID */ snowflake guild_id; + + /** Unique identifier */ + snowflake id; + /** * @brief Role colour. * A colour of 0 means no colour. If you want a black role, diff --git a/include/dpp/scheduled_event.h b/include/dpp/scheduled_event.h index f128d03611..b2b4ec3406 100644 --- a/include/dpp/scheduled_event.h +++ b/include/dpp/scheduled_event.h @@ -95,7 +95,8 @@ struct DPP_EXPORT event_member { /** * @brief A scheduled event */ -struct DPP_EXPORT scheduled_event : public managed, public json_interface { +struct DPP_EXPORT scheduled_event : public managed, public json_interface { + snowflake id; //! Unique identifier snowflake guild_id; //!< the guild id which the scheduled event belongs to snowflake channel_id; //!< the channel id in which the scheduled event will be hosted, or null if scheduled entity type is EXTERNAL (may be empty) snowflake creator_id; //!< Optional: the id of the user that created the scheduled event diff --git a/include/dpp/stage_instance.h b/include/dpp/stage_instance.h index c75b103a9f..e227def117 100644 --- a/include/dpp/stage_instance.h +++ b/include/dpp/stage_instance.h @@ -43,7 +43,7 @@ enum stage_privacy_level : uint8_t { * @brief A stage instance. * Stage instances are like a conference facility, with moderators/speakers and listeners. */ -struct DPP_EXPORT stage_instance : public managed, public json_interface { +struct DPP_EXPORT stage_instance : public managed, public json_interface { /// The guild id of the associated Stage channel snowflake guild_id; /// The id of the associated Stage channel @@ -54,6 +54,8 @@ struct DPP_EXPORT stage_instance : public managed, public json_interface { +class DPP_EXPORT user : public managed, public json_interface { public: /** Discord username */ std::string username; @@ -93,6 +93,8 @@ class DPP_EXPORT user : public managed, public json_interface { std::string global_name; /** Avatar hash */ utility::iconhash avatar; + /** Unique identifier */ + snowflake id; /** Avatar decoration hash */ utility::iconhash avatar_decoration; /** Flags built from a bitmask of values in dpp::user_flags */ diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index bb046570cf..214c3be4d4 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -41,7 +41,7 @@ enum webhook_type { /** * @brief Represents a discord webhook */ -class DPP_EXPORT webhook : public managed, public json_interface { +class DPP_EXPORT webhook : public managed, public json_interface { public: uint8_t type; //!< the type of the webhook snowflake guild_id; //!< Optional: the guild id this webhook is for @@ -52,6 +52,8 @@ class DPP_EXPORT webhook : public managed, public json_interface { std::string token; //!< Optional: the secure token of the webhook (returned for Incoming Webhooks) snowflake application_id; //!< the bot/OAuth2 application that created this webhook (may be empty) std::string* image_data; //!< base64 encoded image data if uploading a new image + /** Unique identifier */ + snowflake id; /** * @brief Construct a new webhook object diff --git a/src/dpp/cache.cpp b/src/dpp/cache.cpp index 715b829dd8..96d9bb99b1 100644 --- a/src/dpp/cache.cpp +++ b/src/dpp/cache.cpp @@ -27,8 +27,7 @@ #include namespace dpp { - -std::unordered_map deletion_queue; +std::unordered_map deletion_queue; std::mutex deletion_mutex; #define cache_helper(type, cache_name, setter, getter, counter) \ diff --git a/src/dpp/managed.cpp b/src/dpp/managed.cpp deleted file mode 100644 index 2a9d8fb1cb..0000000000 --- a/src/dpp/managed.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/************************************************************************************ - * - * D++, A Lightweight C++ library for Discord - * - * SPDX-License-Identifier: Apache-2.0 - * Copyright 2021 Craig Edwards and D++ contributors - * (https://github.com/brainboxdotcc/DPP/graphs/contributors) - * - * 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. - * - ************************************************************************************/ -#include - -namespace dpp { - -managed::managed(const snowflake nid) : id(nid) { -} - -bool managed::operator==(const managed& other) const noexcept { - return id == other.id; -} - -bool managed::operator!=(const managed& other) const noexcept { - return id != other.id; -} - -double managed::get_creation_time() const { - return this->id.get_creation_time(); -} - -} // namespace dpp diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index f3adb662f9..86499bec8a 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -628,8 +628,8 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b { set_test(TS, false); - dpp::managed m(189759562910400512); - set_test(TS, ((uint64_t) m.get_creation_time()) == 1465312605); + dpp::managed m(189759562910400512); + set_test(TS, ((uint64_t)m.get_creation_time()) == 1465312605); } { diff --git a/src/unittest/test.h b/src/unittest/test.h index 96d531e0a4..dbd8f96397 100644 --- a/src/unittest/test.h +++ b/src/unittest/test.h @@ -250,10 +250,11 @@ DPP_TEST(CORO_MUMBO_JUMBO, "coro: online mumbo jumbo in event handler", tf_onlin void coro_offline_tests(); void coro_online_tests(dpp::cluster *bot); -class test_cached_object_t : public dpp::managed { +class test_cached_object_t : public dpp::managed { public: - test_cached_object_t(dpp::snowflake _id) : dpp::managed(_id) { }; + test_cached_object_t(dpp::snowflake _id) : dpp::managed(_id) { }; virtual ~test_cached_object_t() = default; + dpp::snowflake id; std::string foo; };