Skip to content

Commit 569cb1f

Browse files
committed
Initial import.
0 parents  commit 569cb1f

File tree

3 files changed

+321
-0
lines changed

3 files changed

+321
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*~
2+
*#
3+
*.bak

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Portable Snippets
2+
3+
This is a collection of snippets written in C for doing various tasks
4+
in a relatively portable manner. Some of them may be a bit overkill
5+
for your application; feel free to just take what you need.
6+
Everything is CC0 licensed (public domain).
7+
8+
This repository currently contains:
9+
10+
* endian.h — endianness detection and swapping
11+
12+
Please don't be shy about filing issues about these; if you have
13+
problems it's likely others will, as well, so we would like to fix
14+
them.
15+
16+
If you have a snippet you would like to contribute, please file an
17+
issue or pull request. These are coming soon (I have the code, just
18+
need to clean it up and/or remove some proprietary bits):
19+
20+
* Runtime CPU feature detection (SSE, AVX, NEON, etc.).
21+
* High-precision time. There is
22+
[some code in µnit for this](https://github.com/nemequ/munit/blob/ca64cf27eda984855323917736ed595030f150db/munit.c#L274)
23+
but it's geared towards timing.
24+
* A portable stdatomic.h
25+
26+
Some things don't really fit in a "snippet", or aren't public domain
27+
and so cannot be included in this repository, so here are a few
28+
projects for doing things portably which you may be interested in:
29+
30+
* [parg](https://github.com/jibsen/parg)
31+
Argument parsing similar to getopt/getopt_long. Public domain.
32+
* [TinyCThread](https://tinycthread.github.io/) — Implements the C11
33+
threads API on top of pthreads and the Windows API. zlib license.
34+
* [pstdint.h](http://www.azillionmonkeys.com/qed/pstdint.h)
35+
stdint.h/cstdint for platforms which don't have it. 3-clause BSD
36+
license.
37+
* [safe-math](https://github.com/nemequ/safe-math) — portable
38+
overflow-safe path functions. MIT license.
39+
40+
If there is a project you'd like to see added to the list, please file
41+
an issue.

endian.h

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
/* Portable Snippets - https://gitub.com/nemequ/portable-snippets
2+
* Created by Evan Nemerson <[email protected]>
3+
*
4+
* To the extent possible under law, the authors have waived all
5+
* copyright and related or neighboring rights to Hedley. For
6+
* details, see the Creative Commons Zero 1.0 Universal license at
7+
* https://creativecommons.org/publicdomain/zero/1.0/
8+
******************************************************************
9+
* Endianness detection and swapping
10+
* v1
11+
*
12+
* This is probably a bit overkill; you may want to simplify things a
13+
* bit (i.e., remove unused macros) if you copy this into your
14+
* project.
15+
*
16+
* Support for PDP endian is incomplete.
17+
*
18+
* If you improve this, *please* contribute your change back to us.
19+
*/
20+
21+
/* TODO: don't require this on old versions of MSVC */
22+
#include <stdint.h>
23+
24+
#if !defined(PSNIP_ENDIAN_H)
25+
#define PSNIP_ENDIAN_H
26+
27+
#if !defined(PSNIP_LITTLE_ENDIAN)
28+
# define PSNIP_LITTLE_ENDIAN 1234
29+
#endif
30+
#if !defined(PSNIP_BIG_ENDIAN)
31+
# define PSNIP_BIG_ENDIAN 4321
32+
#endif
33+
#if !defined(PSNIP_PDP_ENDIAN)
34+
# define PSNIP_PDP_ENDIAN 3412
35+
#endif
36+
37+
/* Detection
38+
*
39+
* Detecting endianness can be a bit tricky. There isn't really a
40+
* good standard way of determining endianness, and it's actually
41+
* possible to mix endianness within a single program. This is
42+
* currently pretty rare, though.
43+
*
44+
* We define PSNIP_BYTE_ORDER to PSNIP_LITTLE_ENDIAN,
45+
* PSNIP_BIG_ENDIAN, or PSNIP_PDP_ENDIAN. Additionally, you can use
46+
* the PSNIP_RT_BYTE_ORDER to check the runtime byte order, which is a
47+
* bit more reliable (though it does introduce some runtime overhead.
48+
*
49+
* In the event we are unable to determine endianness at compile-time,
50+
* PSNIP_BYTE_ORDER is left undefined and you will be forced to rely
51+
* on PSNIP_RT_BYTE_ORDER. */
52+
53+
#if !defined(PSNIP_BYTE_ORDER)
54+
/* GCC (and compilers masquerading as GCC) define __BYTE_ORDER__. */
55+
# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
56+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
57+
# elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
58+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
59+
# elif defined(__BYTE_ORDER__) && defined(__ORDER_PDP_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_PDP_ENDIAN__)
60+
# define PSNIP_BYTE_ORDER PSNIP_PDP_ENDIAN
61+
/* We know the endianness of some common architectures. Common
62+
* architectures not listed (ARM, POWER, MIPS, etc.) here are
63+
* bi-endian. */
64+
# elif defined(__amd64) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
65+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
66+
# elif defined(__s390x__) || defined(__zarch__)
67+
# define PSNIP_BYTE_ORDER PSNIP_BIG_ENDIAN
68+
/* Looks like we'll have to rely on the platform. If we're missing a
69+
* platform, please let us know. */
70+
# elif defined(_WIN32)
71+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
72+
# elif defined(sun) || defined(__sun) /* Solaris */
73+
# include <sys/byteorder.h>
74+
# if defined(_LITTLE_ENDIAN)
75+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
76+
# elif defined(_BIG_ENDIAN)
77+
# define PSNIP_BYTE_ORDER PSNIP_BIG_ENDIAN
78+
# endif
79+
# elif defined(__APPLE__)
80+
# include <libkern/OSByteOrder.h>
81+
# if defined(__LITTLE_ENDIAN__)
82+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
83+
# elif defined(__BIG_ENDIAN__)
84+
# define PSNIP_BYTE_ORDER PSNIP_BIG_ENDIAN
85+
# endif
86+
# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(BSD)
87+
# include <machine/endian.h>
88+
# if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
89+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
90+
# elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)
91+
# define PSNIP_BYTE_ORDER PSNIP_BIG_ENDIAN
92+
# elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __PDP_ENDIAN)
93+
# define PSNIP_BYTE_ORDER PSNIP_PDP_ENDIAN
94+
# endif
95+
# else
96+
# include <endian.h>
97+
# if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
98+
# define PSNIP_BYTE_ORDER PSNIP_LITTLE_ENDIAN
99+
# elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
100+
# define PSNIP_BYTE_ORDER PSNIP_BIG_ENDIAN
101+
# elif defined(__BYTE_ORDER) && defined(__PDP_ENDIAN) && (__BYTE_ORDER == __PDP_ENDIAN)
102+
# define PSNIP_BYTE_ORDER PSNIP_PDP_ENDIAN
103+
# endif
104+
# endif
105+
#endif
106+
107+
/* PDP endian not yet supported. Patches welcome. */
108+
#if defined(PSNIP_BYTE_ORDER) && (PSNIP_BYTE_ORDER == PSNIP_PDP_ENDIAN)
109+
# undef PSNIP_PDP_ENDIAN
110+
#endif
111+
112+
/* We need fixed-length types for some stuff. */
113+
#if defined(_WIN32)
114+
# define PSNIP_ENDIAN_UINT16_T unsigned short
115+
# define PSNIP_ENDIAN_UINT32_T unsigned long
116+
# define PSNIP_ENDIAN_UINT64_T unsigned __int64
117+
#else
118+
# include <stdint.h>
119+
# define PSNIP_ENDIAN_UINT16_T uint16_t
120+
# define PSNIP_ENDIAN_UINT32_T uint32_t
121+
# define PSNIP_ENDIAN_UINT64_T uint64_t
122+
#endif
123+
124+
/* Runtime detection. */
125+
#define PSNIP_RT_BYTE_ORDER_IS_LE \
126+
((((union { unsigned char bytes[4]; PSNIP_ENDIAN_UINT32_T value; }) { { 1, 2, 3, 4 } }).value) == UINT32_C(0x04030201))
127+
#define PSNIP_RT_BYTE_ORDER_IS_BE \
128+
((((union { unsigned char bytes[4]; PSNIP_ENDIAN_UINT32_T value; }) { { 1, 2, 3, 4 } }).value) == UINT32_C(0x01020304))
129+
#define PSNIP_RT_BYTE_ORDER \
130+
(PSNIP_RT_BYTE_ORDER_IS_LE ? PSNIP_LITTLE_ENDIAN : (PSNIP_RT_BYTE_ORDER_IS_BE ? PSNIP_BIG_ENDIAN : PSNIP_PDP_ENDIAN))
131+
132+
/* Swapping
133+
*
134+
* We define PSNIP_BSWAP16, PSNIP_BSWAP32, and PSNIP_BSWAP64 to
135+
* unconditionally swap byte orders between big-endian and
136+
* little-endian.
137+
*
138+
* We also define macros for reading and writing values with different
139+
* endiannesses which will be preprocessed to either a swap operation
140+
* or identity, depending on the system's endianness as determined at
141+
* compile time or, if none could be determined, we fall back on
142+
* runtime detection. These are probably the macros you want to use.
143+
* They are:
144+
*
145+
* PSNIP_READ_LE16, PSNIP_READ_LE32, PSNIP_READ_LE64,
146+
* PSNIP_READ_BE16, PSNIP_READ_BE32, PSNIP_READ_BE64,
147+
* PSNIP_WRITE_LE16, PSNIP_WRITE_LE32, PSNIP_WRITE_LE64,
148+
* PSNIP_WRITE_BE16, PSNIP_WRITE_BE32, PSNIP_WRITE_BE64,
149+
*
150+
* Finally, there are runtime-only version of those macros which
151+
* ignore the compile-time endianness and always check at runtime:
152+
*
153+
* PSNIP_READ_RT_LE16, PSNIP_READ_RT_LE32, PSNIP_READ_RT_LE64,
154+
* PSNIP_READ_RT_BE16, PSNIP_READ_RT_BE32, PSNIP_READ_RT_BE64,
155+
* PSNIP_WRITE_RT_LE16, PSNIP_WRITE_RT_LE32, PSNIP_WRITE_RT_LE64,
156+
* PSNIP_WRITE_RT_BE16, PSNIP_WRITE_RT_BE32, PSNIP_WRITE_RT_BE64
157+
*
158+
* Interestingly, GCC and clang will detect that these are for
159+
* swapping endianness and optimize them into an unconditional bswap,
160+
* at least when endianness is known at compile time. Intel, OTOH,
161+
* keeps the runtime checks.
162+
*/
163+
164+
#if defined(__clang__) && defined(__has_builtin)
165+
# if !defined(PSNIP_BSWAP16) && __has_builtin(__builtin_bswap16)
166+
# define PSNIP_BSWAP16(v) __builtin_bswap16((int16_t) (v))
167+
# endif
168+
# if !defined(PSNIP_BSWAP32) && __has_builtin(__builtin_bswap32)
169+
# define PSNIP_BSWAP32(v) __builtin_bswap32((int32_t) (v))
170+
# endif
171+
# if !defined(PSNIP_BSWAP64) && __has_builtin(__builtin_bswap64)
172+
# define PSNIP_BSWAP64(v) __builtin_bswap64((int64_t) (v))
173+
# endif
174+
#endif
175+
176+
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
177+
# if !defined(PSNIP_BSWAP16) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
178+
# define PSNIP_BSWAP16(v) __builtin_bswap16((int16_t) (v))
179+
# endif
180+
# if !defined(PSNIP_BSWAP32)
181+
# define PSNIP_BSWAP32(v) __builtin_bswap32((int32_t) (v))
182+
# endif
183+
# if !defined(PSNIP_BSWAP64)
184+
# define PSNIP_BSWAP64(v) __builtin_bswap64((int64_t) (v))
185+
# endif
186+
#endif
187+
188+
#if defined(_MSC_VER) && _MSC_VER >= 1310
189+
# include <stdlib.h>
190+
# if !defined(PSNIP_BSWAP16)
191+
# define PSNIP_BSWAP16(v) _byteswap_ushort((unsigned short) (v))
192+
# endif
193+
# if !defined(PSNIP_BSWAP16)
194+
# define PSNIP_BSWAP32(v) _byteswap_ulong((unsigned long) (v))
195+
# endif
196+
# if !defined(PSNIP_BSWAP16)
197+
# define PSNIP_BSWAP64(v) _byteswap_uint64((unsigned __int64) (v))
198+
# endif
199+
#endif
200+
201+
#if !defined(PSNIP_BSWAP16)
202+
# define PSNIP_BSWAP16(v) \
203+
(((((PSNIP_ENDIAN_UINT16_T) (v)) & UINT16_C(0xff00)) >> 8) | \
204+
((((PSNIP_ENDIAN_UINT16_T) (v)) & UINT16_C(0x00ff)) << 8))
205+
#endif
206+
#if !defined(PSNIP_BSWAP32)
207+
# define PSNIP_BSWAP32(v) \
208+
(((((PSNIP_ENDIAN_UINT32_T) (v)) & UINT32_C(0xff000000)) >> 24) | \
209+
((((PSNIP_ENDIAN_UINT32_T) (v)) & UINT32_C(0x00ff0000)) >> 8) | \
210+
((((PSNIP_ENDIAN_UINT32_T) (v)) & UINT32_C(0x0000ff00)) << 8) | \
211+
((((PSNIP_ENDIAN_UINT32_T) (v)) & UINT32_C(0x000000ff)) << 24))
212+
#endif
213+
#if !defined(PSNIP_BSWAP64)
214+
# define PSNIP_BSWAP64(v) \
215+
(((((PSNIP_ENDIAN_UINT64_T) (v)) & (0xff00000000000000ULL)) >> 56) | \
216+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x00ff000000000000ULL)) >> 40) | \
217+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x0000ff0000000000ULL)) >> 24) | \
218+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x000000ff00000000ULL)) >> 8) | \
219+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x00000000ff000000ULL)) << 8) | \
220+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x0000000000ff0000ULL)) << 24) | \
221+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x000000000000ff00ULL)) << 40) | \
222+
((((PSNIP_ENDIAN_UINT64_T) (v)) & (0x00000000000000ffULL)) << 56));
223+
#endif
224+
225+
static inline PSNIP_ENDIAN_UINT16_T psnip_io_le16(PSNIP_ENDIAN_UINT16_T v) { return (PSNIP_RT_BYTE_ORDER == PSNIP_LITTLE_ENDIAN ? (v) : PSNIP_BSWAP16(v)); }
226+
static inline PSNIP_ENDIAN_UINT32_T psnip_io_le32(PSNIP_ENDIAN_UINT32_T v) { return (PSNIP_RT_BYTE_ORDER == PSNIP_LITTLE_ENDIAN ? (v) : PSNIP_BSWAP32(v)); }
227+
static inline PSNIP_ENDIAN_UINT64_T psnip_io_le64(PSNIP_ENDIAN_UINT64_T v) { return (PSNIP_RT_BYTE_ORDER == PSNIP_LITTLE_ENDIAN ? (v) : PSNIP_BSWAP64(v)); }
228+
static inline PSNIP_ENDIAN_UINT16_T psnip_io_be16(PSNIP_ENDIAN_UINT16_T v) { return (PSNIP_RT_BYTE_ORDER == PSNIP_BIG_ENDIAN ? (v) : PSNIP_BSWAP16(v)); }
229+
static inline PSNIP_ENDIAN_UINT32_T psnip_io_be32(PSNIP_ENDIAN_UINT32_T v) { return (PSNIP_RT_BYTE_ORDER == PSNIP_BIG_ENDIAN ? (v) : PSNIP_BSWAP32(v)); }
230+
static inline PSNIP_ENDIAN_UINT64_T psnip_io_be64(PSNIP_ENDIAN_UINT64_T v) { return (PSNIP_RT_BYTE_ORDER == PSNIP_BIG_ENDIAN ? (v) : PSNIP_BSWAP64(v)); }
231+
232+
#define PSNIP_READ_RT_LE16(v) psnip_io_le16(v)
233+
#define PSNIP_READ_RT_LE32(v) psnip_io_le32(v)
234+
#define PSNIP_READ_RT_LE64(v) psnip_io_le64(v)
235+
#define PSNIP_READ_RT_BE16(v) psnip_io_be16(v)
236+
#define PSNIP_READ_RT_BE32(v) psnip_io_be32(v)
237+
#define PSNIP_READ_RT_BE64(v) psnip_io_be64(v)
238+
239+
#if defined(PSNIP_BYTE_ORDER)
240+
# if PSNIP_BYTE_ORDER == PSNIP_LITTLE_ENDIAN
241+
# define PSNIP_READ_LE16(v) (v)
242+
# define PSNIP_READ_LE32(v) (v)
243+
# define PSNIP_READ_LE64(v) (v)
244+
# define PSNIP_READ_BE16(v) PSNIP_BSWAP16(v)
245+
# define PSNIP_READ_BE32(v) PSNIP_BSWAP32(v)
246+
# define PSNIP_READ_BE64(v) PSNIP_BSWAP64(v)
247+
# elif PSNIP_BYTE_ORDER == PSNIP_BIG_ENDIAN
248+
# define PSNIP_READ_LE16(v) PSNIP_BSWAP16(v)
249+
# define PSNIP_READ_LE32(v) PSNIP_BSWAP32(v)
250+
# define PSNIP_READ_LE64(v) PSNIP_BSWAP64(v)
251+
# define PSNIP_READ_BE16(v) (v)
252+
# define PSNIP_READ_BE32(v) (v)
253+
# define PSNIP_READ_BE64(v) (v)
254+
# endif
255+
#else
256+
# define PSNIP_READ_LE16(v) PSNIP_READ_RT_LE16(v)
257+
# define PSNIP_READ_LE32(v) PSNIP_READ_RT_LE32(v)
258+
# define PSNIP_READ_LE64(v) PSNIP_READ_RT_LE64(v)
259+
# define PSNIP_READ_BE16(v) PSNIP_READ_RT_BE16(v)
260+
# define PSNIP_READ_BE32(v) PSNIP_READ_RT_BE32(v)
261+
# define PSNIP_READ_BE64(v) PSNIP_READ_RT_BE64(v)
262+
#endif
263+
264+
#define PSNIP_WRITE_LE16(v) PSNIP_READ_LE16(v)
265+
#define PSNIP_WRITE_LE32(v) PSNIP_READ_LE32(v)
266+
#define PSNIP_WRITE_LE64(v) PSNIP_READ_LE64(v)
267+
#define PSNIP_WRITE_BE16(v) PSNIP_READ_BE16(v)
268+
#define PSNIP_WRITE_BE32(v) PSNIP_READ_BE32(v)
269+
#define PSNIP_WRITE_BE64(v) PSNIP_READ_BE64(v)
270+
#define PSNIP_WRITE_RT_LE16(v) PSNIP_READ_RT_LE16(v)
271+
#define PSNIP_WRITE_RT_LE32(v) PSNIP_READ_RT_LE32(v)
272+
#define PSNIP_WRITE_RT_LE64(v) PSNIP_READ_RT_LE64(v)
273+
#define PSNIP_WRITE_RT_BE16(v) PSNIP_READ_RT_BE16(v)
274+
#define PSNIP_WRITE_RT_BE32(v) PSNIP_READ_RT_BE32(v)
275+
#define PSNIP_WRITE_RT_BE64(v) PSNIP_READ_RT_BE64(v)
276+
277+
#endif /* !defined(PSNIP_ENDIAN_H) */

0 commit comments

Comments
 (0)