summaryrefslogtreecommitdiff
path: root/src/upb_array.h
blob: 370f6ebd48693e4dd5cdd04a5544ddb95588478f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * upb - a minimalist implementation of protocol buffers.
 *
 * Copyright (c) 2009 Joshua Haberman.  See LICENSE for details.
 *
 * Defines an in-memory, polymorphic array type.  The array does not know its
 * own type -- its owner must know that information out-of-band.
 *
 * upb_arrays are memory-managed in the sense that they contain a pointer
 * ("mem") to memory that is "owned" by the array (which may be NULL if the
 * array owns no memory).  There is a separate pointer ("elements") that points
 * to the the array's currently "effective" memory, which is either equal to
 * mem (if the array's current value is memory we own) or not (if the array is
 * referencing other memory).
 *
 * If the array is referencing other memory, it is up to the array's owner to
 * ensure that the other memory remains valid for as long as the array is
 * referencing it.
 *
 */

#ifndef UPB_ARRAY_H_
#define UPB_ARRAY_H_

#include <stdlib.h>
#include "upb.h"

#ifdef __cplusplus
extern "C" {
#endif

struct upb_string;

/* upb_arrays can be at most 2**32 elements long. */
typedef uint32_t upb_arraylen_t;

/* Represents an array (a repeated field) of any type.  The interpretation of
 * the data in the array depends on the type. */
struct upb_array {
  union upb_value_ptr elements;
  upb_arraylen_t len;     /* Number of elements in "elements". */
  upb_arraylen_t size;    /* Memory we own (0 if by reference). */
  void *gptr;
};

INLINE void upb_array_init(struct upb_array *arr)
{
  arr->elements._void = NULL;
  arr->len = 0;
  arr->size = 0;
}

INLINE void upb_array_uninit(struct upb_array *arr)
{
  if(arr->size) free(arr->elements._void);
}

INLINE struct upb_array *upb_array_new(void) {
  struct upb_array *arr = malloc(sizeof(*arr));
  upb_array_init(arr);
  return arr;
}

INLINE void upb_array_free(struct upb_array *arr) {
  upb_array_uninit(arr);
  free(arr);
}

/* Returns a pointer to an array element.  Does not perform a bounds check! */
INLINE union upb_value_ptr upb_array_getelementptr(
    struct upb_array *arr, upb_arraylen_t n, upb_field_type_t type)
{
  union upb_value_ptr ptr;
  ptr._void = (void*)((char*)arr->elements._void + n*upb_type_info[type].size);
  return ptr;
}

INLINE union upb_value upb_array_getelement(
    struct upb_array *arr, upb_arraylen_t n, upb_field_type_t type)
{
  return upb_deref(upb_array_getelementptr(arr, n, type), type);
}

INLINE uint32_t upb_round_up_to_pow2(uint32_t v)
{
  /* cf. http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
  v--;
  v |= v >> 1;
  v |= v >> 2;
  v |= v >> 4;
  v |= v >> 8;
  v |= v >> 16;
  v++;
  return v;
}

/* Resizes array to be "len" elements long and ensures we have write access
 * to the array (reallocating if necessary).  Returns true iff we were
 * referencing memory for the array and dropped the reference. */
INLINE bool upb_array_resize(struct upb_array *arr, upb_arraylen_t newlen,
                             upb_field_type_t type)
{
  size_t type_size = upb_type_info[type].size;
  bool dropped = false;
  bool ref = arr->size == 0;   /* Ref'ing external memory. */
  void *data = arr->elements._void;
  if(arr->size < newlen) {
    /* Need to resize. */
    arr->size = UPB_MAX(4, upb_round_up_to_pow2(newlen));
    arr->elements._void = realloc(ref ? NULL : data, arr->size * type_size);
  }
  if(ref) {
    /* Need to take referenced data and copy it to memory we own. */
    memcpy(arr->elements._void, data, UPB_MIN(arr->len, newlen) * type_size);
    dropped = true;
  }
  arr->len = newlen;
  return dropped;
}

/* These are all overlays on upb_array, pointers between them can be cast. */
#define UPB_DEFINE_ARRAY_TYPE(name, type) \
  struct name ## _array { \
    struct upb_fielddef *f; \
    void *gptr; \
    type *elements; \
    upb_arraylen_t len; \
    upb_arraylen_t size; \
  };

UPB_DEFINE_ARRAY_TYPE(upb_double, double)
UPB_DEFINE_ARRAY_TYPE(upb_float,  float)
UPB_DEFINE_ARRAY_TYPE(upb_int32,  int32_t)
UPB_DEFINE_ARRAY_TYPE(upb_int64,  int64_t)
UPB_DEFINE_ARRAY_TYPE(upb_uint32, uint32_t)
UPB_DEFINE_ARRAY_TYPE(upb_uint64, uint64_t)
UPB_DEFINE_ARRAY_TYPE(upb_bool,   bool)
UPB_DEFINE_ARRAY_TYPE(upb_string, struct upb_string*)
UPB_DEFINE_ARRAY_TYPE(upb_msg,    void*)

/* Defines an array of a specific message type (an overlay of upb_array). */
#define UPB_MSG_ARRAY(msg_type) struct msg_type ## _array
#define UPB_DEFINE_MSG_ARRAY(msg_type) \
  UPB_MSG_ARRAY(msg_type) { \
    msg_type **elements; \
    upb_arraylen_t len; \
    upb_arraylen_t size; \
  };

#ifdef __cplusplus
}  /* extern "C" */
#endif

#endif
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback