blob: ad7bc8b09a36522a80200f36c321454ec7bd9026 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef __BLOB_H__
#define __BLOB_H__
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "thunks.h"
OS_ENUM(os_trace_blob_flags, uint16_t,
OS_TRACE_BLOB_NEEDS_FREE = 0x0001,
OS_TRACE_BLOB_TRUNCATED = 0x0002,
);
typedef struct os_trace_blob_s {
union {
uint8_t *ob_b;
void *ob_v;
char *ob_s;
const char *ob_c;
};
uint32_t ob_len;
uint32_t ob_size;
uint32_t ob_maxsize;
uint16_t ob_flags;
bool ob_binary;
} os_trace_blob_s, *os_trace_blob_t;
#pragma mark - helpers (not to be used directly)
OS_ALWAYS_INLINE
static inline uint32_t
_os_trace_blob_available(os_trace_blob_t ob)
{
return ob->ob_size - !ob->ob_binary - ob->ob_len;
}
OS_ALWAYS_INLINE
static inline uint32_t
_os_trace_blob_growlen(os_trace_blob_t ob, size_t extra)
{
ob->ob_len += extra;
if (!ob->ob_binary) ob->ob_s[ob->ob_len] = '\0';
return (uint32_t)extra;
}
OS_ALWAYS_INLINE
static inline void
_os_trace_blob_setlen(os_trace_blob_t ob, uint32_t len)
{
ob->ob_len = len;
if (!ob->ob_binary) ob->ob_s[len] = '\0';
}
__attribute__((__visibility__("hidden")))
void
os_trace_blob_destroy_slow(os_trace_blob_t ob);
#pragma mark - initialization and simple helpers
#define os_trace_blob_init_buf(buf, binary) (os_trace_blob_s){ \
.ob_v = buf, \
.ob_binary = binary, \
.ob_size = ({ _Static_assert(sizeof(*buf) == 1, ""); countof(buf); }) \
}
OS_ALWAYS_INLINE
static inline uint32_t
os_trace_blob_max_available(os_trace_blob_t ob)
{
uint32_t used = ob->ob_len + !ob->ob_binary;
if (ob->ob_maxsize) return ob->ob_maxsize - used;
if (ob->ob_size) return ob->ob_size - used;
return 0;
}
OS_ALWAYS_INLINE
static inline size_t
os_trace_blob_is_empty(os_trace_blob_t ob)
{
return ob->ob_len == 0;
}
OS_MALLOC __attribute__((__visibility__("hidden")))
char *
os_trace_blob_detach(os_trace_blob_t ob, size_t *len);
OS_ALWAYS_INLINE
static inline void
os_trace_blob_assert_not_allocated(os_trace_blob_t ob)
{
if (os_unlikely(ob->ob_flags & OS_TRACE_BLOB_NEEDS_FREE)) {
OS_TRACE_INTERNAL_CRASH(0, "Buffer needs free");
}
}
OS_ALWAYS_INLINE
static inline void
os_trace_blob_destroy(os_trace_blob_t ob)
{
if (ob->ob_flags & OS_TRACE_BLOB_NEEDS_FREE) {
return os_trace_blob_destroy_slow(ob);
}
}
OS_ALWAYS_INLINE
static inline void
os_trace_blob_set_string(os_trace_blob_t ob, const char *s)
{
if (ob->ob_flags & OS_TRACE_BLOB_NEEDS_FREE) {
free(ob->ob_s);
}
*ob = (os_trace_blob_s){
.ob_c = s,
.ob_len = (uint32_t)strlen(s),
// not setting the size means "const"
};
}
OS_ALWAYS_INLINE
static inline void
os_trace_blob_rtrim(os_trace_blob_t ob)
{
uint32_t len = ob->ob_len;
while (len > 0 && isspace(ob->ob_s[len - 1])) len--;
_os_trace_blob_setlen(ob, len);
}
#pragma mark - appending to the blob
__attribute__((__visibility__("hidden")))
uint32_t
os_trace_blob_add_slow(os_trace_blob_t ob, const void *ptr, size_t size);
OS_ALWAYS_INLINE
static inline uint32_t
os_trace_blob_add(os_trace_blob_t ob, const void *ptr, size_t size)
{
if (os_unlikely(ob->ob_flags & OS_TRACE_BLOB_TRUNCATED)) {
return 0;
}
if (os_unlikely(size > _os_trace_blob_available(ob))) {
return os_trace_blob_add_slow(ob, ptr, size);
}
memcpy(ob->ob_s + ob->ob_len, ptr, size);
return _os_trace_blob_growlen(ob, size);
}
OS_ALWAYS_INLINE
static inline uint32_t
os_trace_blob_addc(os_trace_blob_t ob, int c)
{
uint8_t byte = (uint8_t)c;
return os_trace_blob_add(ob, &byte, 1);
}
OS_ALWAYS_INLINE
static inline uint32_t
os_trace_blob_add_safe_string(os_trace_blob_t ob, const char *s)
{
// safe means pure ascii no control chars
return os_trace_blob_add(ob, s, strlen(s));
}
#endif // !__LIBTRACE_BLOB_INTERNAL_H__