File: SkAssert.h

package info (click to toggle)
webkit2gtk 2.51.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 455,340 kB
  • sloc: cpp: 3,865,253; javascript: 197,710; ansic: 165,177; python: 49,241; asm: 21,868; ruby: 18,095; perl: 16,926; xml: 4,623; sh: 2,409; yacc: 2,356; java: 2,019; lex: 1,330; pascal: 372; makefile: 210
file content (202 lines) | stat: -rw-r--r-- 6,811 bytes parent folder | download | duplicates (17)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
 * Copyright 2022 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkAssert_DEFINED
#define SkAssert_DEFINED

#include "include/private/base/SkAPI.h"
#include "include/private/base/SkAttributes.h"
#include "include/private/base/SkDebug.h" // IWYU pragma: keep

#include <cstddef>
#include <limits>

#if defined(__clang__) && defined(__has_attribute)
    #if __has_attribute(likely)
        #define SK_LIKELY [[likely]]
        #define SK_UNLIKELY [[unlikely]]
    #else
        #define SK_LIKELY
        #define SK_UNLIKELY
    #endif
#else
    #define SK_LIKELY
    #define SK_UNLIKELY
#endif

// c++23 will give us [[assume]] -- until then we're stuck with various other options:
#if defined(__clang__)
    #define SK_ASSUME(cond) __builtin_assume(cond)
#elif defined(__GNUC__)
    #if __GNUC__ >= 13
        #define SK_ASSUME(cond) __attribute__((assume(cond)))
    #else
        // NOTE: This implementation could actually evaluate `cond`, which is not desirable.
        #define SK_ASSUME(cond) ((cond) ? (void)0 : __builtin_unreachable())
    #endif
#elif defined(_MSC_VER)
    #define SK_ASSUME(cond) __assume(cond)
#else
    #define SK_ASSUME(cond) ((void)0)
#endif

/** Called internally if we hit an unrecoverable error.
    The platform implementation must not return, but should either throw
    an exception or otherwise exit.
*/
[[noreturn]] SK_API extern void sk_abort_no_print(void);

#if defined(SK_BUILD_FOR_GOOGLE3)
    void SkDebugfForDumpStackTrace(const char* data, void* unused);
    namespace base {
        void DumpStackTrace(int skip_count, void w(const char*, void*), void* arg);
    }
#  define SK_DUMP_GOOGLE3_STACK() ::base::DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)
#else
#  define SK_DUMP_GOOGLE3_STACK()
#endif

#if !defined(SK_ABORT)
#  if defined(SK_BUILD_FOR_WIN)
     // This style lets Visual Studio follow errors back to the source file.
#    define SK_DUMP_LINE_FORMAT "%s(%d)"
#  else
#    define SK_DUMP_LINE_FORMAT "%s:%d"
#  endif
#  define SK_ABORT(message, ...) \
    do { \
        SkDebugf(SK_DUMP_LINE_FORMAT ": fatal error: \"" message "\"\n", \
                 __FILE__, __LINE__, ##__VA_ARGS__); \
        SK_DUMP_GOOGLE3_STACK(); \
        sk_abort_no_print(); \
    } while (false)
#endif

// SkASSERT, SkASSERTF and SkASSERT_RELEASE can be used as standalone assertion expressions, e.g.
//    uint32_t foo(int x) {
//        SkASSERT(x > 4);
//        return x - 4;
//    }
// and are also written to be compatible with constexpr functions:
//    constexpr uint32_t foo(int x) {
//        return SkASSERT(x > 4),
//               x - 4;
//    }
#if defined(__clang__)
#define SkASSERT_RELEASE(cond) \
    static_cast<void>( __builtin_expect(static_cast<bool>(cond), 1) \
        ? static_cast<void>(0) \
        : []{ SK_ABORT("check(%s)", #cond); }() )

#define SkASSERTF_RELEASE(cond, fmt, ...)                                  \
    static_cast<void>( __builtin_expect(static_cast<bool>(cond), 1)        \
        ? static_cast<void>(0)                                             \
        : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() )
#else
#define SkASSERT_RELEASE(cond) \
    static_cast<void>( (cond) ? static_cast<void>(0) : []{ SK_ABORT("check(%s)", #cond); }() )

#define SkASSERTF_RELEASE(cond, fmt, ...)                                   \
    static_cast<void>( (cond)                                               \
        ? static_cast<void>(0)                                              \
        : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() )
#endif

#if defined(SK_DEBUG)
    #define SkASSERT(cond)            SkASSERT_RELEASE(cond)
    #define SkASSERTF(cond, fmt, ...) SkASSERTF_RELEASE(cond, fmt, ##__VA_ARGS__)
    #define SkDEBUGFAIL(message)      SK_ABORT("%s", message)
    #define SkDEBUGFAILF(fmt, ...)    SK_ABORT(fmt, ##__VA_ARGS__)
    #define SkAssertResult(cond)      SkASSERT(cond)
#else
    #define SkASSERT(cond)            static_cast<void>(0)
    #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)
    #define SkDEBUGFAIL(message)
    #define SkDEBUGFAILF(fmt, ...)

    // unlike SkASSERT, this macro executes its condition in the non-debug build.
    // The if is present so that this can be used with functions marked [[nodiscard]].
    #define SkAssertResult(cond)         if (cond) {} do {} while(false)
#endif

#if !defined(SkUNREACHABLE)
#  if defined(_MSC_VER) && !defined(__clang__)
#    include <intrin.h>
#    define FAST_FAIL_INVALID_ARG                 5
// See https://developercommunity.visualstudio.com/content/problem/1128631/code-flow-doesnt-see-noreturn-with-extern-c.html
// for why this is wrapped. Hopefully removable after msvc++ 19.27 is no longer supported.
[[noreturn]] static inline void sk_fast_fail() { __fastfail(FAST_FAIL_INVALID_ARG); }
#    define SkUNREACHABLE sk_fast_fail()
#  else
#    define SkUNREACHABLE __builtin_trap()
#  endif
#endif

[[noreturn]] SK_API inline void sk_print_index_out_of_bounds(size_t i, size_t size) {
    SK_ABORT("Index (%zu) out of bounds for size %zu.\n", i, size);
}

template <typename T> SK_API inline T sk_collection_check_bounds(T i, T size) {
    if (0 <= i && i < size) SK_LIKELY {
        return i;
    }

    SK_UNLIKELY {
        #if defined(SK_DEBUG)
            sk_print_index_out_of_bounds(static_cast<size_t>(i), static_cast<size_t>(size));
        #else
            SkUNREACHABLE;
        #endif
    }
}

[[noreturn]] SK_API inline void sk_print_length_too_big(size_t i, size_t size) {
    SK_ABORT("Length (%zu) is too big for size %zu.\n", i, size);
}

template <typename T> SK_API inline T sk_collection_check_length(T i, T size) {
    if (0 <= i && i <= size) SK_LIKELY {
        return i;
    }

    SK_UNLIKELY {
        #if defined(SK_DEBUG)
            sk_print_length_too_big(static_cast<size_t>(i), static_cast<size_t>(size));
        #else
            SkUNREACHABLE;
        #endif
    }
}

SK_API inline void sk_collection_not_empty(bool empty) {
    if (empty) SK_UNLIKELY {
        #if defined(SK_DEBUG)
            SK_ABORT("Collection is empty.\n");
        #else
            SkUNREACHABLE;
        #endif
    }
}

[[noreturn]] SK_API inline void sk_print_size_too_big(size_t size, size_t maxSize) {
    SK_ABORT("Size (%zu) can't be represented in bytes. Max size is %zu.\n", size, maxSize);
}

template <typename T>
SK_ALWAYS_INLINE size_t check_size_bytes_too_big(size_t size) {
    const size_t kMaxSize = std::numeric_limits<size_t>::max() / sizeof(T);
    if (size > kMaxSize) {
        #if defined(SK_DEBUG)
            sk_print_size_too_big(size, kMaxSize);
        #else
            SkUNREACHABLE;
        #endif
    }
    return size;
}

#endif  // SkAssert_DEFINED