• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 #ifndef IWUTILS_H
3 #define IWUTILS_H
4 
5 /**************************************************************************************************
6  * IOWOW library
7  *
8  * MIT License
9  *
10  * Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  *  copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *************************************************************************************************/
30 /**
31  * @file
32  * @author Anton Adamansky (adamansky@softmotions.com)
33  */
34 
35 #include "basedefs.h"
36 #include "iwxstr.h"
37 #include <math.h>
38 #include <assert.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 
42 IW_EXTERN_C_START
43 
44 /* Align x_ with v_. v_ must be simple power for 2 value. */
45 #define IW_ROUNDUP(x_, v_) (((x_) + (v_) - 1) & ~((v_) - 1))
46 
47 /* Round down align x_ with v_. v_ must be simple power for 2 value. */
48 #define IW_ROUNDOWN(x_, v_) ((x_) - ((x_) & ((v_) - 1)))
49 
50 #if defined(NDEBUG)
51 #define IW_DODEBUG(IW_expr_) \
52   do {                       \
53   } while (0)
54 #else
55 #define IW_DODEBUG(IW_expr_) \
56   { IW_expr_; }
57 #endif
58 
59 #if __GNUC__ >= 5
60 #define IW_SWAB16(num_) __builtin_bswap16(num_)
61 #else
62 #define IW_SWAB16(num_) \
63   ((((num_) & 0x00ffU) << 8) | (((num_) & 0xff00U) >> 8))
64 #endif
65 
66 #if __GNUC__ >= 4
67 #define IW_SWAB32(num_) __builtin_bswap32(num_)
68 #else
69 #define IW_SWAB32(num_)                                              \
70   ((((num_) & 0x000000ffUL) << 24) | (((num_) & 0x0000ff00UL) << 8) | \
71    (((num_) & 0x00ff0000UL) >> 8) | (((num_) & 0xff000000UL) >> 24))
72 #endif
73 
74 #if __GNUC__ >= 4
75 #define IW_SWAB64(num_) __builtin_bswap64(num_)
76 #else
77 #define IW_SWAB64(num_)                     \
78   ((((num_) & 0x00000000000000ffULL) << 56) | \
79    (((num_) & 0x000000000000ff00ULL) << 40) | \
80    (((num_) & 0x0000000000ff0000ULL) << 24) | \
81    (((num_) & 0x00000000ff000000ULL) << 8) |  \
82    (((num_) & 0x000000ff00000000ULL) >> 8) |  \
83    (((num_) & 0x0000ff0000000000ULL) >> 24) | \
84    (((num_) & 0x00ff000000000000ULL) >> 40) | \
85    (((num_) & 0xff00000000000000ULL) >> 56))
86 #endif
87 
88 #ifdef IW_BIGENDIAN
89 #define IW_HTOIS(num_) IW_SWAB16(num_)
90 #define IW_HTOIL(num_) IW_SWAB32(num_)
91 #define IW_HTOILL(num_) IW_SWAB64(num_)
92 #define IW_ITOHS(num_) IW_SWAB16(num_)
93 #define IW_ITOHL(num_) IW_SWAB32(num_)
94 #define IW_ITOHLL(num_) IW_SWAB64(num_)
95 #else
96 #define IW_HTOIS(num_) (num_)
97 #define IW_HTOIL(num_) (num_)
98 #define IW_HTOILL(num_) (num_)
99 #define IW_ITOHS(num_) (num_)
100 #define IW_ITOHL(num_) (num_)
101 #define IW_ITOHLL(num_) (num_)
102 #endif
103 
104 #define IW_WRITEBV(ptr_, v_, m_)  \
105   static_assert(sizeof(v_) == 1, "Mismatch v_ size"); \
106   (v_) = (m_);                          \
107   memcpy(ptr_, &(v_), 1); \
108   (ptr_) += 1
109 
110 #define IW_WRITESV(ptr_, v_, m_)  \
111   static_assert(sizeof(v_) == 2, "Mismatch v_ size"); \
112   (v_) = (m_);                          \
113   (v_) = IW_HTOIS(v_);                \
114   memcpy(ptr_, &(v_), 2); \
115   (ptr_) += 2
116 
117 #define IW_WRITELV(ptr_, v_, m_)  \
118   static_assert(sizeof(v_) == 4, "Mismatch v_ size"); \
119   (v_) = (m_);                          \
120   (v_) = IW_HTOIL(v_);                \
121   memcpy(ptr_, &(v_), 4); \
122   (ptr_) += 4
123 
124 #define IW_WRITELLV(ptr_, v_, m_) \
125   static_assert(sizeof(v_) == 8, "Mismatch v_ size"); \
126   (v_) = (m_);                          \
127   (v_) = IW_HTOILL(v_);               \
128   memcpy((ptr_), &(v_), 8); \
129   (ptr_) += 8
130 
131 #define IW_READBV(ptr_, t_, m_)   \
132   static_assert(sizeof(t_) == 1, "Mismatch t_ size"); \
133   (t_) = 0; \
134   memcpy(&(t_), ptr_, 1);  \
135   (m_) = (t_);   \
136   (ptr_) += 1
137 
138 #define IW_READSV(ptr_, t_, m_)   \
139   static_assert(sizeof(t_) == 2, "Mismatch t_ size"); \
140   (t_) = 0; \
141   memcpy(&(t_), ptr_, 2);  \
142   (m_) = IW_ITOHS(t_);  \
143   (ptr_) += 2
144 
145 #define IW_READLV(ptr_, t_, m_)   \
146   static_assert(sizeof(t_) == 4, "Mismatch t_ size"); \
147   (t_) = 0; \
148   memcpy(&(t_), ptr_, 4);  \
149   (m_) = IW_ITOHL(t_);  \
150   (ptr_) += 4
151 
152 #define IW_READLLV(ptr_, t_, m_)  \
153   static_assert(sizeof(t_) == 8, "Mismatch t_ size"); \
154   (t_) = 0; \
155   memcpy(&(t_), ptr_, 8);  \
156   (m_) = IW_ITOHLL(t_); \
157   (ptr_) += 8
158 
159 #ifndef SIZE_T_MAX
160 #define SIZE_T_MAX ((size_t)-1)
161 #endif
162 
163 #ifndef OFF_T_MIN
164 #define OFF_T_MIN ((off_t)(((uint64_t)1) << (8 * sizeof(off_t) - 1)))
165 #endif
166 #ifndef OFF_T_MAX
167 #define OFF_T_MAX ((off_t) ~(((uint64_t)1) << (8 * sizeof(off_t) - 1)))
168 #endif
169 
170 #ifdef __GNUC__
171 #define IW_LIKELY(x_) __builtin_expect(!!(x_), 1)
172 #define IW_UNLIKELY(x_) __builtin_expect(!!(x_), 0)
173 #else
174 #define IW_LIKELY(x_)
175 #define IW_UNLIKELY(x_)
176 #endif
177 
178 #define IW_RANGES_OVERLAP(IW_s1_, IW_e1_, IW_s2_, IW_e2_) \
179   (((IW_e1_) > (IW_s2_) && (IW_e1_) <= (IW_e2_)) ||       \
180    ((IW_s1_) >= (IW_s2_) && (IW_s1_) < (IW_e2_)) ||       \
181    ((IW_s1_) <= (IW_s2_) && (IW_e1_) >= (IW_e2_)))
182 
183 
184 ///////////////////////////////////////////////////////////////////////////
185 //                    Variable length number encoding                    //
186 ///////////////////////////////////////////////////////////////////////////
187 
188 /* set a buffer for a variable length 32 bit number */
189 #define IW_SETVNUMBUF(len_, buf_, num_) \
190   do { \
191     int32_t _num_ = (num_); \
192     if (_num_ == 0){ \
193       ((signed char *)(buf_))[0] = 0; \
194       (len_) = 1; \
195     } else { \
196       (len_) = 0; \
197       while(_num_ > 0) { \
198         int _rem_ = _num_ & 0x7f; \
199         _num_ >>= 7; \
200         if(_num_ > 0){ \
201           ((signed char *)(buf_))[(len_)] = ~(_rem_); \
202         } else { \
203           ((signed char *)(buf_))[(len_)] = _rem_; \
204         } \
205         (len_)++; \
206       } \
207     } \
208   } while(0)
209 
210 /* set a buffer for a variable length 64 number */
211 #define IW_SETVNUMBUF64(len_, buf_, num_) \
212   do { \
213     int64_t _num_ = (num_); \
214     if (_num_ == 0){ \
215       ((signed char *)(buf_))[0] = 0; \
216       (len_) = 1; \
217     } else { \
218       (len_) = 0; \
219       while(_num_ > 0) { \
220         int _rem_ = _num_ & 0x7f; \
221         _num_ >>= 7; \
222         if(_num_ > 0){ \
223           ((signed char *)(buf_))[(len_)] = ~(_rem_); \
224         } else { \
225           ((signed char *)(buf_))[(len_)] = _rem_; \
226         } \
227         (len_)++; \
228       } \
229     } \
230   } while(0)
231 
232 
233 /* read a 32 bit variable length buffer */
234 #define IW_READVNUMBUF(buf_, num_, step_) \
235   do { \
236     (num_) = 0; \
237     int32_t _base_ = 1; \
238     int _i_ = 0; \
239     while(1){ \
240       if (((const signed char *)(buf_))[_i_] >= 0){ \
241         (num_) += _base_ * ((const signed char *)(buf_))[_i_]; \
242         break; \
243       } \
244       (num_) += _base_ * ~(((const signed char *)(buf_))[_i_]); \
245       _base_ <<= 7; \
246       _i_++; \
247     } \
248     (step_) = _i_ + 1; \
249   } while(0)
250 
251 /* read a 64 bit variable length buffer */
252 #define IW_READVNUMBUF64(buf_, num_, step_) \
253   do { \
254     (num_) = 0; \
255     int64_t _base_ = 1; \
256     int _i_ = 0; \
257     while(1){ \
258       if (((const signed char *)(buf_))[_i_] >= 0){ \
259         (num_) += _base_ * ((const signed char *)(buf_))[_i_]; \
260         break; \
261       } \
262       (num_) += _base_ * ~(((const signed char *)(buf_))[_i_]); \
263       _base_ <<= 7; \
264       _i_++; \
265     } \
266     (step_) = _i_ + 1; \
267   } while(0)
268 
269 
270 /* read a 64 bit variable length buffer */
271 #define IW_READVNUMBUF64_2(buf_, num_) \
272   do { \
273     (num_) = 0; \
274     int64_t _base_ = 1; \
275     int _i_ = 0; \
276     while(1){ \
277       if (((const signed char *)(buf_))[_i_] >= 0){ \
278         (num_) += _base_ * ((const signed char *)(buf_))[_i_]; \
279         break; \
280       } \
281       (num_) += _base_ * ~(((const signed char *)(buf_))[_i_]); \
282       _base_ <<= 7; \
283       _i_++; \
284     } \
285   } while(0)
286 
287 
288 #define IW_VNUMBUFSZ 10
289 
290 #define IW_VNUMSIZE32(num_) \
291   ((num_) < 0x80ULL ? 1 : \
292    (num_) < 0x4000ULL ? 2 : \
293    (num_) < 0x200000ULL ? 3 : \
294    (num_) < 0x10000000ULL ? 4 : 5)
295 
296 /* Size of variable number in bytes */
297 #ifdef IW_32
298 #define IW_VNUMSIZE IW_VNUMSIZE32
299 #else
300 #define IW_VNUMSIZE(num_) \
301   ((num_) < 0x80ULL ? 1 : \
302    (num_) < 0x4000ULL ? 2 : \
303    (num_) < 0x200000ULL ? 3 : \
304    (num_) < 0x10000000ULL ? 4 : \
305    (num_) < 0x800000000ULL ? 5 : \
306    (num_) < 0x40000000000ULL ? 6 : \
307    (num_) < 0x2000000000000ULL ? 7 : \
308    (num_) < 0x100000000000000ULL ? 8 : \
309    (num_) < 0x8000000000000000ULL ? 9 : 10)
310 #endif
311 
312 /* Lexicographic comparison of values */
313 #define IW_CMP(rv_, vp1_, vp1sz_, vp2_, vp2sz_) \
314   do { \
315     (rv_) = 0; \
316     int min_ = (vp1sz_) < (vp2sz_) ? (vp1sz_) : (vp2sz_); \
317     for (int i = 0; i < min_; i++) { \
318       (rv_) = (int) (((const uint8_t *)(vp1_))[i] - ((const uint8_t *)(vp2_))[i]); \
319       if (rv_) { \
320         break; \
321       } \
322     } \
323     if ((rv_) == 0) (rv_) = (vp1sz_) - (vp2sz_); \
324   } while(0)
325 
326 
327 /* Lexicographic comparison common prefix of values */
328 #define IW_CMP2(rv_, vp1_, vp1sz_, vp2_, vp2sz_) \
329   do { \
330     (rv_) = 0; \
331     int min_ = (vp1sz_) < (vp2sz_) ? (vp1sz_) : (vp2sz_); \
332     for (int i = 0; i < min_; i++) { \
333       (rv_) = (int) (((const uint8_t *)(vp1_))[i] - ((const uint8_t *)(vp2_))[i]); \
334       if (rv_) { \
335         break; \
336       } \
337     } \
338   } while(0)
339 
340 IW_EXPORT iwrc iwu_init(void);
341 
342 /**
343  * @brief Set seed to random generator
344  */
345 IW_EXPORT void iwu_rand_seed(uint32_t seed);
346 
347 /**
348  * @brief Generate random in [0, 0xffffffff]
349  */
350 IW_EXPORT uint32_t iwu_rand_u32(void);
351 
352 /**
353  * @brief Create normal distributed random number.
354  * @param avg Distribution pivot
355  * @param sd Avg square deviation
356  */
357 IW_EXPORT double_t iwu_rand_dnorm(double_t avg, double_t sd);
358 
359 /**
360  * @brief Create uniform distributed integer random number in: `[0, range)`
361  */
362 IW_EXPORT uint32_t iwu_rand_range(uint32_t range);
363 
364 /**
365  * @brief Create normal distributed integer random number.
366  */
367 IW_EXPORT uint32_t iwu_rand_inorm(int range);
368 
369 IW_EXPORT int iwlog2_32(uint32_t val);
370 
371 IW_EXPORT int iwlog2_64(uint64_t val);
372 
373 IW_EXPORT uint32_t iwu_crc32(const uint8_t *buf, int len, uint32_t init);
374 
375 /**
376  * @brief Replaces a char @a sch with @a rch in a null terminated @a data char buffer.
377  */
378 IW_EXPORT char *iwu_replace_char(char *data, char sch, char rch);
379 
380 /**
381  * @brief Returns `\0` terminated string as replacement
382  * of given `key`.
383  */
384 typedef const char *(*iwu_replace_mapper)(const char *key, void *op);
385 
386 /**
387  * @brief Replaces all occurriences of `keys`
388  * in `data` using `mapper` function.
389  *
390  * @param [out] result Resulting xstr buffer.
391  * @param data   Data to search
392  * @param datalen Length of data buffer
393  * @param keys   Array of keys to search
394  * @param keysz  Number of elements in keys array
395  * @param mapper Replacement mapper
396  * @param mapper_op Replacement mapper opaque data
397  */
398 IW_EXPORT iwrc iwu_replace(IWXSTR **result,
399                            const char *data,
400                            int datalen,
401                            const char *keys[],
402                            int keysz,
403                            iwu_replace_mapper mapper,
404                            void *mapper_op);
405 
406 IW_EXPORT int iwu_cmp_files(FILE *f1, FILE *f2, bool verbose);
407 
408 IW_EXPORT char *iwu_file_read_as_buf(const char *path);
409 
410 /**
411  * @brief Create X31 hash value.
412  */
413 IW_EXPORT uint32_t iwu_x31_u32_hash(const char *data);
414 
415 IW_EXTERN_C_END
416 
417 #endif
418