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