Home | History | Annotate | Line # | Download | only in mDNSShared
      1  1.1  christos /*
      2  1.1  christos  * Copyright (c) 2023-2024 Apple Inc. All rights reserved.
      3  1.1  christos  *
      4  1.1  christos  * Licensed under the Apache License, Version 2.0 (the "License");
      5  1.1  christos  * you may not use this file except in compliance with the License.
      6  1.1  christos  * You may obtain a copy of the License at
      7  1.1  christos  *
      8  1.1  christos  *     https://www.apache.org/licenses/LICENSE-2.0
      9  1.1  christos  *
     10  1.1  christos  * Unless required by applicable law or agreed to in writing, software
     11  1.1  christos  * distributed under the License is distributed on an "AS IS" BASIS,
     12  1.1  christos  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  1.1  christos  * See the License for the specific language governing permissions and
     14  1.1  christos  * limitations under the License.
     15  1.1  christos  */
     16  1.1  christos 
     17  1.1  christos #ifndef MDNS_GENERAL_H
     18  1.1  christos #define MDNS_GENERAL_H
     19  1.1  christos 
     20  1.1  christos /*!
     21  1.1  christos  *	@brief
     22  1.1  christos  *		Evaluates to non-zero if compiling for a particular platform.
     23  1.1  christos  *
     24  1.1  christos  *	@param PLATFORM_NAME
     25  1.1  christos  *		The name of the platform, e.g., APPLE.
     26  1.1  christos  */
     27  1.1  christos #define MDNS_PLATFORM(PLATFORM_NAME)	MDNS_PLATFORM_PRIVATE_DEFINITION_ ## PLATFORM_NAME ()
     28  1.1  christos 
     29  1.1  christos /*!
     30  1.1  christos  *	@brief
     31  1.1  christos  *		Evaluates to non-zero if compiling for Apple OSes.
     32  1.1  christos  *
     33  1.1  christos  *	@discussion
     34  1.1  christos  *		`__APPLE__` is defined when compiling for Apple, see
     35  1.1  christos  *		<https://developer.apple.com/library/archive/documentation/Porting/Conceptual/PortingUnix/compiling/compiling.html>.
     36  1.1  christos  */
     37  1.1  christos #if defined(__APPLE__) && __APPLE__
     38  1.1  christos 	#define MDNS_PLATFORM_PRIVATE_DEFINITION_APPLE()	1
     39  1.1  christos #else
     40  1.1  christos 	#define MDNS_PLATFORM_PRIVATE_DEFINITION_APPLE()	0
     41  1.1  christos #endif
     42  1.1  christos 
     43  1.1  christos #if MDNS_PLATFORM(APPLE)
     44  1.1  christos 	#include <TargetConditionals.h>
     45  1.1  christos #endif
     46  1.1  christos 
     47  1.1  christos /*!
     48  1.1  christos  *	@brief
     49  1.1  christos  *		Evaluates to non-zero if compiling for a particular OS.
     50  1.1  christos  *
     51  1.1  christos  *	@param OS_NAME
     52  1.1  christos  *		The name of the OS, e.g., macOS, iOS, etc.
     53  1.1  christos  */
     54  1.1  christos #define MDNS_OS(OS_NAME)	MDNS_OS_PRIVATE_DEFINITION_ ## OS_NAME ()
     55  1.1  christos 
     56  1.1  christos /*!
     57  1.1  christos  *	@brief
     58  1.1  christos  *		Evaluates to non-zero if compiling for macOS.
     59  1.1  christos  *
     60  1.1  christos  *	@discussion
     61  1.1  christos  *		Use `MDNS_OS(macOS)` instead of using this macro directly.
     62  1.1  christos  */
     63  1.1  christos #if defined(TARGET_OS_OSX) && TARGET_OS_OSX
     64  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_macOS()	1
     65  1.1  christos #else
     66  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_macOS()	0
     67  1.1  christos #endif
     68  1.1  christos 
     69  1.1  christos /*!
     70  1.1  christos  *	@brief
     71  1.1  christos  *		Evaluates to non-zero if compiling for iOS.
     72  1.1  christos  *
     73  1.1  christos  *	@discussion
     74  1.1  christos  *		Use `MDNS_OS(iOS)` instead of using this macro directly.
     75  1.1  christos  */
     76  1.1  christos #if defined(TARGET_OS_IOS) && TARGET_OS_IOS
     77  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_iOS()	1
     78  1.1  christos #else
     79  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_iOS()	0
     80  1.1  christos #endif
     81  1.1  christos 
     82  1.1  christos /*!
     83  1.1  christos  *	@brief
     84  1.1  christos  *		Evaluates to non-zero if compiling for watchOS.
     85  1.1  christos  *
     86  1.1  christos  *	@discussion
     87  1.1  christos  *		Use `MDNS_OS(watchOS)` instead of using this macro directly.
     88  1.1  christos  */
     89  1.1  christos #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH
     90  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_watchOS()	1
     91  1.1  christos #else
     92  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_watchOS()	0
     93  1.1  christos #endif
     94  1.1  christos 
     95  1.1  christos /*!
     96  1.1  christos  *	@brief
     97  1.1  christos  *		Evaluates to non-zero if compiling for tvOS.
     98  1.1  christos  *
     99  1.1  christos  *	@discussion
    100  1.1  christos  *		Use `MDNS_OS(tvOS)` instead of using this macro directly.
    101  1.1  christos  */
    102  1.1  christos #if defined(TARGET_OS_TV) && TARGET_OS_TV
    103  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_tvOS()	1
    104  1.1  christos #else
    105  1.1  christos 	#define MDNS_OS_PRIVATE_DEFINITION_tvOS()	0
    106  1.1  christos #endif
    107  1.1  christos 
    108  1.1  christos // Time conversion constants
    109  1.1  christos 
    110  1.1  christos #define MDNS_NANOSECONDS_PER_SECOND		1000000000
    111  1.1  christos #define MDNS_MILLISECONDS_PER_SECOND	1000
    112  1.1  christos #define MDNS_MILLISECONDS_PER_MINUTE	(MDNS_MILLISECONDS_PER_SECOND * MDNS_SECONDS_PER_MINUTE)
    113  1.1  christos #define MDNS_MILLISECONDS_PER_HOUR		(MDNS_MILLISECONDS_PER_SECOND * MDNS_SECONDS_PER_HOUR)
    114  1.1  christos #define MDNS_SECONDS_PER_MINUTE			60
    115  1.1  christos #define MDNS_SECONDS_PER_HOUR			(MDNS_SECONDS_PER_MINUTE * MDNS_MINUTES_PER_HOUR)
    116  1.1  christos #define MDNS_SECONDS_PER_DAY			(MDNS_SECONDS_PER_HOUR * MDNS_HOUR_PER_DAY)
    117  1.1  christos #define MDNS_MINUTES_PER_HOUR			60
    118  1.1  christos #define MDNS_HOUR_PER_DAY				24
    119  1.1  christos 
    120  1.1  christos // Clang's __has_*() builtin macros are defined as zero if not defined.
    121  1.1  christos 
    122  1.1  christos #if !defined(__has_attribute)
    123  1.1  christos 	#define __has_attribute(X)	0
    124  1.1  christos #endif
    125  1.1  christos #if !defined(__has_extension)
    126  1.1  christos 	#define __has_extension(X)	0
    127  1.1  christos #endif
    128  1.1  christos #if !defined(__has_feature)
    129  1.1  christos 	#define __has_feature(X)	0
    130  1.1  christos #endif
    131  1.1  christos 
    132  1.1  christos /*!
    133  1.1  christos  *	@brief
    134  1.1  christos  *		Evaluates to non-zero if the compiler is Clang.
    135  1.1  christos  *
    136  1.1  christos  *	@discussion
    137  1.1  christos  *		__clang__ is defined when compiling with Clang, see
    138  1.1  christos  *		<https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros>.
    139  1.1  christos  */
    140  1.1  christos #if defined(__clang__)
    141  1.1  christos 	#define MDNS_COMPILER_IS_CLANG() 1
    142  1.1  christos #else
    143  1.1  christos 	#define MDNS_COMPILER_IS_CLANG() 0
    144  1.1  christos #endif
    145  1.1  christos 
    146  1.1  christos /*!
    147  1.1  christos  *	@brief
    148  1.1  christos  *		Evaluates to non-zero if the compiler is Clang and its version is at least a specified version.
    149  1.1  christos  *
    150  1.1  christos  *	@param MAJOR
    151  1.1  christos  *		The specified version's major number.
    152  1.1  christos  *
    153  1.1  christos  *	@param MINOR
    154  1.1  christos  *		The specified version's minor number.
    155  1.1  christos  *
    156  1.1  christos  *	@param PATCH_LEVEL
    157  1.1  christos  *		The specified version's patch level.
    158  1.1  christos  *
    159  1.1  christos  *	@discussion
    160  1.1  christos  *		Clang version numbers are of the form "<major number>.<minor number>.<patch level>". See
    161  1.1  christos  *		<https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros>
    162  1.1  christos  */
    163  1.1  christos #if MDNS_COMPILER_IS_CLANG()
    164  1.1  christos 	#define MDNS_CLANG_VERSION_IS_AT_LEAST(MAJOR, MINOR, PATCH_LEVEL) (						\
    165  1.1  christos 		(__clang_major__ > (MAJOR)) || (													\
    166  1.1  christos 			(__clang_major__ == (MAJOR)) && (												\
    167  1.1  christos 				(__clang_minor__ > (MINOR)) || (											\
    168  1.1  christos 					(__clang_minor__ == (MINOR)) && (__clang_patchlevel__ >= (PATCH_LEVEL))	\
    169  1.1  christos 				)																			\
    170  1.1  christos 			)																				\
    171  1.1  christos 		)																					\
    172  1.1  christos 	)
    173  1.1  christos #else
    174  1.1  christos 	#define MDNS_CLANG_VERSION_IS_AT_LEAST(MAJOR, MINOR, PATCH_LEVEL) 0
    175  1.1  christos #endif
    176  1.1  christos 
    177  1.1  christos /*!
    178  1.1  christos  *	@brief
    179  1.1  christos  *		Stringizes the argument and passes it to the _Pragma() operator, which takes a string literal argument.
    180  1.1  christos  *
    181  1.1  christos  *	@param ARG
    182  1.1  christos  *		The argument.
    183  1.1  christos  *
    184  1.1  christos  *	@discussion
    185  1.1  christos  *		Useful for escaping double quotes. For example,
    186  1.1  christos  *
    187  1.1  christos  *			MDNS_PRAGMA_WITH_STRINGIZED_ARGUMENT(clang diagnostic ignored "-Wpadded")
    188  1.1  christos  *
    189  1.1  christos  *		turns into
    190  1.1  christos  *
    191  1.1  christos  *			_Pragma("clang diagnostic ignored \"-Wpadded\"")
    192  1.1  christos  *
    193  1.1  christos  *		See <https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html>.
    194  1.1  christos  */
    195  1.1  christos #define MDNS_PRAGMA_WITH_STRINGIZED_ARGUMENT(ARG)	_Pragma(#ARG)
    196  1.1  christos 
    197  1.1  christos /*!
    198  1.1  christos  *	@brief
    199  1.1  christos  *		For Clang, starts ignoring the specified warning diagnostic flag.
    200  1.1  christos  *
    201  1.1  christos  *	@param WARNING
    202  1.1  christos  *		The warning diagnostic flag.
    203  1.1  christos  *
    204  1.1  christos  *	@discussion
    205  1.1  christos  *		Use MDNS_CLANG_IGNORE_WARNING_END() to undo the effect of this macro.
    206  1.1  christos  */
    207  1.1  christos #if MDNS_COMPILER_IS_CLANG()
    208  1.1  christos 	#define MDNS_CLANG_IGNORE_WARNING_BEGIN(WARNING)	\
    209  1.1  christos 		_Pragma("clang diagnostic push")				\
    210  1.1  christos 		MDNS_PRAGMA_WITH_STRINGIZED_ARGUMENT(clang diagnostic ignored #WARNING)
    211  1.1  christos #else
    212  1.1  christos 	#define MDNS_CLANG_IGNORE_WARNING_BEGIN(WARNING)
    213  1.1  christos #endif
    214  1.1  christos 
    215  1.1  christos /*!
    216  1.1  christos  *	@brief
    217  1.1  christos  *		Use to undo the effect of a previous MDNS_CLANG_IGNORE_WARNING_BEGIN().
    218  1.1  christos  */
    219  1.1  christos #if MDNS_COMPILER_IS_CLANG()
    220  1.1  christos 	#define MDNS_CLANG_IGNORE_WARNING_END()	_Pragma("clang diagnostic pop")
    221  1.1  christos #else
    222  1.1  christos 	#define MDNS_CLANG_IGNORE_WARNING_END()
    223  1.1  christos #endif
    224  1.1  christos 
    225  1.1  christos /*!
    226  1.1  christos  *	@brief
    227  1.1  christos  *		An alternative version of MDNS_CLANG_IGNORE_WARNING_BEGIN() that looks nicer when used among statements.
    228  1.1  christos  *
    229  1.1  christos  *	@discussion
    230  1.1  christos  *		This version looks nicer when used among C statements. Here's an example:
    231  1.1  christos  *
    232  1.1  christos  *			mdns_clang_ignore_warning_begin(-Wformat-nonliteral);
    233  1.1  christos  *			const int n = vsnprintf(dst, len, fmt, args);
    234  1.1  christos  *			mdns_clang_ignore_warning_end();
    235  1.1  christos  */
    236  1.1  christos #define mdns_clang_ignore_warning_begin(WARNING)	\
    237  1.1  christos 	MDNS_CLANG_IGNORE_WARNING_BEGIN(WARNING)		\
    238  1.1  christos 	do {} while (0)
    239  1.1  christos 
    240  1.1  christos /*!
    241  1.1  christos  *	@brief
    242  1.1  christos  *		An alternative version of MDNS_CLANG_IGNORE_WARNING_END() that looks nicer when used among statements.
    243  1.1  christos  *
    244  1.1  christos  *	@discussion
    245  1.1  christos  *		This version looks nicer when used among C statements. Here's an example:
    246  1.1  christos  *
    247  1.1  christos  *			mdns_clang_ignore_warning_begin(-Wformat-nonliteral);
    248  1.1  christos  *			const int n = vsnprintf(dst, len, fmt, args);
    249  1.1  christos  *			mdns_clang_ignore_warning_end();
    250  1.1  christos  */
    251  1.1  christos #define mdns_clang_ignore_warning_end()	\
    252  1.1  christos 	MDNS_CLANG_IGNORE_WARNING_END()		\
    253  1.1  christos 	do {} while (0)
    254  1.1  christos 
    255  1.1  christos /*!
    256  1.1  christos  *	@brief
    257  1.1  christos  *		For Clang, starts ignoring the -Wunaligned-access warning diagnostic flag.
    258  1.1  christos  *
    259  1.1  christos  *	@discussion
    260  1.1  christos  *		The -Wunaligned-access is new in clang version 14.0.3. This macro allow us to conditionally ignore
    261  1.1  christos  *		-Wunaligned-access with Clang 14.0.3 or later. This avoids -Wunknown-warning-option warnings with
    262  1.1  christos  *		earlier Clang versions, which don't recognize -Wunaligned-access.
    263  1.1  christos  */
    264  1.1  christos #if MDNS_CLANG_VERSION_IS_AT_LEAST(14, 0, 3)
    265  1.1  christos 	#define MDNS_CLANG_IGNORE_UNALIGNED_ACCESS_WARNING_BEGIN()	MDNS_CLANG_IGNORE_WARNING_BEGIN(-Wunaligned-access)
    266  1.1  christos #else
    267  1.1  christos 	#define MDNS_CLANG_IGNORE_UNALIGNED_ACCESS_WARNING_BEGIN()
    268  1.1  christos #endif
    269  1.1  christos 
    270  1.1  christos /*!
    271  1.1  christos  *	@brief
    272  1.1  christos  *		Undoes the effect of a previous MDNS_CLANG_IGNORE_UNALIGNED_ACCESS_WARNING_BEGIN().
    273  1.1  christos  */
    274  1.1  christos #if MDNS_CLANG_VERSION_IS_AT_LEAST(14, 0, 3)
    275  1.1  christos 	#define MDNS_CLANG_IGNORE_UNALIGNED_ACCESS_WARNING_END()	MDNS_CLANG_IGNORE_WARNING_END()
    276  1.1  christos #else
    277  1.1  christos 	#define MDNS_CLANG_IGNORE_UNALIGNED_ACCESS_WARNING_END()
    278  1.1  christos #endif
    279  1.1  christos 
    280  1.1  christos /*!
    281  1.1  christos  *	@brief
    282  1.1  christos  *		For Clang, starts ignoring the -Wincompatible-function-pointer-types-strict warning diagnostic flag.
    283  1.1  christos  *
    284  1.1  christos  *	@discussion
    285  1.1  christos  *		-Wincompatible-function-pointer-types-strict is like -Wincompatible-function-pointer-types, but is more
    286  1.1  christos  *		strict in that it warns about function pointer types that are not identical but are still compatible.
    287  1.1  christos  *
    288  1.1  christos  *		The -Wincompatible-function-pointer-types-strict is new in clang version 16.0.0 (see
    289  1.1  christos  *		https://releases.llvm.org/16.0.0/tools/clang/docs/ReleaseNotes.html). This macro allow us to
    290  1.1  christos  *		conditionally ignore -Wincompatible-function-pointer-types-strict with Clang 16.0.0 or later. This
    291  1.1  christos  *		avoids -Wunknown-warning-option warnings with earlier Clang versions, which don't recognize
    292  1.1  christos  *		-Wincompatible-function-pointer-types-strict.
    293  1.1  christos  */
    294  1.1  christos #if MDNS_CLANG_VERSION_IS_AT_LEAST(16, 0, 0)
    295  1.1  christos 	#define MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN() \
    296  1.1  christos 		MDNS_CLANG_IGNORE_WARNING_BEGIN(-Wincompatible-function-pointer-types-strict)
    297  1.1  christos #else
    298  1.1  christos 	#define MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN()
    299  1.1  christos #endif
    300  1.1  christos 
    301  1.1  christos /*!
    302  1.1  christos  *	@brief
    303  1.1  christos  *		Undoes the effect of a previous
    304  1.1  christos  *		MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN().
    305  1.1  christos  */
    306  1.1  christos #if MDNS_CLANG_VERSION_IS_AT_LEAST(16, 0, 0)
    307  1.1  christos 	#define MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_END()	MDNS_CLANG_IGNORE_WARNING_END()
    308  1.1  christos #else
    309  1.1  christos 	#define MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_END()
    310  1.1  christos #endif
    311  1.1  christos 
    312  1.1  christos /*!
    313  1.1  christos  *	@brief
    314  1.1  christos  *		For Clang, treats the specified warning diagnostic flag as an error.
    315  1.1  christos  *
    316  1.1  christos  *	@param WARNING
    317  1.1  christos  *		The warning diagnostic flag.
    318  1.1  christos  *
    319  1.1  christos  *	@discussion
    320  1.1  christos  *		Use MDNS_CLANG_TREAT_WARNING_AS_ERROR_END() to undo the effect of this macro.
    321  1.1  christos  */
    322  1.1  christos #if MDNS_COMPILER_IS_CLANG()
    323  1.1  christos 	#define MDNS_CLANG_TREAT_WARNING_AS_ERROR_BEGIN(WARNING)	\
    324  1.1  christos 		_Pragma("clang diagnostic push")						\
    325  1.1  christos 		MDNS_PRAGMA_WITH_STRINGIZED_ARGUMENT(clang diagnostic error #WARNING)
    326  1.1  christos #else
    327  1.1  christos 	#define MDNS_CLANG_TREAT_WARNING_AS_ERROR_BEGIN(WARNING)
    328  1.1  christos #endif
    329  1.1  christos 
    330  1.1  christos /*!
    331  1.1  christos  *	@brief
    332  1.1  christos  *		Undoes the effect of a previous MDNS_CLANG_TREAT_WARNING_AS_ERROR_BEGIN().
    333  1.1  christos  */
    334  1.1  christos #if MDNS_COMPILER_IS_CLANG()
    335  1.1  christos 	#define MDNS_CLANG_TREAT_WARNING_AS_ERROR_END()	_Pragma("clang diagnostic pop")
    336  1.1  christos #else
    337  1.1  christos 	#define MDNS_CLANG_TREAT_WARNING_AS_ERROR_END()
    338  1.1  christos #endif
    339  1.1  christos 
    340  1.1  christos /*!
    341  1.1  christos  *	@brief
    342  1.1  christos  *		For Clang, specifies that pointers without a nullability qualifier are _Nonnull.
    343  1.1  christos  *
    344  1.1  christos  *	@discussion
    345  1.1  christos  *		See <https://clang.llvm.org/docs/AttributeReference.html#nullability-attributes>.
    346  1.1  christos  */
    347  1.1  christos #if (MDNS_COMPILER_IS_CLANG() && __has_feature(assume_nonnull))
    348  1.1  christos 	#define MDNS_ASSUME_NONNULL_BEGIN	_Pragma("clang assume_nonnull begin")
    349  1.1  christos #else
    350  1.1  christos 	#define MDNS_ASSUME_NONNULL_BEGIN
    351  1.1  christos #endif
    352  1.1  christos 
    353  1.1  christos /*!
    354  1.1  christos  *	@brief
    355  1.1  christos  *		Undoes the effect of a previous MDNS_ASSUME_NONNULL_BEGIN.
    356  1.1  christos  */
    357  1.1  christos #if (MDNS_COMPILER_IS_CLANG() && __has_feature(assume_nonnull))
    358  1.1  christos 	#define MDNS_ASSUME_NONNULL_END	_Pragma("clang assume_nonnull end")
    359  1.1  christos #else
    360  1.1  christos 	#define MDNS_ASSUME_NONNULL_END
    361  1.1  christos #endif
    362  1.1  christos 
    363  1.1  christos /*!
    364  1.1  christos  *	@brief
    365  1.1  christos  *		If supported, an attribute for closed enumeration definitions.
    366  1.1  christos  *
    367  1.1  christos  *	@discussion
    368  1.1  christos  *		See <https://clang.llvm.org/docs/AttributeReference.html#enum-extensibility>.
    369  1.1  christos  */
    370  1.1  christos #if __has_attribute(enum_extensibility)
    371  1.1  christos 	#define MDNS_ENUM_ATTR_CLOSED	__attribute__((enum_extensibility(closed)))
    372  1.1  christos #else
    373  1.1  christos 	#define MDNS_ENUM_ATTR_CLOSED
    374  1.1  christos #endif
    375  1.1  christos 
    376  1.1  christos /*!
    377  1.1  christos  *	@brief
    378  1.1  christos  *		If supported, defines a fixed-width closed enumeration.
    379  1.1  christos  *
    380  1.1  christos  *	@param NAME
    381  1.1  christos  *		The name of the enumeration.
    382  1.1  christos  *
    383  1.1  christos  *	@param UNDERLYING_TYPE
    384  1.1  christos  *		The enumeration's underlying type.
    385  1.1  christos  *
    386  1.1  christos  *	@param ...
    387  1.1  christos  *		The enumerator list.
    388  1.1  christos  *
    389  1.1  christos  *	@discussion
    390  1.1  christos  *		See <https://clang.llvm.org/docs/LanguageExtensions.html#enumerations-with-a-fixed-underlying-type> and
    391  1.1  christos  *		<https://clang.llvm.org/docs/AttributeReference.html#enum-extensibility>.
    392  1.1  christos  */
    393  1.1  christos #if (__has_feature(objc_fixed_enum) || __has_extension(cxx_fixed_enum) || __has_extension(cxx_strong_enums))
    394  1.1  christos 	#define MDNS_CLOSED_ENUM(NAME, UNDERLYING_TYPE, ...)	\
    395  1.1  christos 		typedef enum : UNDERLYING_TYPE {					\
    396  1.1  christos 			__VA_ARGS__										\
    397  1.1  christos 		} MDNS_ENUM_ATTR_CLOSED NAME
    398  1.1  christos #else
    399  1.1  christos 	#define MDNS_CLOSED_ENUM(NAME, UNDERLYING_TYPE, ...)	\
    400  1.1  christos 		typedef UNDERLYING_TYPE NAME;						\
    401  1.1  christos 		enum NAME ## _enum {								\
    402  1.1  christos 			__VA_ARGS__										\
    403  1.1  christos 		} MDNS_ENUM_ATTR_CLOSED
    404  1.1  christos #endif
    405  1.1  christos 
    406  1.1  christos /*!
    407  1.1  christos  *	@brief
    408  1.1  christos  *		If supported, an attribute for flag-like enumeration definitions.
    409  1.1  christos  *
    410  1.1  christos  *	@discussion
    411  1.1  christos  *		See <https://clang.llvm.org/docs/AttributeReference.html#flag-enum>.
    412  1.1  christos  */
    413  1.1  christos #if __has_attribute(flag_enum)
    414  1.1  christos 	#define MDNS_ENUM_ATTR_FLAG	__attribute__((flag_enum))
    415  1.1  christos #else
    416  1.1  christos 	#define MDNS_ENUM_ATTR_FLAG
    417  1.1  christos #endif
    418  1.1  christos 
    419  1.1  christos /*!
    420  1.1  christos  *	@brief
    421  1.1  christos  *		If supported, defines a fixed-width closed flag-like enumeration.
    422  1.1  christos  *
    423  1.1  christos  *	@param NAME
    424  1.1  christos  *		The name of the enumeration.
    425  1.1  christos  *
    426  1.1  christos  *	@param UNDERLYING_TYPE
    427  1.1  christos  *		The enumeration's underlying type.
    428  1.1  christos  *
    429  1.1  christos  *	@param ...
    430  1.1  christos  *		The enumeratior list.
    431  1.1  christos  *
    432  1.1  christos  *	@discussion
    433  1.1  christos  *		See <https://clang.llvm.org/docs/LanguageExtensions.html#enumerations-with-a-fixed-underlying-type> and
    434  1.1  christos  *		<https://clang.llvm.org/docs/AttributeReference.html#flag-enum>.
    435  1.1  christos  */
    436  1.1  christos #if (__has_feature(objc_fixed_enum) || __has_extension(cxx_fixed_enum) || __has_extension(cxx_strong_enums))
    437  1.1  christos 	#define MDNS_CLOSED_OPTIONS(NAME, UNDERLYING_TYPE, ...)	\
    438  1.1  christos 		typedef enum : UNDERLYING_TYPE {					\
    439  1.1  christos 			__VA_ARGS__										\
    440  1.1  christos 		} MDNS_ENUM_ATTR_CLOSED MDNS_ENUM_ATTR_FLAG NAME
    441  1.1  christos #else
    442  1.1  christos 	#define MDNS_CLOSED_OPTIONS(NAME, UNDERLYING_TYPE, ...)	\
    443  1.1  christos 		typedef UNDERLYING_TYPE NAME;						\
    444  1.1  christos 		enum NAME ## _enum {								\
    445  1.1  christos 			__VA_ARGS__										\
    446  1.1  christos 		} MDNS_ENUM_ATTR_CLOSED MDNS_ENUM_ATTR_FLAG
    447  1.1  christos #endif
    448  1.1  christos 
    449  1.1  christos /*!
    450  1.1  christos  *	@brief
    451  1.1  christos  *		For compatibility with C++, marks the beginning of C function declarations.
    452  1.1  christos  *
    453  1.1  christos  *	@discussion
    454  1.1  christos  *		See <https://en.cppreference.com/w/cpp/language/language_linkage>.
    455  1.1  christos  */
    456  1.1  christos #if defined(__cplusplus)
    457  1.1  christos 	#define MDNS_C_DECLARATIONS_BEGIN	extern "C" {
    458  1.1  christos #else
    459  1.1  christos 	#define MDNS_C_DECLARATIONS_BEGIN
    460  1.1  christos #endif
    461  1.1  christos 
    462  1.1  christos /*!
    463  1.1  christos  *	@brief
    464  1.1  christos  *		For compatibility with C++, marks the end of C function declarations.
    465  1.1  christos  *
    466  1.1  christos  *	@discussion
    467  1.1  christos  *		This is the counterpart to MDNS_C_DECLARATIONS_BEGIN.
    468  1.1  christos  */
    469  1.1  christos #if defined(__cplusplus)
    470  1.1  christos 	#define MDNS_C_DECLARATIONS_END	}
    471  1.1  christos #else
    472  1.1  christos 	#define MDNS_C_DECLARATIONS_END
    473  1.1  christos #endif
    474  1.1  christos 
    475  1.1  christos /*!
    476  1.1  christos  *	@brief
    477  1.1  christos  *		Evaluates to non-zero if the compiler conforms to a specific minimum C standard.
    478  1.1  christos  *
    479  1.1  christos  *	@param STANDARD
    480  1.1  christos  *		The C standard.
    481  1.1  christos  */
    482  1.1  christos #define MDNS_C_STANDARD_IS_AT_LEAST(STANDARD)	MDNS_C_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_ ## STANDARD ()
    483  1.1  christos 
    484  1.1  christos /*!
    485  1.1  christos  *	@brief
    486  1.1  christos  *		Evaluates to non-zero if the compiler confroms to the C99 standard or later.
    487  1.1  christos  *
    488  1.1  christos  *	@discussion
    489  1.1  christos  *		__STDC_VERSION__ is a predefined macro that expands to 199901L for the C99 standard. See
    490  1.1  christos  *		<https://en.cppreference.com/w/c/preprocessor/replace>.
    491  1.1  christos  *
    492  1.1  christos  *		Use `MDNS_C_STANDARD_IS_AT_LEAST(C99)` instead of using this macro directly.
    493  1.1  christos  */
    494  1.1  christos #if defined(__STDC_VERSION__)
    495  1.1  christos 	#define MDNS_C_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_C99()	(__STDC_VERSION__ >= 199901L)
    496  1.1  christos #else
    497  1.1  christos 	#define MDNS_C_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_C99()	0
    498  1.1  christos #endif
    499  1.1  christos 
    500  1.1  christos /*!
    501  1.1  christos  *	@brief
    502  1.1  christos  *		Evaluates to non-zero if the compiler confroms to the C11 standard or later.
    503  1.1  christos  *
    504  1.1  christos  *	@discussion
    505  1.1  christos  *		__STDC_VERSION__ is a predefined macro that expands to 201112L for the C11 standard. See
    506  1.1  christos  *		<https://en.cppreference.com/w/c/preprocessor/replace>.
    507  1.1  christos  *
    508  1.1  christos  *		Use `MDNS_C_STANDARD_IS_AT_LEAST(C11)` instead of using this macro directly.
    509  1.1  christos  */
    510  1.1  christos #if defined(__STDC_VERSION__)
    511  1.1  christos 	#define MDNS_C_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_C11()	(__STDC_VERSION__ >= 201112L)
    512  1.1  christos #else
    513  1.1  christos 	#define MDNS_C_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_C11()	0
    514  1.1  christos #endif
    515  1.1  christos 
    516  1.1  christos /*!
    517  1.1  christos  *	@brief
    518  1.1  christos  *		Evaluates to non-zero if the compiler conforms to a specific minimum C++ standard.
    519  1.1  christos  *
    520  1.1  christos  *	@param STANDARD
    521  1.1  christos  *		The C standard.
    522  1.1  christos  */
    523  1.1  christos #define MDNS_CPP_STANDARD_IS_AT_LEAST(STANDARD)	MDNS_CPP_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_ ## STANDARD ()
    524  1.1  christos 
    525  1.1  christos /*!
    526  1.1  christos  *	@brief
    527  1.1  christos  *		Evaluates to non-zero if the compiler confroms to the C++11 standard or later.
    528  1.1  christos  *
    529  1.1  christos  *	@discussion
    530  1.1  christos  *		__cplusplus is a predefined macro that expands to 201103L for the C++11 standard. See
    531  1.1  christos  *		<https://en.cppreference.com/w/cpp/preprocessor/replace>.
    532  1.1  christos  *
    533  1.1  christos  *		Use `MDNS_CPP_STANDARD_IS_AT_LEAST(CPP11)` instead of using this macro directly.
    534  1.1  christos  */
    535  1.1  christos #if defined(__cplusplus)
    536  1.1  christos 	#define MDNS_CPP_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_CPP11()	(__cplusplus >= 201103L)
    537  1.1  christos #else
    538  1.1  christos 	#define MDNS_CPP_STANDARD_PRIVATE_DEFINITION_IS_AT_LEAST_CPP11()	0
    539  1.1  christos #endif
    540  1.1  christos 
    541  1.1  christos /*!
    542  1.1  christos  *	@brief
    543  1.1  christos  *		Causes a compile-time error if an expression evaluates to false.
    544  1.1  christos  *
    545  1.1  christos  *	@param EXPRESSION
    546  1.1  christos  *		The expression.
    547  1.1  christos  *
    548  1.1  christos  *	@param MESSAGE
    549  1.1  christos  *		If supported, a sting literal to include as a diagnostic message if the expression evaluates to false.
    550  1.1  christos  */
    551  1.1  christos #if MDNS_C_STANDARD_IS_AT_LEAST(C11)
    552  1.1  christos 	#define mdns_compile_time_check(EXPRESSION, MESSAGE)	_Static_assert(EXPRESSION, MESSAGE)
    553  1.1  christos #elif MDNS_CPP_STANDARD_IS_AT_LEAST(CPP11)
    554  1.1  christos 	#define mdns_compile_time_check(EXPRESSION, MESSAGE)	static_assert(EXPRESSION, MESSAGE)
    555  1.1  christos #elif defined(__cplusplus)
    556  1.1  christos 	#define	mdns_compile_time_check(EXPRESSION, MESSAGE) \
    557  1.1  christos 		extern "C" int mdns_compile_time_check_failed[(EXPRESSION) ? 1 : -1]
    558  1.1  christos #else
    559  1.1  christos 	#define	mdns_compile_time_check(EXPRESSION, MESSAGE) \
    560  1.1  christos 		extern int mdns_compile_time_check_failed[(EXPRESSION) ? 1 : -1]
    561  1.1  christos #endif
    562  1.1  christos 
    563  1.1  christos /*!
    564  1.1  christos  *	@brief
    565  1.1  christos  *		Causes a compile-time error if an expression evaluates to false.
    566  1.1  christos  *
    567  1.1  christos  *	@param EXPRESSION
    568  1.1  christos  *		The expression.
    569  1.1  christos  *
    570  1.1  christos  *	@discussion
    571  1.1  christos  *		This macro is meant to be used in a local scope, i.e., inside of a function or a block. For the global
    572  1.1  christos  *		scope, use `mdns_compile_time_check()`.
    573  1.1  christos  *
    574  1.1  christos  *		The fallback implementation is based on code from
    575  1.1  christos  *		<https://www.drdobbs.com/compile-time-assertions/184401873>.
    576  1.1  christos  */
    577  1.1  christos #if MDNS_C_STANDARD_IS_AT_LEAST(C11)
    578  1.1  christos 	#define mdns_compile_time_check_local(EXPRESSION)	_Static_assert(EXPRESSION, "Compile-time assertion failed.")
    579  1.1  christos #elif MDNS_CPP_STANDARD_IS_AT_LEAST(CPP11)
    580  1.1  christos 	#define mdns_compile_time_check_local(EXPRESSION)	static_assert(EXPRESSION, "Compile-time assertion failed.")
    581  1.1  christos #else
    582  1.1  christos 	#define mdns_compile_time_check_local(EXPRESSION)								\
    583  1.1  christos 		do {																		\
    584  1.1  christos 			enum {																	\
    585  1.1  christos 				mdns_compile_time_check_local_failed = 1 / ((EXPRESSION) ? 1 : 0)	\
    586  1.1  christos 			};																		\
    587  1.1  christos 		} while (0)
    588  1.1  christos #endif
    589  1.1  christos 
    590  1.1  christos /*!
    591  1.1  christos  *	@brief
    592  1.1  christos  *		Determines at compile-time if the size of a type exceeds a specified maximum.
    593  1.1  christos  *
    594  1.1  christos  *	@param TYPE
    595  1.1  christos  *		The type.
    596  1.1  christos  *
    597  1.1  christos  *	@param MAX_SIZE
    598  1.1  christos  *		The maximum size in bytes.
    599  1.1  christos  */
    600  1.1  christos #define mdns_compile_time_max_size_check(TYPE, MAX_SIZE) \
    601  1.1  christos 	mdns_compile_time_check(sizeof(TYPE) <= MAX_SIZE, "The size of " # TYPE " exceeds max size of '" # MAX_SIZE "'.")
    602  1.1  christos 
    603  1.1  christos /*!
    604  1.1  christos  *	@brief
    605  1.1  christos  *		Determines the size of an array's element type.
    606  1.1  christos  *
    607  1.1  christos  *	@param ARRAY
    608  1.1  christos  *		The array.
    609  1.1  christos  */
    610  1.1  christos #define mdns_sizeof_element(ARRAY)	sizeof(ARRAY[0])
    611  1.1  christos 
    612  1.1  christos /*!
    613  1.1  christos  *	@brief
    614  1.1  christos  *		Determines the size of a member variable from a struct or union.
    615  1.1  christos  *
    616  1.1  christos  *	@param TYPE
    617  1.1  christos  *		The type name of the struct or union.
    618  1.1  christos  *
    619  1.1  christos  *	@param MEMBER
    620  1.1  christos  *		The name of the member variable.
    621  1.1  christos  */
    622  1.1  christos #define mdns_sizeof_member(TYPE, MEMBER)	sizeof(((TYPE *)0)->MEMBER)
    623  1.1  christos 
    624  1.1  christos /*!
    625  1.1  christos  *	@brief
    626  1.1  christos  *		Determines the number of elements in an array.
    627  1.1  christos  *
    628  1.1  christos  *	@param ARRAY
    629  1.1  christos  *		The array.
    630  1.1  christos  */
    631  1.1  christos #define mdns_countof(ARRAY)	(sizeof(ARRAY) / mdns_sizeof_element(ARRAY))
    632  1.1  christos 
    633  1.1  christos /*!
    634  1.1  christos  *	@brief
    635  1.1  christos  *		If an expression evaluates to false, transfers control to a goto label.
    636  1.1  christos  *
    637  1.1  christos  *	@param EXPRESSION
    638  1.1  christos  *		The expression.
    639  1.1  christos  *
    640  1.1  christos  *	@param LABEL
    641  1.1  christos  *		The location's goto label.
    642  1.1  christos  *
    643  1.1  christos  *	@discussion
    644  1.1  christos  *		No debugging information is logged.
    645  1.1  christos  */
    646  1.1  christos #define mdns_require_quiet(EXPRESSION, LABEL)	\
    647  1.1  christos 	do {										\
    648  1.1  christos 		if (!(EXPRESSION)) {					\
    649  1.1  christos 			goto LABEL;							\
    650  1.1  christos 		}										\
    651  1.1  christos 	} while (0)
    652  1.1  christos 
    653  1.1  christos /*!
    654  1.1  christos  *	@brief
    655  1.1  christos  *		If an expression evaluates to false, executes an action, then transfers control to a goto label.
    656  1.1  christos  *
    657  1.1  christos  *	@param EXPRESSION
    658  1.1  christos  *		The expression.
    659  1.1  christos  *
    660  1.1  christos  *	@param LABEL
    661  1.1  christos  *		The goto label.
    662  1.1  christos  *
    663  1.1  christos  *	@param ACTION
    664  1.1  christos  *		The code to execute.
    665  1.1  christos  *
    666  1.1  christos  *	@discussion
    667  1.1  christos  *		No debugging information is logged.
    668  1.1  christos  */
    669  1.1  christos #define mdns_require_action_quiet(EXPRESSION, LABEL, ACTION)	\
    670  1.1  christos 	do {														\
    671  1.1  christos 		if (!(EXPRESSION)) {									\
    672  1.1  christos 			{													\
    673  1.1  christos 				ACTION;											\
    674  1.1  christos 			}													\
    675  1.1  christos 			goto LABEL;											\
    676  1.1  christos 		}														\
    677  1.1  christos 	} while (0)
    678  1.1  christos 
    679  1.1  christos /*!
    680  1.1  christos  *	@brief
    681  1.1  christos  *		If an error code is non-zero, transfers control to a goto label.
    682  1.1  christos  *
    683  1.1  christos  *	@param ERROR
    684  1.1  christos  *		The error code.
    685  1.1  christos  *
    686  1.1  christos  *	@param LABEL
    687  1.1  christos  *		The location's goto label.
    688  1.1  christos  *
    689  1.1  christos  *	@discussion
    690  1.1  christos  *		No debugging information is logged.
    691  1.1  christos  */
    692  1.1  christos #define mdns_require_noerr_quiet(ERROR, LABEL)	mdns_require_quiet(!(ERROR), LABEL)
    693  1.1  christos 
    694  1.1  christos /*!
    695  1.1  christos  *	@brief
    696  1.1  christos  *		If an error code is non-zero, executes an action, then transfers control to a goto label.
    697  1.1  christos  *
    698  1.1  christos  *	@param ERROR
    699  1.1  christos  *		The error code.
    700  1.1  christos  *
    701  1.1  christos  *	@param LABEL
    702  1.1  christos  *		The location's goto label.
    703  1.1  christos  *
    704  1.1  christos  *	@param ACTION
    705  1.1  christos  *		The code to execute.
    706  1.1  christos  *
    707  1.1  christos  *	@discussion
    708  1.1  christos  *		No debugging information is logged.
    709  1.1  christos  */
    710  1.1  christos #define mdns_require_noerr_action_quiet(ERROR, LABEL, ACTION)	mdns_require_action_quiet(!(ERROR), LABEL, ACTION)
    711  1.1  christos 
    712  1.1  christos /*!
    713  1.1  christos  *	@brief
    714  1.1  christos  *		Returns from the current function if an expression evaluates to false.
    715  1.1  christos  *
    716  1.1  christos  *	@param EXPRESSION
    717  1.1  christos  *		The expression.
    718  1.1  christos  */
    719  1.1  christos #define mdns_require_return(EXPRESSION)	\
    720  1.1  christos 	do {								\
    721  1.1  christos 		if (!(EXPRESSION)) {			\
    722  1.1  christos 			return;						\
    723  1.1  christos 		}								\
    724  1.1  christos 	} while (0)
    725  1.1  christos 
    726  1.1  christos /*!
    727  1.1  christos  *	@brief
    728  1.1  christos  *		If an expression evaluates to false, executes an action, then returns.
    729  1.1  christos  *
    730  1.1  christos  *	@param EXPRESSION
    731  1.1  christos  *		The expression.
    732  1.1  christos  *
    733  1.1  christos  *	@param ACTION
    734  1.1  christos  *		The code to execute.
    735  1.1  christos  *
    736  1.1  christos  *	@discussion
    737  1.1  christos  *		No debugging information is logged.
    738  1.1  christos  */
    739  1.1  christos #define mdns_require_return_action(EXPRESSION, ACTION)	\
    740  1.1  christos 	do {												\
    741  1.1  christos 		if (!(EXPRESSION)) {							\
    742  1.1  christos 			{											\
    743  1.1  christos 				ACTION;									\
    744  1.1  christos 			}											\
    745  1.1  christos 			return;										\
    746  1.1  christos 		}												\
    747  1.1  christos 	} while (0)
    748  1.1  christos 
    749  1.1  christos /*!
    750  1.1  christos  *	@brief
    751  1.1  christos  *		Returns from the current function with a specified value if an expression evaluates to false.
    752  1.1  christos  *
    753  1.1  christos  *	@param EXPRESSION
    754  1.1  christos  *		The expression.
    755  1.1  christos  *
    756  1.1  christos  *	@param VALUE
    757  1.1  christos  *		The return value.
    758  1.1  christos  */
    759  1.1  christos #define mdns_require_return_value(EXPRESSION, VALUE)	\
    760  1.1  christos 	do {												\
    761  1.1  christos 		if (!(EXPRESSION)) {							\
    762  1.1  christos 			return (VALUE);								\
    763  1.1  christos 		}												\
    764  1.1  christos 	} while (0)
    765  1.1  christos 
    766  1.1  christos /*!
    767  1.1  christos  *	@brief
    768  1.1  christos  *		Returns from the current function with a specified return value if an error code is non-zero.
    769  1.1  christos  *
    770  1.1  christos  *	@param ERROR
    771  1.1  christos  *		The error code.
    772  1.1  christos  *
    773  1.1  christos  *	@param VALUE
    774  1.1  christos  *		The return value.
    775  1.1  christos  */
    776  1.1  christos #define mdns_require_noerr_return_value(ERROR, VALUE)	mdns_require_return_value(!(ERROR), VALUE)
    777  1.1  christos 
    778  1.1  christos /*!
    779  1.1  christos  *	@brief
    780  1.1  christos  *		Assigns a value to a variable if the variable's address isn't NULL.
    781  1.1  christos  *
    782  1.1  christos  *	@param VARIABLE_ADDR
    783  1.1  christos  *		The variable's address.
    784  1.1  christos  *
    785  1.1  christos  *	@param VALUE
    786  1.1  christos  *		The value.
    787  1.1  christos  */
    788  1.1  christos #define mdns_assign(VARIABLE_ADDR, VALUE)	\
    789  1.1  christos 	do {									\
    790  1.1  christos 		if (VARIABLE_ADDR) {				\
    791  1.1  christos 			*(VARIABLE_ADDR) = (VALUE);		\
    792  1.1  christos 		}									\
    793  1.1  christos 	} while (0)
    794  1.1  christos 
    795  1.1  christos /*!
    796  1.1  christos  *	@brief
    797  1.1  christos  *		Declares an array of bytes that is meant to be used as explicit padding at the end of a struct.
    798  1.1  christos  *
    799  1.1  christos  *	@param BYTE_COUNT
    800  1.1  christos  *		The size of the array in number of bytes.
    801  1.1  christos  *
    802  1.1  christos  *	@discussion
    803  1.1  christos  *		This explicit padding is meant to be used as the final member variable of a struct to eliminate the
    804  1.1  christos  *		-Wpadded warning about a struct's overall size being implicitly padded up to an alignment boundary.
    805  1.1  christos  *		In other words, in place of such implicit padding, use this explicit padding instead.
    806  1.1  christos  */
    807  1.1  christos #define MDNS_STRUCT_PAD(BYTE_COUNT)							\
    808  1.1  christos 	MDNS_CLANG_IGNORE_WARNING_BEGIN(-Wzero-length-array)	\
    809  1.1  christos 	char _mdns_unused_padding[(BYTE_COUNT)]					\
    810  1.1  christos 	MDNS_CLANG_IGNORE_WARNING_END()
    811  1.1  christos 
    812  1.1  christos /*!
    813  1.1  christos  *	@brief
    814  1.1  christos  *		Like MDNS_STRUCT_PAD(), except that the amount of padding is specified for 64-bit and 32-bit platforms.
    815  1.1  christos  *
    816  1.1  christos  *	@param BYTE_COUNT_64
    817  1.1  christos  *		The amount of padding in number of bytes to use on 64-bit platforms.
    818  1.1  christos  *
    819  1.1  christos  *	@param BYTE_COUNT_32
    820  1.1  christos  *		The amount of padding in number of bytes to use on 32-bit platforms.
    821  1.1  christos  *
    822  1.1  christos  *	@discussion
    823  1.1  christos  *		This macro assumes that pointers on 64-bit platforms are eight bytes in size and that pointers on 32-bit
    824  1.1  christos  *		platforms are four bytes in size.
    825  1.1  christos  *
    826  1.1  christos  *		If the size of a pointer is something other than eight or four bytes, then a compiler error will occur.
    827  1.1  christos  */
    828  1.1  christos #define MDNS_STRUCT_PAD_64_32(BYTE_COUNT_64, BYTE_COUNT_32)	\
    829  1.1  christos 	MDNS_STRUCT_PAD(										\
    830  1.1  christos 		(sizeof(void *) == 8) ? BYTE_COUNT_64 :				\
    831  1.1  christos 		(sizeof(void *) == 4) ? BYTE_COUNT_32 : -1			\
    832  1.1  christos 	)
    833  1.1  christos 
    834  1.1  christos /*!
    835  1.1  christos  *	@brief
    836  1.1  christos  *		Compile-time check to ensure that a struct that uses MDNS_STRUCT_PAD() or MDNS_STRUCT_PAD_64_32() hasn't
    837  1.1  christos  *		specified too much padding.
    838  1.1  christos  *
    839  1.1  christos  *	@param STRUCT_TYPE
    840  1.1  christos  *		The struct type.
    841  1.1  christos  *
    842  1.1  christos  *	@discussion
    843  1.1  christos  *		There's too much padding if the padding's size is greater than or equal to the struct's alignment
    844  1.1  christos  *		requirement. This is because the point of MDNS_STRUCT_PAD() and MDNS_STRUCT_PAD_64_32() is to explicitly
    845  1.1  christos  *		pad a struct up to a multiple of the struct's alignment requirement. Violating this check would
    846  1.1  christos  *		unnecessarily increase the size of the struct.
    847  1.1  christos  */
    848  1.1  christos #define MDNS_GENERAL_STRUCT_PAD_CHECK(STRUCT_TYPE)															\
    849  1.1  christos 	mdns_compile_time_check(mdns_sizeof_member(STRUCT_TYPE, _mdns_unused_padding) < _Alignof(STRUCT_TYPE),	\
    850  1.1  christos 		"Padding exceeds alignment of '" # STRUCT_TYPE "', so the amount of padding is excessive.")
    851  1.1  christos 
    852  1.1  christos /*!
    853  1.1  christos  *	@brief
    854  1.1  christos  *		Retains a Core Foundation object if the specified object reference is non-NULL.
    855  1.1  christos  *
    856  1.1  christos  *	@param OBJ
    857  1.1  christos  *		A reference to the object to retain.
    858  1.1  christos  *
    859  1.1  christos  *	@discussion
    860  1.1  christos  *		The object reference is explicitly compared against NULL to avoid a warning from the Clang analyzer's
    861  1.1  christos  *		osx.NumberObjectConversion checker. See
    862  1.1  christos  *		<https://clang.llvm.org/docs/analyzer/checkers.html#osx-numberobjectconversion-c-c-objc>.
    863  1.1  christos  */
    864  1.1  christos #define mdns_cf_retain_null_safe(OBJ)	\
    865  1.1  christos 	do {								\
    866  1.1  christos 		if ((OBJ) != NULL) {			\
    867  1.1  christos 			CFRetain((OBJ));			\
    868  1.1  christos 		}								\
    869  1.1  christos 	} while (0)
    870  1.1  christos 
    871  1.1  christos /*!
    872  1.1  christos  *	@brief
    873  1.1  christos  *		Releases the Core Foundation object referenced by a pointer.
    874  1.1  christos  *
    875  1.1  christos  *	@param OBJ_PTR
    876  1.1  christos  *		The address of the pointer that either references a Core Foundation object or references NULL.
    877  1.1  christos  *
    878  1.1  christos  *	@discussion
    879  1.1  christos  *		If the pointer contains a non-NULL reference, then the pointer will be set to NULL after releasing the
    880  1.1  christos  *		object.
    881  1.1  christos  *
    882  1.1  christos  *		The object reference is explicitly compared against NULL to avoid a warning from the Clang analyzer's
    883  1.1  christos  *		osx.NumberObjectConversion checker. See
    884  1.1  christos  *		<https://clang.llvm.org/docs/analyzer/checkers.html#osx-numberobjectconversion-c-c-objc>.
    885  1.1  christos  */
    886  1.1  christos #define mdns_cf_forget(OBJ_PTR)		\
    887  1.1  christos 	do {							\
    888  1.1  christos 		if (*(OBJ_PTR) != NULL) {	\
    889  1.1  christos 			CFRelease(*(OBJ_PTR));	\
    890  1.1  christos 			*(OBJ_PTR) = NULL;		\
    891  1.1  christos 		}							\
    892  1.1  christos 	} while (0)
    893  1.1  christos 
    894  1.1  christos /*!
    895  1.1  christos  *	@brief
    896  1.1  christos  *		Alternative to the `default` label in a switch statement that covers all enumeration values.
    897  1.1  christos  *
    898  1.1  christos  *	@discussion
    899  1.1  christos  *		Use `MDNS_COVERED_SWITCH_DEFAULT` instead of `default` to avoid the `-Wcovered-switch-default` warning
    900  1.1  christos  *		in a switch statement that covers all enumeration values. This macro is useful when strict enforcement
    901  1.1  christos  *		of the `-Wswitch-default` warning compels us to include a default label in such switch statements.
    902  1.1  christos  */
    903  1.1  christos #if MDNS_COMPILER_IS_CLANG()
    904  1.1  christos 	#define MDNS_COVERED_SWITCH_DEFAULT								\
    905  1.1  christos 		MDNS_CLANG_IGNORE_WARNING_BEGIN(-Wcovered-switch-default)	\
    906  1.1  christos 		default														\
    907  1.1  christos 		MDNS_CLANG_IGNORE_WARNING_END()
    908  1.1  christos #else
    909  1.1  christos 	#define MDNS_COVERED_SWITCH_DEFAULT	default
    910  1.1  christos #endif
    911  1.1  christos 
    912  1.1  christos /*!
    913  1.1  christos  *	@brief
    914  1.1  christos  *		The static keyword for array parameters for C99 or later.
    915  1.1  christos  *
    916  1.1  christos  *	@discussion
    917  1.1  christos  *		See <https://en.cppreference.com/w/c/language/operator_other#Function_call>.
    918  1.1  christos  */
    919  1.1  christos #if MDNS_C_STANDARD_IS_AT_LEAST(C99)
    920  1.1  christos 	#define MDNS_STATIC_ARRAY_PARAM	static
    921  1.1  christos #else
    922  1.1  christos 	#define MDNS_STATIC_ARRAY_PARAM
    923  1.1  christos #endif
    924  1.1  christos 
    925  1.1  christos /*!
    926  1.1  christos  *	@brief
    927  1.1  christos  *		The size of a Universally Unique Identifier (UUID) in bytes.
    928  1.1  christos  *
    929  1.1  christos  *	@discussion
    930  1.1  christos  *		See <https://datatracker.ietf.org/doc/html/rfc4122#section-4.1>.
    931  1.1  christos  */
    932  1.1  christos #define MDNS_UUID_SIZE	16
    933  1.1  christos 
    934  1.1  christos #endif	// MDNS_GENERAL_H
    935