1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_
6#define MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_
7
8#include <stddef.h>
9
10#include <deque>
11
12#include "mojo/public/system/macros.h"
13
14namespace mojo {
15
16// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and
17// zero-initialized. Allocations remain valid for the lifetime of the Buffer.
18class Buffer {
19 public:
20  typedef void (*Destructor)(void* address);
21
22  Buffer();
23  virtual ~Buffer();
24
25  virtual void* Allocate(size_t num_bytes, Destructor func = NULL) = 0;
26
27  static Buffer* current();
28
29 private:
30  Buffer* previous_;
31};
32
33namespace internal {
34
35// The following class is designed to be allocated on the stack.  If necessary,
36// it will failover to allocating objects on the heap.
37class ScratchBuffer : public Buffer {
38 public:
39  ScratchBuffer();
40  virtual ~ScratchBuffer();
41
42  virtual void* Allocate(size_t num_bytes, Destructor func = NULL)
43      MOJO_OVERRIDE;
44
45 private:
46  enum { kMinSegmentSize = 512 };
47
48  struct Segment {
49    Segment* next;
50    char* cursor;
51    char* end;
52  };
53
54  void* AllocateInSegment(Segment* segment, size_t num_bytes);
55  void AddOverflowSegment(size_t delta);
56
57  char fixed_data_[kMinSegmentSize];
58  Segment fixed_;
59  Segment* overflow_;
60
61  struct PendingDestructor {
62    Destructor func;
63    void* address;
64  };
65  std::deque<PendingDestructor> pending_dtors_;
66
67  MOJO_DISALLOW_COPY_AND_ASSIGN(ScratchBuffer);
68};
69
70// FixedBuffer provides a simple way to allocate objects within a fixed chunk
71// of memory. Objects are allocated by calling the |Allocate| method, which
72// extends the buffer accordingly. Objects allocated in this way are not freed
73// explicitly. Instead, they remain valid so long as the FixedBuffer remains
74// valid.  The Leak method may be used to steal the underlying memory from the
75// FixedBuffer.
76//
77// Typical usage:
78//
79//   {
80//     FixedBuffer buf(8 + 8);
81//
82//     int* a = static_cast<int*>(buf->Allocate(sizeof(int)));
83//     *a = 2;
84//
85//     double* b = static_cast<double*>(buf->Allocate(sizeof(double)));
86//     *b = 3.14f;
87//
88//     void* data = buf.Leak();
89//     Process(data);
90//
91//     free(data);
92//   }
93//
94class FixedBuffer : public Buffer {
95 public:
96  explicit FixedBuffer(size_t size);
97  virtual ~FixedBuffer();
98
99  // Grows the buffer by |num_bytes| and returns a pointer to the start of the
100  // addition. The resulting address is 8-byte aligned, and the content of the
101  // memory is zero-filled.
102  virtual void* Allocate(size_t num_bytes, Destructor func = NULL)
103      MOJO_OVERRIDE;
104
105  size_t size() const { return size_; }
106
107  // Returns the internal memory owned by the Buffer to the caller. The Buffer
108  // relinquishes its pointer, effectively resetting the state of the Buffer
109  // and leaving the caller responsible for freeing the returned memory address
110  // when no longer needed.
111  void* Leak();
112
113 private:
114  char* ptr_;
115  size_t cursor_;
116  size_t size_;
117
118  MOJO_DISALLOW_COPY_AND_ASSIGN(FixedBuffer);
119};
120
121}  // namespace internal
122
123class AllocationScope {
124 public:
125  AllocationScope() {}
126  ~AllocationScope() {}
127
128  Buffer* buffer() { return &buffer_; }
129
130 private:
131  internal::ScratchBuffer buffer_;
132
133  MOJO_DISALLOW_COPY_AND_ASSIGN(AllocationScope);
134};
135
136}  // namespace mojo
137
138#endif  // MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_
139