xref: /third_party/littlefs/lfs_util.h (revision 19ea8026)
1/*
2 * lfs utility functions
3 *
4 * Copyright (c) 2022, The littlefs authors.
5 * Copyright (c) 2017, Arm Limited. All rights reserved.
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8#ifndef LFS_UTIL_H
9#define LFS_UTIL_H
10
11// Users can override lfs_util.h with their own configuration by defining
12// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
13//
14// If LFS_CONFIG is used, none of the default utils will be emitted and must be
15// provided by the config file. To start, I would suggest copying lfs_util.h
16// and modifying as needed.
17#ifdef LFS_CONFIG
18#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
19#define LFS_STRINGIZE2(x) #x
20#include LFS_STRINGIZE(LFS_CONFIG)
21#else
22
23// System includes
24#include <stdint.h>
25#include <stdbool.h>
26#include <string.h>
27#include <inttypes.h>
28
29#ifndef LFS_NO_MALLOC
30#include <stdlib.h>
31#endif
32#ifndef LFS_NO_ASSERT
33#include <assert.h>
34#endif
35#if !defined(LFS_NO_DEBUG) || \
36        !defined(LFS_NO_WARN) || \
37        !defined(LFS_NO_ERROR) || \
38        defined(LFS_YES_TRACE)
39#include <stdio.h>
40#endif
41
42#ifdef __cplusplus
43extern "C"
44{
45#endif
46
47
48// Macros, may be replaced by system specific wrappers. Arguments to these
49// macros must not have side-effects as the macros can be removed for a smaller
50// code footprint
51
52// Logging functions
53#ifndef LFS_TRACE
54#ifdef LFS_YES_TRACE
55#define LFS_TRACE_(fmt, ...) \
56    printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
57#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
58#else
59#define LFS_TRACE(...)
60#endif
61#endif
62
63#ifndef LFS_DEBUG
64#ifndef LFS_NO_DEBUG
65#define LFS_DEBUG_(fmt, ...) \
66    printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
67#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
68#else
69#define LFS_DEBUG(...)
70#endif
71#endif
72
73#ifndef LFS_WARN
74#ifndef LFS_NO_WARN
75#define LFS_WARN_(fmt, ...) \
76    printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
77#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
78#else
79#define LFS_WARN(...)
80#endif
81#endif
82
83#ifndef LFS_ERROR
84#ifndef LFS_NO_ERROR
85#define LFS_ERROR_(fmt, ...) \
86    printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
87#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
88#else
89#define LFS_ERROR(...)
90#endif
91#endif
92
93// Runtime assertions
94#ifndef LFS_ASSERT
95#ifndef LFS_NO_ASSERT
96#define LFS_ASSERT(test) assert(test)
97#else
98#define LFS_ASSERT(test)
99#endif
100#endif
101
102
103// Builtin functions, these may be replaced by more efficient
104// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
105// expensive basic C implementation for debugging purposes
106
107// Min/max functions for unsigned 32-bit numbers
108static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
109    return (a > b) ? a : b;
110}
111
112static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
113    return (a < b) ? a : b;
114}
115
116// Align to nearest multiple of a size
117static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
118    return a - (a % alignment);
119}
120
121static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
122    return lfs_aligndown(a + alignment-1, alignment);
123}
124
125// Find the smallest power of 2 greater than or equal to a
126static inline uint32_t lfs_npw2(uint32_t a) {
127#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
128    return 32 - __builtin_clz(a-1);
129#else
130    uint32_t r = 0;
131    uint32_t s;
132    a -= 1;
133    s = (a > 0xffff) << 4; a >>= s; r |= s;
134    s = (a > 0xff  ) << 3; a >>= s; r |= s;
135    s = (a > 0xf   ) << 2; a >>= s; r |= s;
136    s = (a > 0x3   ) << 1; a >>= s; r |= s;
137    return (r | (a >> 1)) + 1;
138#endif
139}
140
141// Count the number of trailing binary zeros in a
142// lfs_ctz(0) may be undefined
143static inline uint32_t lfs_ctz(uint32_t a) {
144#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
145    return __builtin_ctz(a);
146#else
147    return lfs_npw2((a & -a) + 1) - 1;
148#endif
149}
150
151// Count the number of binary ones in a
152static inline uint32_t lfs_popc(uint32_t a) {
153#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
154    return __builtin_popcount(a);
155#else
156    a = a - ((a >> 1) & 0x55555555);
157    a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
158    return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
159#endif
160}
161
162// Find the sequence comparison of a and b, this is the distance
163// between a and b ignoring overflow
164static inline int lfs_scmp(uint32_t a, uint32_t b) {
165    return (int)(unsigned)(a - b);
166}
167
168// Convert between 32-bit little-endian and native order
169static inline uint32_t lfs_fromle32(uint32_t a) {
170#if (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
171    (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
172    (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
173    return a;
174#elif !defined(LFS_NO_INTRINSICS) && ( \
175    (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
176    (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
177    (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
178    return __builtin_bswap32(a);
179#else
180    return (((uint8_t*)&a)[0] <<  0) |
181           (((uint8_t*)&a)[1] <<  8) |
182           (((uint8_t*)&a)[2] << 16) |
183           (((uint8_t*)&a)[3] << 24);
184#endif
185}
186
187static inline uint32_t lfs_tole32(uint32_t a) {
188    return lfs_fromle32(a);
189}
190
191// Convert between 32-bit big-endian and native order
192static inline uint32_t lfs_frombe32(uint32_t a) {
193#if !defined(LFS_NO_INTRINSICS) && ( \
194    (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
195    (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
196    (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
197    return __builtin_bswap32(a);
198#elif (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
199    (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
200    (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
201    return a;
202#else
203    return (((uint8_t*)&a)[0] << 24) |
204           (((uint8_t*)&a)[1] << 16) |
205           (((uint8_t*)&a)[2] <<  8) |
206           (((uint8_t*)&a)[3] <<  0);
207#endif
208}
209
210static inline uint32_t lfs_tobe32(uint32_t a) {
211    return lfs_frombe32(a);
212}
213
214// Calculate CRC-32 with polynomial = 0x04c11db7
215uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
216
217// Allocate memory, only used if buffers are not provided to littlefs
218// Note, memory must be 64-bit aligned
219static inline void *lfs_malloc(size_t size) {
220#ifndef LFS_NO_MALLOC
221    return malloc(size);
222#else
223    (void)size;
224    return NULL;
225#endif
226}
227
228// Deallocate memory, only used if buffers are not provided to littlefs
229static inline void lfs_free(void *p) {
230#ifndef LFS_NO_MALLOC
231    free(p);
232#else
233    (void)p;
234#endif
235}
236
237
238#ifdef __cplusplus
239} /* extern "C" */
240#endif
241
242#endif
243#endif
244