Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkAssert.h
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkAssert_DEFINED
9#define SkAssert_DEFINED
10
13#include "include/private/base/SkDebug.h" // IWYU pragma: keep
14
15#include <cstddef>
16#include <limits>
17
18#if defined(__clang__) && defined(__has_attribute)
19 #if __has_attribute(likely)
20 #define SK_LIKELY [[likely]]
21 #define SK_UNLIKELY [[unlikely]]
22 #else
23 #define SK_LIKELY
24 #define SK_UNLIKELY
25 #endif
26#else
27 #define SK_LIKELY
28 #define SK_UNLIKELY
29#endif
30
31// c++23 will give us [[assume]] -- until then we're stuck with various other options:
32#if defined(__clang__)
33 #define SK_ASSUME(cond) __builtin_assume(cond)
34#elif defined(__GNUC__)
35 #if __GNUC__ >= 13
36 #define SK_ASSUME(cond) __attribute__((assume(cond)))
37 #else
38 // NOTE: This implementation could actually evaluate `cond`, which is not desirable.
39 #define SK_ASSUME(cond) ((cond) ? (void)0 : __builtin_unreachable())
40 #endif
41#elif defined(_MSC_VER)
42 #define SK_ASSUME(cond) __assume(cond)
43#else
44 #define SK_ASSUME(cond) ((void)0)
45#endif
46
47/** Called internally if we hit an unrecoverable error.
48 The platform implementation must not return, but should either throw
49 an exception or otherwise exit.
50*/
51[[noreturn]] SK_API extern void sk_abort_no_print(void);
52
53#if defined(SK_BUILD_FOR_GOOGLE3)
54 void SkDebugfForDumpStackTrace(const char* data, void* unused);
55 namespace base {
56 void DumpStackTrace(int skip_count, void w(const char*, void*), void* arg);
57 }
58# define SK_DUMP_GOOGLE3_STACK() ::base::DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)
59#else
60# define SK_DUMP_GOOGLE3_STACK()
61#endif
62
63#if !defined(SK_ABORT)
64# if defined(SK_BUILD_FOR_WIN)
65 // This style lets Visual Studio follow errors back to the source file.
66# define SK_DUMP_LINE_FORMAT "%s(%d)"
67# else
68# define SK_DUMP_LINE_FORMAT "%s:%d"
69# endif
70# define SK_ABORT(message, ...) \
71 do { \
72 SkDebugf(SK_DUMP_LINE_FORMAT ": fatal error: \"" message "\"\n", \
73 __FILE__, __LINE__, ##__VA_ARGS__); \
74 SK_DUMP_GOOGLE3_STACK(); \
75 sk_abort_no_print(); \
76 } while (false)
77#endif
78
79// SkASSERT, SkASSERTF and SkASSERT_RELEASE can be used as standalone assertion expressions, e.g.
80// uint32_t foo(int x) {
81// SkASSERT(x > 4);
82// return x - 4;
83// }
84// and are also written to be compatible with constexpr functions:
85// constexpr uint32_t foo(int x) {
86// return SkASSERT(x > 4),
87// x - 4;
88// }
89#if defined(__clang__)
90#define SkASSERT_RELEASE(cond) \
91 static_cast<void>( __builtin_expect(static_cast<bool>(cond), 1) \
92 ? static_cast<void>(0) \
93 : []{ SK_ABORT("check(%s)", #cond); }() )
94
95#define SkASSERTF_RELEASE(cond, fmt, ...) \
96 static_cast<void>( __builtin_expect(static_cast<bool>(cond), 1) \
97 ? static_cast<void>(0) \
98 : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() )
99#else
100#define SkASSERT_RELEASE(cond) \
101 static_cast<void>( (cond) ? static_cast<void>(0) : []{ SK_ABORT("check(%s)", #cond); }() )
102
103#define SkASSERTF_RELEASE(cond, fmt, ...) \
104 static_cast<void>( (cond) \
105 ? static_cast<void>(0) \
106 : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() )
107#endif
108
109#if defined(SK_DEBUG)
110 #define SkASSERT(cond) SkASSERT_RELEASE(cond)
111 #define SkASSERTF(cond, fmt, ...) SkASSERTF_RELEASE(cond, fmt, ##__VA_ARGS__)
112 #define SkDEBUGFAIL(message) SK_ABORT("%s", message)
113 #define SkDEBUGFAILF(fmt, ...) SK_ABORT(fmt, ##__VA_ARGS__)
114 #define SkAssertResult(cond) SkASSERT(cond)
115#else
116 #define SkASSERT(cond) static_cast<void>(0)
117 #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)
118 #define SkDEBUGFAIL(message)
119 #define SkDEBUGFAILF(fmt, ...)
120
121 // unlike SkASSERT, this macro executes its condition in the non-debug build.
122 // The if is present so that this can be used with functions marked [[nodiscard]].
123 #define SkAssertResult(cond) if (cond) {} do {} while(false)
124#endif
125
126#if !defined(SkUNREACHABLE)
127# if defined(_MSC_VER) && !defined(__clang__)
128# include <intrin.h>
129# define FAST_FAIL_INVALID_ARG 5
130// See https://developercommunity.visualstudio.com/content/problem/1128631/code-flow-doesnt-see-noreturn-with-extern-c.html
131// for why this is wrapped. Hopefully removable after msvc++ 19.27 is no longer supported.
132[[noreturn]] static inline void sk_fast_fail() { __fastfail(FAST_FAIL_INVALID_ARG); }
133# define SkUNREACHABLE sk_fast_fail()
134# else
135# define SkUNREACHABLE __builtin_trap()
136# endif
137#endif
138
139[[noreturn]] SK_API inline void sk_print_index_out_of_bounds(size_t i, size_t size) {
140 SK_ABORT("Index (%zu) out of bounds for size %zu.\n", i, size);
141}
142
143template <typename T> SK_API inline T sk_collection_check_bounds(T i, T size) {
144 if (0 <= i && i < size) SK_LIKELY {
145 return i;
146 }
147
149 #if defined(SK_DEBUG)
150 sk_print_index_out_of_bounds(static_cast<size_t>(i), static_cast<size_t>(size));
151 #else
153 #endif
154 }
155}
156
157[[noreturn]] SK_API inline void sk_print_length_too_big(size_t i, size_t size) {
158 SK_ABORT("Length (%zu) is too big for size %zu.\n", i, size);
159}
160
161template <typename T> SK_API inline T sk_collection_check_length(T i, T size) {
162 if (0 <= i && i <= size) SK_LIKELY {
163 return i;
164 }
165
167 #if defined(SK_DEBUG)
168 sk_print_length_too_big(static_cast<size_t>(i), static_cast<size_t>(size));
169 #else
171 #endif
172 }
173}
174
176 if (empty) SK_UNLIKELY {
177 #if defined(SK_DEBUG)
178 SK_ABORT("Collection is empty.\n");
179 #else
181 #endif
182 }
183}
184
185[[noreturn]] SK_API inline void sk_print_size_too_big(size_t size, size_t maxSize) {
186 SK_ABORT("Size (%zu) can't be represented in bytes. Max size is %zu.\n", size, maxSize);
187}
188
189template <typename T>
191 const size_t kMaxSize = std::numeric_limits<size_t>::max() / sizeof(T);
192 if (size > kMaxSize) {
193 #if defined(SK_DEBUG)
194 sk_print_size_too_big(size, kMaxSize);
195 #else
197 #endif
198 }
199 return size;
200}
201
202#endif // SkAssert_DEFINED
static bool unused
#define SK_API
Definition SkAPI.h:35
#define SkUNREACHABLE
Definition SkAssert.h:135
SK_ALWAYS_INLINE size_t check_size_bytes_too_big(size_t size)
Definition SkAssert.h:190
#define SK_ABORT(message,...)
Definition SkAssert.h:70
SK_API void sk_collection_not_empty(bool empty)
Definition SkAssert.h:175
SK_API void sk_print_size_too_big(size_t size, size_t maxSize)
Definition SkAssert.h:185
SK_API void sk_abort_no_print(void)
SK_API T sk_collection_check_bounds(T i, T size)
Definition SkAssert.h:143
SK_API void sk_print_length_too_big(size_t i, size_t size)
Definition SkAssert.h:157
#define SK_LIKELY
Definition SkAssert.h:27
SK_API void sk_print_index_out_of_bounds(size_t i, size_t size)
Definition SkAssert.h:139
#define SK_UNLIKELY
Definition SkAssert.h:28
SK_API T sk_collection_check_length(T i, T size)
Definition SkAssert.h:161
#define SK_ALWAYS_INLINE
EMSCRIPTEN_KEEPALIVE void empty()
SkScalar w
#define T