Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines and implements a number of miscellaneous
22 : * templates for finding object minima and maxima and interface
23 : * macros for assertion checking.
24 : *
25 : */
26 :
27 : #pragma once
28 :
29 : #include <lib/core/CHIPConfig.h>
30 : #include <lib/core/CHIPError.h>
31 : #include <lib/core/ErrorStr.h>
32 : #include <lib/support/Assertions.h>
33 : #include <lib/support/ObjectDump.h>
34 : #include <lib/support/logging/TextOnlyLogging.h>
35 : #include <memory>
36 :
37 : /**
38 : * @def ReturnErrorOnFailure(expr, ...)
39 : *
40 : * @brief
41 : * Returns the error code if the expression returns an error. For a CHIP_ERROR expression, this means any value other
42 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
43 : *
44 : * Example usage:
45 : *
46 : * @code
47 : * ReturnErrorOnFailure(channel->SendMsg(msg), mState = Uninitialized);
48 : * @endcode
49 : *
50 : * @param[in] expr An expression to be tested.
51 : * @param[in] ... Statements to execute before returning. Optional.
52 : */
53 : #define ReturnErrorOnFailure(expr, ...) \
54 : do \
55 : { \
56 : auto __err = (expr); \
57 : if (!::chip::ChipError::IsSuccess(__err)) \
58 : { \
59 : __VA_ARGS__; \
60 : return __err; \
61 : } \
62 : } while (false)
63 :
64 : /**
65 : * @def ReturnErrorVariantOnFailure(expr)
66 : *
67 : * @brief
68 : * This is for use when the calling function returns a Variant type. It returns a CHIP_ERROR variant with the corresponding error
69 : * code if the expression returns an error.
70 : *
71 : * Example usage:
72 : *
73 : * @code
74 : * ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1));
75 : * @endcode
76 : *
77 : * @param[in] variantType The Variant type that the calling function returns.
78 : * @param[in] expr An expression to be tested.
79 : * @param[in] ... Statements to execute before returning. Optional.
80 : */
81 : #define ReturnErrorVariantOnFailure(variantType, expr, ...) \
82 : do \
83 : { \
84 : auto __err = (expr); \
85 : if (!::chip::ChipError::IsSuccess(__err)) \
86 : { \
87 : __VA_ARGS__; \
88 : return variantType::Create<CHIP_ERROR>(__err); \
89 : } \
90 : } while (false)
91 :
92 : /**
93 : * @def ReturnLogErrorOnFailure(expr)
94 : *
95 : * @brief
96 : * Returns the error code if the expression returns something different
97 : * than CHIP_NO_ERROR.
98 : *
99 : * Example usage:
100 : *
101 : * @code
102 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
103 : * @endcode
104 : *
105 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
106 : */
107 : #if CHIP_CONFIG_ERROR_SOURCE
108 : #define ReturnLogErrorOnFailure(expr) \
109 : do \
110 : { \
111 : auto __err = (expr); \
112 : if (!::chip::ChipError::IsSuccess(__err)) \
113 : { \
114 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
115 : return __err; \
116 : } \
117 : } while (false)
118 : #else
119 : #define ReturnLogErrorOnFailure(expr) \
120 : do \
121 : { \
122 : auto __err = (expr); \
123 : if (!::chip::ChipError::IsSuccess(__err)) \
124 : { \
125 : ::chip::Logging::LogFailure(::chip::Logging::kLogModule_NotSpecified, __err); \
126 : return __err; \
127 : } \
128 : } while (false)
129 : #endif
130 :
131 : /**
132 : * @def SuccessOrLog(expr, MOD, MSG, ...)
133 : *
134 : * @brief
135 : * If expr returns something other than CHIP_NO_ERROR, log a message for the specified module
136 : * in the 'Error' category.
137 : *
138 : * Example usage:
139 : *
140 : * @code
141 : * SuccessOrLog(channel->SendMsg(msg), Module, "Failure message: %s", param);
142 : * @endcode
143 : *
144 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
145 : * @param[in] MOD The log module to use.
146 : * @param[in] MSG The log message format string.
147 : * @param[in] ... Optional arguments for the log message.
148 : */
149 : #define SuccessOrLog(expr, MOD, MSG, ...) \
150 : do \
151 : { \
152 : CHIP_ERROR __lerr = (expr); \
153 : if (!::chip::ChipError::IsSuccess(__lerr)) \
154 : { \
155 : ChipLogFailure(__lerr, MOD, MSG, ##__VA_ARGS__); \
156 : } \
157 : } while (false)
158 :
159 : /**
160 : * @def ReturnAndLogOnFailure(expr, MOD, MSG, ...)
161 : *
162 : * @brief
163 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
164 : * in the 'Error' category and return.
165 : *
166 : * Example usage:
167 : *
168 : * @code
169 : * ReturnAndLogOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
170 : * @endcode
171 : *
172 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
173 : * @param[in] MOD The log module to use.
174 : * @param[in] MSG The log message format string.
175 : * @param[in] ... Optional arguments for the log message.
176 : */
177 : #define ReturnAndLogOnFailure(expr, MOD, MSG, ...) \
178 : do \
179 : { \
180 : CHIP_ERROR __err = (expr); \
181 : if (!::chip::ChipError::IsSuccess(__err)) \
182 : { \
183 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
184 : return; \
185 : } \
186 : } while (false)
187 :
188 : /**
189 : * @def ReturnErrorAndLogOnFailure(expr, MOD, MSG, ...)
190 : *
191 : * @brief
192 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
193 : * in the 'Error' category and return the error.
194 : *
195 : * Example usage:
196 : *
197 : * @code
198 : * ReturnErrorAndLogOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
199 : * @endcode
200 : *
201 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
202 : * @param[in] MOD The log module to use.
203 : * @param[in] MSG The log message format string.
204 : * @param[in] ... Optional arguments for the log message.
205 : */
206 : #define ReturnErrorAndLogOnFailure(expr, MOD, MSG, ...) \
207 : do \
208 : { \
209 : CHIP_ERROR __err = (expr); \
210 : if (!::chip::ChipError::IsSuccess(__err)) \
211 : { \
212 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
213 : return __err; \
214 : } \
215 : } while (false)
216 :
217 : /**
218 : * @def ReturnValueAndLogOnFailure(expr, value, MOD, MSG, ...)
219 : *
220 : * @brief
221 : * If expr returns something other than CHIP_NO_ERROR, log a message for the specified module
222 : * in the 'Error' category and return the error.
223 : *
224 : * Example usage:
225 : *
226 : * @code
227 : * ReturnValueAndLogOnFailure(channel->SendMsg(msg), false, Module, "Failure message: %s", param);
228 : * @endcode
229 : *
230 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
231 : * @param[in] value A value to return if @a expr is an error.
232 : * @param[in] MOD The log module to use.
233 : * @param[in] MSG The log message format string.
234 : * @param[in] ... Optional arguments for the log message.
235 : */
236 : #define ReturnValueAndLogOnFailure(expr, value, MOD, MSG, ...) \
237 : do \
238 : { \
239 : CHIP_ERROR __err = (expr); \
240 : if (!::chip::ChipError::IsSuccess(__err)) \
241 : { \
242 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
243 : return value; \
244 : } \
245 : } while (false)
246 :
247 : /**
248 : * @def ReturnOnFailure(expr, ...)
249 : *
250 : * @brief
251 : * Returns if the expression returns an error. For a CHIP_ERROR expression, this means any value other
252 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
253 : *
254 : * Example usage:
255 : *
256 : * @code
257 : * ReturnOnFailure(channel->SendMsg(msg), mState = Uninitialized);
258 : * @endcode
259 : *
260 : * @param[in] expr An expression to be tested.
261 : * @param[in] ... Statements to execute before returning. Optional.
262 : */
263 : #define ReturnOnFailure(expr, ...) \
264 : do \
265 : { \
266 : auto __err = (expr); \
267 : if (!::chip::ChipError::IsSuccess(__err)) \
268 : { \
269 : __VA_ARGS__; \
270 : return; \
271 : } \
272 : } while (false)
273 :
274 : /**
275 : * @def ReturnValueOnFailure(expr, value, ...)
276 : *
277 : * @brief
278 : * Returns value if the expression returns an error. For a CHIP_ERROR expression, this means any value other
279 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
280 : *
281 : * Example usage:
282 : *
283 : * @code
284 : * ReturnValueOnFailure(channel->SendMsg(msg), Status::Failure, mState = Uninitialized);
285 : * @endcode
286 : *
287 : * @param[in] expr An expression to be tested.
288 : * @param[in] value A value to return if @a expr is an error.
289 : * @param[in] ... Statements to execute before returning. Optional.
290 : */
291 : #define ReturnValueOnFailure(expr, value, ...) \
292 : do \
293 : { \
294 : auto __err = (expr); \
295 : if (!::chip::ChipError::IsSuccess(__err)) \
296 : { \
297 : __VA_ARGS__; \
298 : return value; \
299 : } \
300 : } while (false)
301 :
302 : /**
303 : * @def VerifyOrReturnLogError(expr, code)
304 : *
305 : * @brief
306 : * Returns and print a specified error code if expression evaluates to false
307 : *
308 : * Example usage:
309 : *
310 : * @code
311 : * VerifyOrReturnLogError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
312 : * @endcode
313 : *
314 : * @param[in] expr A Boolean expression to be evaluated.
315 : * @param[in] code A value to return if @a expr is false.
316 : */
317 : #if CHIP_CONFIG_ERROR_SOURCE
318 : #define VerifyOrReturnLogError(expr, code) \
319 : do \
320 : { \
321 : if (!(expr)) \
322 : { \
323 : auto __code = (code); \
324 : ::chip::Logging::LogVerifyOrReturnErrorWithSource(__code, __FILE__, __LINE__); \
325 : return __code; \
326 : } \
327 : } while (false)
328 : #else // CHIP_CONFIG_ERROR_SOURCE
329 : #define VerifyOrReturnLogError(expr, code) \
330 : do \
331 : { \
332 : if (!(expr)) \
333 : { \
334 : auto __code = (code); \
335 : ::chip::Logging::LogVerifyOrReturnError(#expr, __LINE__, __code); \
336 : return __code; \
337 : } \
338 : } while (false)
339 : #endif // CHIP_CONFIG_ERROR_SOURCE
340 :
341 : /**
342 : * @def SuccessOrShutdown(expr, ...)
343 : *
344 : * @brief
345 : * This is expected to be called from within a class that implements a Shutdown method.
346 : * It checks for the specified error, which is expected to commonly be successful (CHIP_NO_ERROR),
347 : * on failure, it calls the statements to be executed before shutdown if provided,
348 : * then calls the Shutdown method of the class and returns the error.
349 : *
350 : * @param[in] expr A ChipError object to be evaluated against success (CHIP_NO_ERROR).
351 : * @param[in] ... Statements to execute before shutdown. Optional.
352 : *
353 : */
354 : #define SuccessOrShutdown(expr, ...) \
355 : do \
356 : { \
357 : auto __err = (expr); \
358 : if (!::chip::ChipError::IsSuccess(__err)) \
359 : { \
360 : __VA_ARGS__; \
361 : this->Shutdown(); \
362 : return __err; \
363 : } \
364 : } while (false)
365 :
366 : /**
367 : * @def SuccessOrExit(error)
368 : *
369 : * @brief
370 : * This checks for the specified error, which is expected to
371 : * commonly be successful (CHIP_NO_ERROR), and branches to
372 : * the local label 'exit' if the status is unsuccessful.
373 : *
374 : * Example Usage:
375 : *
376 : * @code
377 : * CHIP_ERROR TryHard()
378 : * {
379 : * CHIP_ERROR err;
380 : *
381 : * err = TrySomething();
382 : * SuccessOrExit(err);
383 : *
384 : * err = TrySomethingElse();
385 : * SuccessOrExit(err);
386 : *
387 : * exit:
388 : * return err;
389 : * }
390 : * @endcode
391 : *
392 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
393 : *
394 : */
395 : #define SuccessOrExit(error) VerifyOrExit(::chip::ChipError::IsSuccess((error)), {})
396 :
397 : /**
398 : * @def SuccessOrExitAction(error, anAction)
399 : *
400 : * @brief
401 : * This checks for the specified error, which is expected to
402 : * commonly be successful (CHIP_NO_ERROR), and both executes
403 : * @a anAction and branches to the local label 'exit' if the
404 : * status is unsuccessful.
405 : *
406 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
407 : */
408 : #define SuccessOrExitAction(error, action) VerifyOrExit(::chip::ChipError::IsSuccess((error)), action)
409 :
410 : #ifndef chipDie
411 : extern "C" void chipDie(void) __attribute((noreturn));
412 :
413 0 : inline void chipDie(void)
414 : {
415 0 : ChipLogError(NotSpecified, "chipDie chipDie chipDie");
416 0 : chipAbort();
417 : }
418 : #endif // chipDie
419 :
420 : /**
421 : * @def VerifyOrDie(aCondition)
422 : *
423 : * @brief
424 : * This checks for the specified condition, which is expected to
425 : * commonly be true and forces an immediate abort if the condition
426 : * is false.
427 : *
428 : * Example Usage:
429 : *
430 : * @code
431 : * void FreeBuffer(const uint8_t *buf)
432 : * {
433 : * VerifyOrDie(buf != NULL);
434 : * free(buf);
435 : * }
436 : * @endcode
437 : *
438 : * @param[in] aCondition A Boolean expression to be evaluated.
439 : *
440 : * @sa #VerifyOrDieWithMsg
441 : * @sa #chipDie
442 : *
443 : */
444 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
445 : #define VerifyOrDie(aCondition) VerifyOrDo(aCondition, ::chip::Logging::LogVerifyOrDie(__FILE__, __LINE__))
446 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
447 : #define VerifyOrDie(aCondition) VerifyOrDo(aCondition, ::chip::Logging::LogVerifyOrDie(__FILE__, __LINE__, #aCondition))
448 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
449 : #define VerifyOrDie(aCondition) VerifyOrDieWithoutLogging(aCondition)
450 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
451 :
452 : /**
453 : * @def SuccessOrDie(error)
454 : *
455 : * @brief
456 : * This checks for the specified error, which is expected to
457 : * commonly be successful (CHIP_NO_ERROR), forces an immediate abort if the status
458 : * is unsuccessful.
459 : *
460 : *
461 : * Example Usage:
462 : *
463 : * @code
464 : * uint8_t* AllocateBuffer()
465 : * {
466 : * uint8_t* buffer;
467 : * SuccessOrDie(ChipAllocateBuffer(buffer));
468 : * return buffer;
469 : * }
470 : * @endcode
471 : *
472 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
473 : *
474 : */
475 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
476 : #define SuccessOrDie(error) \
477 : do \
478 : { \
479 : auto __err = (error); \
480 : VerifyOrDo(::chip::ChipError::IsSuccess(__err), ::chip::Logging::LogSuccessOrDie(__FILE__, __LINE__, __err)); \
481 : } while (false)
482 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
483 : #define SuccessOrDie(error) \
484 : do \
485 : { \
486 : auto __err = (error); \
487 : VerifyOrDo(::chip::ChipError::IsSuccess(__err), ::chip::Logging::LogSuccessOrDie(__FILE__, __LINE__, __err, #error)); \
488 : } while (false)
489 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
490 : #define SuccessOrDie(error) VerifyOrDieWithoutLogging(::chip::ChipError::IsSuccess((error)))
491 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
492 :
493 : /**
494 : * @def VerifyOrDieWithObject(aCondition, aObject)
495 : *
496 : * Like VerifyOrDie(), but calls DumpObjectToLog()
497 : * on the provided object on failure before aborting
498 : * if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE is enabled.
499 : */
500 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
501 : #define VerifyOrDieWithObject(aCondition, aObject) \
502 : VerifyOrDo(aCondition, ::chip::DumpObjectToLog(aObject); ::chip::Logging::LogVerifyOrDie(__FILE__, __LINE__, #aCondition))
503 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
504 : #define VerifyOrDieWithObject(aCondition, aObject) VerifyOrDieWithoutLogging(aCondition)
505 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
506 :
507 : /**
508 : * @def VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...)
509 : *
510 : * @brief
511 : * This checks for the specified condition, which is expected to
512 : * commonly be true and both prints @a aMessage and forces an
513 : * immediate abort if the condition is false.
514 : *
515 : * Example Usage:
516 : *
517 : * @code
518 : * void FreeBuffer(const uint8_t *buf)
519 : * {
520 : * VerifyOrDieWithMsg(buf != NULL, MemoryManagement, "Invalid pointer passed to FreeBuffer");
521 : * free(buf);
522 : * }
523 : * @endcode
524 : *
525 : * @param[in] aCondition A Boolean expression to be evaluated.
526 : * @param[in] aModule A chip LogModule short-hand mnemonic identifing
527 : * the logical section of code that is a
528 : * source the logged message.
529 : * @param[in] aMessage A pointer to a NULL-terminated C string with
530 : * C Standard Library-style format specifiers
531 : * containing the log message to be formatted
532 : * and logged.
533 : * @param[in] ... A variadic argument list whose elements should
534 : * correspond to the format specifiers in @a
535 : * aMessage.
536 : *
537 : * @sa #VerifyOrDie
538 : * @sa #chipDie
539 : *
540 : */
541 : #define CHIP_VERIFY_OR_DIE_WITH_MSG_SELECT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, NAME, ...) NAME
542 :
543 : #define VerifyOrDieWithMsg_NO_VA_ARGS(aCondition, aModule, aMessage) \
544 : VerifyOrDo(aCondition, ::chip::Logging::LogVerifyOrDieWithMsg(::chip::Logging::kLogModule_##aModule, aMessage))
545 :
546 : #define VerifyOrDieWithMsg_VA_ARGS(aCondition, aModule, aMessage, ...) \
547 : VerifyOrDo(aCondition, ChipLogError(aModule, aMessage, ##__VA_ARGS__); chipAbort())
548 :
549 : #define VerifyOrDieWithMsg(...) \
550 : CHIP_VERIFY_OR_DIE_WITH_MSG_SELECT(__VA_ARGS__, VerifyOrDieWithMsg_VA_ARGS, VerifyOrDieWithMsg_VA_ARGS, \
551 : VerifyOrDieWithMsg_VA_ARGS, VerifyOrDieWithMsg_VA_ARGS, VerifyOrDieWithMsg_VA_ARGS, \
552 : VerifyOrDieWithMsg_VA_ARGS, VerifyOrDieWithMsg_VA_ARGS, VerifyOrDieWithMsg_NO_VA_ARGS) \
553 : (__VA_ARGS__)
554 :
555 : /**
556 : * @def LogErrorOnFailure(expr)
557 : *
558 : * @brief
559 : * Logs a message if the expression returns something different than CHIP_NO_ERROR.
560 : *
561 : * Example usage:
562 : *
563 : * @code
564 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
565 : * @endcode
566 : *
567 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
568 : */
569 : #if CHIP_CONFIG_ERROR_SOURCE
570 : #define LogErrorOnFailure(expr) \
571 : do \
572 : { \
573 : auto __err = (expr); \
574 : if (!::chip::ChipError::IsSuccess(__err)) \
575 : { \
576 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
577 : } \
578 : } while (false)
579 : #else
580 : #define LogErrorOnFailure(expr) \
581 : do \
582 : { \
583 : auto __err = (expr); \
584 : if (!::chip::ChipError::IsSuccess(__err)) \
585 : { \
586 : ::chip::Logging::LogFailure(::chip::Logging::kLogModule_NotSpecified, __err); \
587 : } \
588 : } while (false)
589 : #endif
590 :
591 : #if (__cplusplus >= 201103L)
592 :
593 : #ifndef __FINAL
594 : #define __FINAL final
595 : #endif
596 :
597 : #ifndef __OVERRIDE
598 : #define __OVERRIDE override
599 : #endif
600 :
601 : #ifndef __CONSTEXPR
602 : #define __CONSTEXPR constexpr
603 : #endif
604 :
605 : #else
606 :
607 : #ifndef __FINAL
608 : #define __FINAL
609 : #endif
610 :
611 : #ifndef __OVERRIDE
612 : #define __OVERRIDE
613 : #endif
614 :
615 : #ifndef __CONSTEXPR
616 : #define __CONSTEXPR constexpr
617 : #endif
618 :
619 : #endif // (__cplusplus >= 201103L)
620 :
621 : #if ((__cplusplus >= 201703L) || (defined(__GNUC__) && (__GNUC__ >= 7)) || (defined(__clang__)) && (__clang_major__ >= 4))
622 : #define CHECK_RETURN_VALUE [[nodiscard]]
623 : #elif defined(__GNUC__) && (__GNUC__ >= 4)
624 : #define CHECK_RETURN_VALUE __attribute__((warn_unused_result))
625 : #elif defined(_MSC_VER) && (_MSC_VER >= 1700)
626 : #define CHECK_RETURN_VALUE _Check_return_
627 : #else
628 : #define CHECK_RETURN_VALUE
629 : #endif
630 :
631 : #if defined(__clang__)
632 : #define FALLTHROUGH [[clang::fallthrough]]
633 : #elif defined(__GNUC__)
634 : #define FALLTHROUGH __attribute__((fallthrough))
635 : #else
636 : #define FALLTHROUGH (void) 0
637 : #endif
638 :
639 : /**
640 : * @def MATTER_ARRAY_SIZE(aArray)
641 : *
642 : * @brief
643 : * Returns the size of an array in number of elements.
644 : *
645 : * Example Usage:
646 : *
647 : * @code
648 : * int numbers[10];
649 : * SortNumbers(numbers, MATTER_ARRAY_SIZE(numbers));
650 : * @endcode
651 : *
652 : * @return The size of an array in number of elements.
653 : *
654 : * @note Clever template-based solutions seem to fail when MATTER_ARRAY_SIZE is used
655 : * with a variable-length array argument, so we just do the C-compatible
656 : * thing in C++ as well.
657 : */
658 : #ifndef MATTER_ARRAY_SIZE
659 : #define MATTER_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
660 : #endif
661 :
662 : /**
663 : * @brief Ensures that if `str` is NULL, a non-null `default_str_value` is provided
664 : *
665 : * @param str - null-terminated string pointer or nullptr
666 : * @param default_str_value - replacement value if `str` is nullptr
667 : * @return `str` if not null, otherwise `default_str_value`
668 : */
669 40 : inline const char * DefaultStringWhenNull(const char * str, const char * default_str_value)
670 : {
671 40 : return (str != nullptr) ? str : default_str_value;
672 : }
673 :
674 : /**
675 : * @brief Ensure that a string for a %s specifier is shown as "(null)" if null
676 : *
677 : * @param str - null-terminated string pointer or nullptr
678 : * @return `str` if not null, otherwise literal "(null)"
679 : */
680 40 : inline const char * StringOrNullMarker(const char * str)
681 : {
682 40 : return DefaultStringWhenNull(str, "(null)");
683 : }
684 :
685 : namespace chip {
686 :
687 : /**
688 : * Utility for checking, at compile time if the array is constexpr, whether an
689 : * array is sorted. Can be used for static_asserts.
690 : */
691 : template <typename T>
692 : constexpr bool ArrayIsSorted(const T * aArray, size_t aLength)
693 : {
694 : if (aLength == 0 || aLength == 1)
695 : {
696 : return true;
697 : }
698 :
699 : if (aArray[0] > aArray[1])
700 : {
701 : return false;
702 : }
703 :
704 : return ArrayIsSorted(aArray + 1, aLength - 1);
705 : }
706 :
707 : template <typename T, size_t N>
708 : constexpr bool ArrayIsSorted(const T (&aArray)[N])
709 : {
710 : return ArrayIsSorted(aArray, N);
711 : }
712 :
713 : /**
714 : * @def ScopeExit(fn)
715 : *
716 : * @brief
717 : * RAII to automatically release resources on scope exit (instead of depending on goto exit)
718 : * See https://en.cppreference.com/w/cpp/experimental/scope_exit.html
719 : * Use with ReturnOnFailure, ReturnLogErrorOnFailure, ReturnAndLogOnFailure and other such methods
720 : * to return an error code result from a method call without needing to store in a local var
721 : *
722 : * Example usage:
723 : *
724 : * @code
725 : * Resource * resource = GetResource();
726 : * auto resourceHolder = ScopeExit([&] { resource->Release() });
727 : * // If the call below fails, logs, returns the error code, and calls resourceHolder
728 : * ReturnAndLogOnFailure(ProcessAndSaveResource(resource), Module, "Failure message: %s", param);
729 : * resourceHolder->release(); // Cancel clean-up at end of successful method
730 : * @endcode
731 : */
732 : template <class F>
733 : __attribute__((always_inline)) inline auto ScopeExit(F && fn)
734 : {
735 30360 : auto deleter = [f = std::forward<F>(fn)](void *) mutable { f(); };
736 15283 : return std::unique_ptr<void, decltype(deleter)>(reinterpret_cast<void *>(1), std::move(deleter));
737 : }
738 :
739 : } // namespace chip
|