summaryrefslogtreecommitdiff
path: root/upb/env.h
blob: 500b0acdfc21abf3ca02a67da5fd7b240921b025 (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
 * upb - a minimalist implementation of protocol buffers.
 *
 * Copyright (c) 2014 Google Inc.  See LICENSE for details.
 * Author: Josh Haberman <jhaberman@gmail.com>
 *
 * A upb::Environment provides a means for injecting malloc and an
 * error-reporting callback into encoders/decoders.  This allows them to be
 * independent of nearly all assumptions about their actual environment.
 *
 * It is also a container for allocating the encoders/decoders themselves that
 * insulates clients from knowing their actual size.  This provides ABI
 * compatibility even if the size of the objects change.  And this allows the
 * structure definitions to be in the .c files instead of the .h files, making
 * the .h files smaller and more readable.
 */

#include "upb/upb.h"

#ifndef UPB_ENV_H_
#define UPB_ENV_H_

#ifdef __cplusplus
namespace upb {
class Environment;
class SeededAllocator;
}
#endif

UPB_DECLARE_TYPE(upb::Environment, upb_env);
UPB_DECLARE_TYPE(upb::SeededAllocator, upb_seededalloc);

typedef void *upb_alloc_func(void *ud, void *ptr, size_t oldsize, size_t size);
typedef void upb_cleanup_func(void *ud);
typedef bool upb_error_func(void *ud, const upb_status *status);

// An environment is *not* thread-safe.
UPB_DEFINE_CLASS0(upb::Environment,
 public:
  Environment();
  ~Environment();

  // Set a custom memory allocation function for the environment.  May ONLY
  // be called before any calls to Malloc()/Realloc()/AddCleanup() below.
  // If this is not called, the system realloc() function will be used.
  // The given user pointer "ud" will be passed to the allocation function.
  //
  // The allocation function will not receive corresponding "free" calls.  it
  // must ensure that the memory is valid for the lifetime of the Environment,
  // but it may be reclaimed any time thereafter.  The likely usage is that
  // "ud" points to a stateful allocator, and that the allocator frees all
  // memory, arena-style, when it is destroyed.  In this case the allocator must
  // outlive the Environment.  Another possibility is that the allocation
  // function returns GC-able memory that is guaranteed to be GC-rooted for the
  // life of the Environment.
  void SetAllocationFunction(upb_alloc_func* alloc, void* ud);

  template<class T>
  void SetAllocator(T* allocator) {
    SetAllocationFunction(allocator->GetAllocationFunction(), allocator);
  }

  // Set a custom error reporting function.
  void SetErrorFunction(upb_error_func* func, void* ud);

  // Set the error reporting function to simply copy the status to the given
  // status and abort.
  void ReportErrorsTo(Status* status);

  // Returns true if all allocations and AddCleanup() calls have succeeded,
  // and no errors were reported with ReportError() (except ones that recovered
  // successfully).
  bool ok() const;

  //////////////////////////////////////////////////////////////////////////////
  // Functions for use by encoders/decoders.

  // Reports an error to this environment's callback, returning true if
  // the caller should try to recover.
  bool ReportError(const Status* status);

  // Allocate memory.  Uses the environment's allocation function.
  //
  // There is no need to free(). All memory will be freed automatically, but is
  // guaranteed to outlive the Environment.
  void* Malloc(size_t size);

  // Reallocate memory.  Preserves "oldsize" bytes from the existing buffer
  // Requires: oldsize <= existing_size.
  //
  // TODO(haberman): should we also enforce that oldsize <= size?
  void* Realloc(void* ptr, size_t oldsize, size_t size);

  // Add a cleanup function to run when the environment is destroyed.
  // Returns false on out-of-memory.
  //
  // The first call to AddCleanup() after SetAllocationFunction() is guaranteed
  // to return true -- this makes it possible to robustly set a cleanup handler
  // for a custom allocation function.
  bool AddCleanup(upb_cleanup_func* func, void* ud);

  // Total number of bytes that have been allocated.  It is undefined what
  // Realloc() does to this counter.
  size_t BytesAllocated() const;

 private:
  UPB_DISALLOW_COPY_AND_ASSIGN(Environment);
,
UPB_DEFINE_STRUCT0(upb_env,
  bool ok_;
  size_t bytes_allocated;

  // Alloc function.
  upb_alloc_func *alloc;
  void *alloc_ud;

  // Error-reporting function.
  upb_error_func *err;
  void *err_ud;

  // Userdata for default alloc func.
  void *default_alloc_ud;

  // Cleanup entries.  Pointer to a cleanup_ent, defined in env.c
  void *cleanup_head;

  // For future expansion, since the size of this struct is exposed to users.
  void *future1;
  void *future2;
));

UPB_BEGIN_EXTERN_C

void upb_env_init(upb_env *e);
void upb_env_uninit(upb_env *e);
void upb_env_setallocfunc(upb_env *e, upb_alloc_func *func, void *ud);
void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud);
void upb_env_reporterrorsto(upb_env *e, upb_status *status);
bool upb_env_ok(const upb_env *e);
bool upb_env_reporterror(upb_env *e, const upb_status *status);
void *upb_env_malloc(upb_env *e, size_t size);
void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size);
bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud);
size_t upb_env_bytesallocated(const upb_env *e);

UPB_END_EXTERN_C

// An allocator that allocates from an initial memory region (likely the stack)
// before falling back to another allocator.
UPB_DEFINE_CLASS0(upb::SeededAllocator,
 public:
  SeededAllocator(void *mem, size_t len);
  ~SeededAllocator();

  // Set a custom fallback memory allocation function for the allocator, to use
  // once the initial region runs out.
  //
  // May ONLY be called before GetAllocationFunction().  If this is not
  // called, the system realloc() will be the fallback allocator.
  void SetFallbackAllocator(upb_alloc_func *alloc, void *ud);

  // Gets the allocation function for this allocator.
  upb_alloc_func* GetAllocationFunction();

 private:
  UPB_DISALLOW_COPY_AND_ASSIGN(SeededAllocator);
,
UPB_DEFINE_STRUCT0(upb_seededalloc,
  // Fallback alloc function.
  upb_alloc_func *alloc;
  upb_cleanup_func *alloc_cleanup;
  void *alloc_ud;
  bool need_cleanup;
  bool returned_allocfunc;

  // Userdata for default alloc func.
  void *default_alloc_ud;

  // Pointers for the initial memory region.
  void *mem_base;
  void *mem_ptr;
  void *mem_limit;

  // For future expansion, since the size of this struct is exposed to users.
  void *future1;
  void *future2;
));

UPB_BEGIN_EXTERN_C

void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len);
void upb_seededalloc_uninit(upb_seededalloc *a);
void upb_seededalloc_setfallbackalloc(upb_seededalloc *a, upb_alloc_func *func,
                                      void *ud);
upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a);

UPB_END_EXTERN_C

#ifdef __cplusplus

namespace upb {

inline Environment::Environment() {
  upb_env_init(this);
}
inline Environment::~Environment() {
  upb_env_uninit(this);
}
inline void Environment::SetAllocationFunction(upb_alloc_func *alloc,
                                               void *ud) {
  upb_env_setallocfunc(this, alloc, ud);
}
inline void Environment::SetErrorFunction(upb_error_func *func, void *ud) {
  upb_env_seterrorfunc(this, func, ud);
}
inline void Environment::ReportErrorsTo(Status* status) {
  upb_env_reporterrorsto(this, status);
}
inline bool Environment::ok() const {
  return upb_env_ok(this);
}
inline bool Environment::ReportError(const Status* status) {
  return upb_env_reporterror(this, status);
}
inline void *Environment::Malloc(size_t size) {
  return upb_env_malloc(this, size);
}
inline void *Environment::Realloc(void *ptr, size_t oldsize, size_t size) {
  return upb_env_realloc(this, ptr, oldsize, size);
}
inline bool Environment::AddCleanup(upb_cleanup_func *func, void *ud) {
  return upb_env_addcleanup(this, func, ud);
}
inline size_t Environment::BytesAllocated() const {
  return upb_env_bytesallocated(this);
}

inline SeededAllocator::SeededAllocator(void *mem, size_t len) {
  upb_seededalloc_init(this, mem, len);
}
inline SeededAllocator::~SeededAllocator() {
  upb_seededalloc_uninit(this);
}
inline void SeededAllocator::SetFallbackAllocator(upb_alloc_func *alloc,
                                                  void *ud) {
  upb_seededalloc_setfallbackalloc(this, alloc, ud);
}
inline upb_alloc_func *SeededAllocator::GetAllocationFunction() {
  return upb_seededalloc_getallocfunc(this);
}

}  // namespace upb

#endif  // __cplusplus

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