pike.git / src / buffer.h

version» Context lines:

pike.git/src/buffer.h:1: + /* + || This file is part of Pike. For copyright information see COPYRIGHT. + || Pike is distributed under GPL, LGPL and MPL. See the file COPYING + || for more information. + */    -  + #ifndef BUFFER_H + #define BUFFER_H +  + #include <stdlib.h> + #include <stddef.h> + #include <string.h> +  + #include "bitvector.h" + #include "pike_memory.h" + #include "global.h" +  + #define MACRO static inline PIKE_UNUSED_ATTRIBUTE +  + struct byte_buffer { +  void * restrict dst; +  void * end; +  size_t length; +  unsigned INT16 flags; + }; +  + static const INT16 BUFFER_GROW_EXACT = 0x1; + static const INT16 BUFFER_GROW_MEXEC = 0x2; +  + #define BUFFER_INIT() CAST_STRUCT_LITERAL(struct byte_buffer){ NULL, NULL, 0, 0 } +  + PMOD_EXPORT void buffer_free(struct byte_buffer *b); + PMOD_EXPORT int buffer_grow_nothrow(struct byte_buffer *b, size_t len); + PMOD_EXPORT void buffer_grow(struct byte_buffer *b, size_t len); + PMOD_EXPORT const char *buffer_get_string(struct byte_buffer *b); +  + PIKE_WARN_UNUSED_RESULT_ATTRIBUTE + PMOD_EXPORT void* buffer_finish(struct byte_buffer *b); +  + PIKE_WARN_UNUSED_RESULT_ATTRIBUTE + PMOD_EXPORT struct pike_string *buffer_finish_pike_string(struct byte_buffer *b); +  + PIKE_WARN_UNUSED_RESULT_ATTRIBUTE + MACRO void* buffer_ptr(const struct byte_buffer *b) { +  return (char*)b->end - b->length; + } +  + MALLOC_FUNCTION MACRO void *buffer_dst(const struct byte_buffer *b) { +  return b->dst; + } +  + MACRO void buffer_set_flags(struct byte_buffer *b, INT16 flags) { +  b->flags = flags; + } +  + MACRO void buffer_add_flags(struct byte_buffer *b, INT16 flags) { +  b->flags |= flags; + } +  + PIKE_WARN_UNUSED_RESULT_ATTRIBUTE + MACRO size_t buffer_content_length(const struct byte_buffer *b) { +  return (char*)b->dst - (char*)buffer_ptr(b); + } +  + PIKE_WARN_UNUSED_RESULT_ATTRIBUTE + MACRO size_t buffer_length(const struct byte_buffer *b) { +  return b->length; + } +  + PIKE_WARN_UNUSED_RESULT_ATTRIBUTE + MACRO size_t buffer_space(struct byte_buffer *b) { +  return (char*)b->end - (char*)b->dst; + } +  + MACRO void buffer_init(struct byte_buffer *buf) { +  struct byte_buffer b = BUFFER_INIT(); +  *buf = b; + } +  + MACRO void buffer_clear(struct byte_buffer *b) { +  b->dst = buffer_ptr(b); + } +  + #ifdef PIKE_DEBUG + PMOD_EXPORT void buffer_remove(struct byte_buffer *b, size_t len); + #else + MACRO void buffer_remove(struct byte_buffer *b, size_t len) { +  b->dst = (char*)b->dst - len; + } + #endif +  + #ifdef PIKE_DEBUG + PMOD_EXPORT void buffer_check_space(struct byte_buffer *b, size_t len); + PMOD_EXPORT void buffer_check_position(struct byte_buffer *b, size_t pos); + #else + MACRO void buffer_check_space(struct byte_buffer *PIKE_UNUSED(b), size_t PIKE_UNUSED(len)) { } + MACRO void buffer_check_position(struct byte_buffer *PIKE_UNUSED(b), size_t PIKE_UNUSED(pos)) { } + #endif +  + MACRO void buffer_advance(struct byte_buffer *b, size_t len) { +  char *dst = buffer_dst(b); +  buffer_check_space(b, len); +  b->dst = dst + len; + } +  + MACRO void buffer_init_from_mem(struct byte_buffer *b, void *ptr, size_t len, size_t pos) { +  b->dst = ptr; +  b->end = (char*)ptr + len; +  b->length = len; +  buffer_advance(b, pos); + } +  + /** +  * Ensures that the buffer has at least len bytes free space. +  * If more space is be allocated, it will be power of 2 bytes. +  * Throws an exception in out-of-memory situations. +  */ + MACRO void* buffer_ensure_space(struct byte_buffer *b, size_t len) { +  if (UNLIKELY((char*)b->dst + len > (char*)b->end)) { +  buffer_grow(b, len); +  +  STATIC_ASSUME((char*)b->dst + len <= (char*)b->end); +  } +  return buffer_dst(b); + } +  + /** +  * Same as buffer_ensure_space() but returns 0 in out-of-memory situations +  * instead of throwing an exception. +  */ + MACRO int buffer_ensure_space_nothrow(struct byte_buffer *b, size_t len) { +  if (UNLIKELY((char*)b->dst + len > (char*)b->end)) { +  if (!buffer_grow_nothrow(b, len)) return 0; +  +  STATIC_ASSUME((char*)b->dst + len <= (char*)b->end); +  } +  +  return 1; + } +  + #define ASSUME_UNCHANGED(b, CODE) do { \ +  const struct byte_buffer __B = *b; \ +  do CODE while(0); \ +  STATIC_ASSUME(__B.dst == b->dst); \ +  STATIC_ASSUME(__B.end == b->end); \ +  STATIC_ASSUME(__B.length == b->length); \ +  STATIC_ASSUME(__B.flags == b->flags); \ + } while (0) +  + MACRO void buffer_memcpy_unsafe(struct byte_buffer *b, const void * src, size_t len) { +  unsigned INT8 * restrict dst = buffer_dst(b); +  buffer_check_space(b, len); +  ASSUME_UNCHANGED(b, { +  memcpy(dst, src, len); +  }); +  b->dst = dst + len; + } + MACRO void buffer_memcpy(struct byte_buffer *b, const void * src, size_t len) { +  buffer_ensure_space(b, len); +  buffer_memcpy_unsafe(b, src, len); + } +  + MACRO void buffer_add_str_unsafe(struct byte_buffer *b, const char *str) { +  buffer_memcpy_unsafe(b, str, strlen(str)); + } +  + MACRO void buffer_add_str(struct byte_buffer *b, const char * str) { +  buffer_memcpy(b, str, strlen(str)); + } +  + MALLOC_FUNCTION + MACRO void* buffer_alloc_unsafe(struct byte_buffer *b, size_t len) { +  char * dst = buffer_dst(b); +  +  buffer_check_space(b, len); +  +  b->dst = dst + len; +  +  return dst; + } +  + MALLOC_FUNCTION + MACRO void* buffer_alloc(struct byte_buffer *b, size_t len) { +  buffer_ensure_space(b, len); +  return buffer_alloc_unsafe(b, len); + } +  + #define DO_TRANSFORM(VAR, TRANS) VAR = TRANS(VAR) + #define GEN_BUFFER_ADD(name, type, transform, transform_back) \ + MACRO void buffer_add_ ## name ## _unsafe(struct byte_buffer *b, type a) { \ +  unsigned INT8 * dst = buffer_dst(b); \ +  buffer_check_space(b, sizeof(a)); \ +  ASSUME_UNCHANGED(b, { \ +  DO_TRANSFORM(a, transform); \ +  memcpy(dst, &a, sizeof(a)); \ +  }); \ +  b->dst = dst + sizeof(a); \ + } \ + MACRO void buffer_add_ ## name (struct byte_buffer *b, type a) { \ +  buffer_ensure_space(b, sizeof(a)); \ +  buffer_add_##name##_unsafe(b, a); \ + } \ + MACRO void buffer_set_ ## name (struct byte_buffer *b, size_t pos, type a) { \ +  unsigned INT8 * dst = buffer_ptr(b); \ +  /* If the second addition overflows, the first check will fail */ \ +  buffer_check_position(b, pos); \ +  buffer_check_position(b, pos + sizeof(a)); \ +  dst += pos; \ +  ASSUME_UNCHANGED(b, { \ +  DO_TRANSFORM(a, transform); \ +  memcpy(dst, &a, sizeof(a)); \ +  }); \ + } \ + MACRO type buffer_get_ ## name (struct byte_buffer *b, size_t pos) { \ +  type a; \ +  unsigned INT8 * src = buffer_ptr(b); \ +  /* If the second addition overflows, the first check will fail */ \ +  buffer_check_position(b, pos); \ +  buffer_check_position(b, pos + sizeof(a)); \ +  src += pos; \ +  memcpy(&a, src, sizeof(a)); \ +  DO_TRANSFORM(a, transform_back); \ +  return a; \ + } +  + GEN_BUFFER_ADD(be16, unsigned INT16, hton16, ntoh16) + GEN_BUFFER_ADD(le16, unsigned INT16, ntoh16, hton16) +  + GEN_BUFFER_ADD(be32, unsigned INT32, hton32, ntoh32) + GEN_BUFFER_ADD(le32, unsigned INT32, ntoh32, hton32) +  + GEN_BUFFER_ADD(be64, UINT64, hton64, ntoh64) + GEN_BUFFER_ADD(le64, UINT64, ntoh64, hton64) +  + #undef DO_TRANSFORM + #define DO_TRANSFORM(VAR, TRANS) +  + GEN_BUFFER_ADD(u16, unsigned INT16, , ) + GEN_BUFFER_ADD(u32, unsigned INT32, , ) + GEN_BUFFER_ADD(u64, UINT64, , ) +  + GEN_BUFFER_ADD(u8, unsigned INT8, , ) + GEN_BUFFER_ADD(char, char, , ) +  + #undef DO_TRANSFORM + #undef GEN_BUFFER_ADD + #undef MACRO + #undef ASSUME_UNCHANGED +  + #define BUFFER_ADD_UNSAFE(b, a) do { \ +  struct byte_buffer *__b__ = (b); \ +  unsigned INT8 * dst = buffer_dst(__b__); \ +  buffer_check_space(__b__, sizeof(a)); \ +  ASSUME_UNCHANGED(__b__, { \ +  memcpy(dst, &a, sizeof(a)); \ +  }); \ +  __b__->dst = dst + sizeof(a); \ + } while(0) + #define BUFFER_ADD(b, a) do { \ +  buffer_ensure_space(b, sizeof(a)); \ +  BUFFER_ADD_UNSAFE(b, a); \ + } while(0) + #define BUFFER_SET(b, pos, a) do { \ +  struct byte_buffer *__b__ = (b); \ +  size_t __pos__ = (pos); \ +  unsigned INT8 * dst = buffer_ptr(__b__); \ +  buffer_check_position(__b__, __pos__); \ +  buffer_check_position(__b__, __pos__ + sizeof(a)); \ +  ASSUME_UNCHANGED(__b__, { \ +  memcpy(dst, &a, sizeof(a)); \ +  }); \ + } while(0) +  + #endif /* BUFFER_H */   Newline at end of file added.