4444 * Changelog:
4545 *
4646 * v2.0.1:
47+ * Better implementations of builtin functions when compiling wasm with clang
4748 * Correctly mark `ext_allocator_memdup` and `ext_allocator_strdup` inline.
4849 *
4950 * v2.0.0:
125126#include <stddef.h>
126127#include <stdint.h>
127128
129+ #if defined(__wasm__ ) && !defined(EXTLIB_WASM )
130+ #define EXTLIB_WASM
131+ #endif
132+
128133#ifdef EXTLIB_WASM
129134#ifndef EXTLIB_NO_STD
130135#define EXTLIB_NO_STD
169174#include <stdio.h>
170175#include <stdlib.h>
171176#include <string.h>
172- #else // EXTLIB_NO_STD
177+ #elif defined(EXTLIB_WASM ) && defined(__clang__ )
178+ #define memcmp __builtin_memcmp
179+ #define memcpy __builtin_memcpy
180+ #define memset __builtin_memset
181+ #define memchr __builtin_memchr
182+ static inline int strcmp (const char * l , const char * r ) {
183+ for (; * l == * r && * l ; l ++ , r ++ );
184+ return * (unsigned char * )l - * (unsigned char * )r ;
185+ }
186+ static inline size_t strlen (const char * s ) {
187+ size_t len = 0 ;
188+ while (s [len ] != '\0' ) len ++ ;
189+ return len ;
190+ }
191+ #else
173192static inline int memcmp (const void * s1 , const void * s2 , size_t n ) {
174193 const unsigned char * p1 = (const unsigned char * )s1 ;
175194 const unsigned char * p2 = (const unsigned char * )s2 ;
@@ -193,6 +212,14 @@ static inline void *memset(void *s, int c, size_t n) {
193212 while (n -- ) * p ++ = (unsigned char )c ;
194213 return s ;
195214}
215+ static inline void * memchr (const void * src_void , int c , size_t length ) {
216+ const uint8_t * src = (const uint8_t * )src_void ;
217+ while (length -- > 0 ) {
218+ if (* src == c ) return (void * )src ;
219+ src ++ ;
220+ }
221+ return NULL ;
222+ }
196223static inline size_t strlen (const char * s ) {
197224 size_t len = 0 ;
198225 while (s [len ] != '\0' ) len ++ ;
@@ -202,7 +229,6 @@ static inline int strcmp(const char *l, const char *r) {
202229 for (; * l == * r && * l ; l ++ , r ++ );
203230 return * (unsigned char * )l - * (unsigned char * )r ;
204231}
205- void assert (int c ); // TODO: are we sure we want to require wasm embedder to provide `assert`?
206232#endif // EXTLIB_NO_STD
207233
208234#ifdef EXTLIB_THREADSAFE
@@ -232,6 +258,7 @@ void assert(int c); // TODO: are we sure we want to require wasm embedder to pr
232258// Assert is disabled when compiling with NDEBUG, unreachable is instead replaced with compiler
233259// intrinsics on gcc, clang and msvc.
234260#ifndef NDEBUG
261+
235262#ifndef EXTLIB_NO_STD
236263#define EXT_ASSERT (cond , msg ) \
237264 ((cond) ? ((void)0) \
@@ -240,21 +267,33 @@ void assert(int c); // TODO: are we sure we want to require wasm embedder to pr
240267
241268#define EXT_UNREACHABLE () \
242269 (fprintf(stderr, "%s:%d: error: reached unreachable code\n", __FILE__, __LINE__), abort())
270+
271+ #elif defined(EXTLIB_WASM ) && defined(__clang__ )
272+
273+ #define EXT_ASSERT (cond , msg ) \
274+ do { \
275+ if(!(cond)) __builtin_trap(); \
276+ } while(0)
277+
278+ #define EXT_UNREACHABLE () __builtin_trap()
279+
243280#else
244281#define EXT_ASSERT (cond , msg ) assert((cond) && msg)
245282#define EXT_UNREACHABLE () assert(false && "reached unreachable code")
246283#endif // EXTLIB_NO_STD
247284
248- #else
249- #define EXT_ASSERT (cond , msg ) ((void)(cond))
285+ #else // NDEBUG
286+ #define EXT_ASSERT (cond , msg ) \
287+ do { \
288+ } while(0)
250289
251290#if defined(__GNUC__ ) || defined(__clang__ )
252291#define EXT_UNREACHABLE () __builtin_unreachable()
253292#elif defined(_MSC_VER )
254293#include <stdlib.h>
255294#define EXT_UNREACHABLE () __assume(0)
256295#else
257- #define EXT_UNREACHABLE ()
296+ #define EXT_UNREACHABLE () ((void)0)
258297#endif // defined(__GNUC__) || defined(__clang__)
259298
260299#endif // NDEBUG
@@ -2494,18 +2533,9 @@ void ext_sb_replace(Ext_StringBuffer *sb, size_t start, const char *to_replace,
24942533 EXT_ASSERT (start < sb -> size , "start out of bounds" );
24952534 size_t to_replace_len = strlen (to_replace );
24962535 for (size_t i = start ; i < sb -> size ; i ++ ) {
2497- #ifdef EXTLIB_NO_STD
2498- for (size_t j = 0 ; j < to_replace_len ; j ++ ) {
2499- if (sb -> items [i ] == to_replace [j ]) {
2500- sb -> items [i ] = replacment ;
2501- break ;
2502- }
2503- }
2504- #else
25052536 if (memchr (to_replace , sb -> items [i ], to_replace_len ) != NULL ) {
25062537 sb -> items [i ] = replacment ;
25072538 }
2508- #endif
25092539 }
25102540}
25112541
@@ -2689,14 +2719,7 @@ ptrdiff_t ext_ss_rfind_cstr(Ext_StringSlice ss, const char *needle, size_t offse
26892719}
26902720
26912721static bool any_match (char c , const char * set , size_t set_len ) {
2692- #ifdef EXTLIB_NO_STD
2693- for (size_t i = 0 ; i < set_len ; i ++ ) {
2694- if (c == set [i ]) return true;
2695- }
2696- return false;
2697- #else
26982722 return memchr (set , c , set_len ) != NULL ;
2699- #endif // EXTLIB_NO_STD
27002723}
27012724
27022725Ext_StringSlice ext_ss_split_once_any (Ext_StringSlice * ss , const char * set ) {
0 commit comments