aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/core/utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/osmocom/core/utils.h')
-rw-r--r--include/osmocom/core/utils.h94
1 files changed, 85 insertions, 9 deletions
diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index 86191209..92bea59f 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -33,14 +33,23 @@
/*! Make a value_string entry from an enum value name */
#define OSMO_VALUE_STRING(x) { x, #x }
/*! Number of bytes necessary to store given BITS */
-#define OSMO_BYTES_FOR_BITS(BITS) ((BITS + 8 - 1) / 8)
+#define OSMO_BYTES_FOR_BITS(BITS) (((BITS) + 7) / 8)
/*! Copy a C-string into a sized buffer using sizeof to detect buffer's size */
#define OSMO_STRLCPY_ARRAY(array, src) osmo_strlcpy(array, src, sizeof(array))
+/*! Branch prediction optimizations */
+#if defined(__GNUC__)
+#define OSMO_LIKELY(exp) __builtin_expect(!!(exp), 1)
+#define OSMO_UNLIKELY(exp) __builtin_expect(!!(exp), 0)
+#else
+#define OSMO_LIKELY(exp) exp
+#define OSMO_UNLIKELY(exp) exp
+#endif
+
/*! A mapping between human-readable string and numeric value */
struct value_string {
- int value; /*!< numeric value */
+ uint32_t value; /*!< numeric value */
const char *str; /*!< human-readable string */
};
@@ -57,7 +66,7 @@ uint8_t osmo_char2bcd(char c);
int osmo_bcd2str(char *dst, size_t dst_size, const uint8_t *bcd, int start_nibble, int end_nibble, bool allow_hex);
int osmo_str2bcd(uint8_t *dst, size_t dst_size, const char *digits, int start_nibble, int end_nibble, bool allow_hex);
-int osmo_hexparse(const char *str, uint8_t *b, int max_len);
+int osmo_hexparse(const char *str, uint8_t *b, unsigned int max_len);
char *osmo_ubit_dump_buf(char *buf, size_t buf_len, const uint8_t *bits, unsigned int len);
char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);
@@ -102,9 +111,11 @@ do { \
* the predicate evaluates to false (0).
*/
#define OSMO_ASSERT(exp) \
- if (!(exp)) { \
+do { \
+ if (OSMO_UNLIKELY(!(exp))) { \
osmo_panic("Assert failed %s %s:%d\n", #exp, __FILE__, __LINE__); \
- }
+ } \
+} while (0); /* some code invokes OSMO_ASSERT() without the semicolon */
/*! duplicate a string using talloc and release its prior content (if any)
* \param[in] ctx Talloc context to use for allocation
@@ -117,6 +128,8 @@ static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char
*dst = talloc_strdup(ctx, newstr);
}
+void osmo_talloc_replace_string_fmt(void *ctx, char **dst, const char *fmt, ...);
+
/*! Append to a string and re-/allocate if necessary.
* \param[in] ctx Talloc context to use for initial allocation.
* \param[in,out] dest char* to re-/allocate and append to.
@@ -155,10 +168,12 @@ size_t osmo_quote_cstr_buf(char *buf, size_t bufsize, const char *str, int in_le
char *osmo_quote_cstr_c(void *ctx, const char *str, int in_len);
const char *osmo_escape_str(const char *str, int len);
+int osmo_escape_str_buf3(char *buf, size_t bufsize, const char *str, int in_len);
char *osmo_escape_str_buf2(char *buf, size_t bufsize, const char *str, int in_len);
const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
char *osmo_escape_str_c(const void *ctx, const char *str, int in_len);
const char *osmo_quote_str(const char *str, int in_len);
+int osmo_quote_str_buf3(char *buf, size_t bufsize, const char *str, int in_len);
char *osmo_quote_str_buf2(char *buf, size_t bufsize, const char *str, int in_len);
const char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
char *osmo_quote_str_c(const void *ctx, const char *str, int in_len);
@@ -167,6 +182,18 @@ int osmo_print_n(char *buf, size_t bufsize, const char *str, size_t n);
uint32_t osmo_isqrt32(uint32_t x);
+/*! Floored Modulo (See also: Daan Leijen, Division and Modulus for Computer Scientists).
+ * \param[in] x dividend.
+ * \param[in] y divisor.
+ * \returns remainder of x divided by y. */
+#define OSMO_MOD_FLR(x, y) (((x) > 0 && (y) < 0) || ((x) < 0 && (y) > 0) ? (x) % (y) + (y) : (x) % (y))
+
+/*! Euclidean Modulo (See also: Daan Leijen, Division and Modulus for Computer Scientists).
+ * \param[in] x dividend.
+ * \param[in] y divisor.
+ * \returns remainder of x divided by y. */
+#define OSMO_MOD_EUC(x, y) ((x) % (y) < 0 ? (y) > 0 ? (x) % (y) + (y) : (x) % (y) - (y) : (x) % (y))
+
char osmo_luhn(const char* in, int in_len);
/*! State for OSMO_STRBUF_APPEND() and OSMO_STRBUF_PRINTF(). See there for examples. */
@@ -222,9 +249,9 @@ struct osmo_strbuf {
#define OSMO_STRBUF_APPEND(STRBUF, func, args...) do { \
if (!(STRBUF).pos) \
(STRBUF).pos = (STRBUF).buf; \
- size_t _sb_remain = (STRBUF).buf ? (STRBUF).len - ((STRBUF).pos - (STRBUF).buf) : 0; \
+ size_t _sb_remain = OSMO_STRBUF_REMAIN(STRBUF); \
int _sb_l = func((STRBUF).pos, _sb_remain, ##args); \
- if (_sb_l < 0 || _sb_l > _sb_remain) \
+ if (_sb_l < 0 || (size_t)_sb_l > _sb_remain) \
(STRBUF).pos = (STRBUF).buf + (STRBUF).len; \
else if ((STRBUF).pos) \
(STRBUF).pos += _sb_l; \
@@ -254,6 +281,38 @@ struct osmo_strbuf {
#define OSMO_STRBUF_PRINTF(STRBUF, fmt, args...) \
OSMO_STRBUF_APPEND(STRBUF, snprintf, fmt, ##args)
+/*! Get remaining space for characters and terminating nul in the given struct osmo_strbuf.
+ * \param[in] sb the string buffer to get the remaining space for.
+ * \returns remaining space in the given struct osmo_strbuf. */
+static inline size_t _osmo_strbuf_remain(const struct osmo_strbuf *sb)
+{
+ if (OSMO_UNLIKELY(sb == NULL || sb->buf == NULL))
+ return 0;
+ if (sb->pos == NULL)
+ return sb->len;
+ return sb->len - (sb->pos - sb->buf);
+}
+
+/*! Return remaining space for characters and terminating nul in the given struct osmo_strbuf. */
+#define OSMO_STRBUF_REMAIN(STRBUF) \
+ _osmo_strbuf_remain(&(STRBUF))
+
+/*! Get number of actual characters (without terminating nul) in the given struct osmo_strbuf.
+ * \param[in] sb the string buffer to get the number of characters for.
+ * \returns number of actual characters (without terminating nul). */
+static inline size_t _osmo_strbuf_char_count(const struct osmo_strbuf *sb)
+{
+ if (OSMO_UNLIKELY(sb == NULL || sb->buf == NULL))
+ return 0;
+ if (sb->pos == NULL || sb->pos <= sb->buf)
+ return 0;
+ return OSMO_MIN((size_t)(sb->pos - sb->buf), sb->len - 1);
+}
+
+/*! Return number of actual characters contained in struct osmo_strbuf (without terminating nul). */
+#define OSMO_STRBUF_CHAR_COUNT(STRBUF) \
+ _osmo_strbuf_char_count(&(STRBUF))
+
/*! Like OSMO_STRBUF_APPEND(), but for function signatures that return the char* buffer instead of a length.
* When using this function, the final STRBUF.chars_needed may not reflect the actual number of characters needed, since
* that number cannot be obtained from this kind of function signature.
@@ -265,7 +324,7 @@ struct osmo_strbuf {
#define OSMO_STRBUF_APPEND_NOLEN(STRBUF, func, args...) do { \
if (!(STRBUF).pos) \
(STRBUF).pos = (STRBUF).buf; \
- size_t _sb_remain = (STRBUF).buf ? (STRBUF).len - ((STRBUF).pos - (STRBUF).buf) : 0; \
+ size_t _sb_remain = OSMO_STRBUF_REMAIN(STRBUF); \
if (_sb_remain) { \
func((STRBUF).pos, _sb_remain, ##args); \
} \
@@ -277,8 +336,25 @@ struct osmo_strbuf {
(STRBUF).chars_needed += _sb_l; \
} while(0)
+void osmo_strbuf_drop_tail(struct osmo_strbuf *sb, size_t n_chars);
+/* Convenience macro. struct osmo_strbuf are typically static to a function scope. Avoid having to type '&', same as
+ * with all the other OSMO_STRBUF_* API. */
+#define OSMO_STRBUF_DROP_TAIL(STRBUF, N_CHARS) osmo_strbuf_drop_tail(&(STRBUF), N_CHARS)
+
+void osmo_strbuf_added_tail(struct osmo_strbuf *sb, size_t n_chars);
+/* Convenience macro. struct osmo_strbuf are typically static to a function scope. Avoid having to type '&', same as
+ * with all the other OSMO_STRBUF_* API. */
+#define OSMO_STRBUF_ADDED_TAIL(STRBUF, N_CHARS) osmo_strbuf_added_tail(&(STRBUF), N_CHARS)
+
bool osmo_str_startswith(const char *str, const char *startswith_str);
+int osmo_float_str_to_int(int64_t *val, const char *str, unsigned int precision);
+int osmo_int_to_float_str_buf(char *buf, size_t buflen, int64_t val, unsigned int precision);
+char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision);
+
+int osmo_str_to_int64(int64_t *result, const char *str, int base, int64_t min_val, int64_t max_val);
+int osmo_str_to_int(int *result, const char *str, int base, int min_val, int max_val);
+
/*! Translate a buffer function to a talloc context function.
* This is the full function body of a char *foo_name_c(void *ctx, val...) function, implemented by an
* int foo_name_buf(buf, buflen, val...) function:
@@ -314,7 +390,7 @@ bool osmo_str_startswith(const char *str, const char *startswith_str);
_needed = FUNC_BUF(_str, _len, ## FUNC_BUF_ARGS); \
if (_needed < 0) \
goto OSMO_NAME_C_on_error; \
- if (_needed < _len) \
+ if ((unsigned int) _needed < _len) \
return _str; \
_len = _needed + 1; \
if (_str) \