summaryrefslogtreecommitdiffstats
path: root/mojo/public/bindings/lib/buffer.h
blob: 6f0ce8866ece6576eb5e56a9883090bcdf345b00 (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
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_
#define MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_

#include <stddef.h>

#include <deque>

#include "mojo/public/system/macros.h"

namespace mojo {

// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and
// zero-initialized. Allocations remain valid for the lifetime of the Buffer.
class Buffer {
 public:
  typedef void (*Destructor)(void* address);

  Buffer();
  virtual ~Buffer();

  virtual void* Allocate(size_t num_bytes, Destructor func = NULL) = 0;

  static Buffer* current();

 private:
  Buffer* previous_;
};

namespace internal {

// The following class is designed to be allocated on the stack.  If necessary,
// it will failover to allocating objects on the heap.
class ScratchBuffer : public Buffer {
 public:
  ScratchBuffer();
  virtual ~ScratchBuffer();

  virtual void* Allocate(size_t num_bytes, Destructor func = NULL)
      MOJO_OVERRIDE;

 private:
  enum { kMinSegmentSize = 512 };

  struct Segment {
    Segment* next;
    char* cursor;
    char* end;
  };

  void* AllocateInSegment(Segment* segment, size_t num_bytes);
  void AddOverflowSegment(size_t delta);

  char fixed_data_[kMinSegmentSize];
  Segment fixed_;
  Segment* overflow_;

  struct PendingDestructor {
    Destructor func;
    void* address;
  };
  std::deque<PendingDestructor> pending_dtors_;

  MOJO_DISALLOW_COPY_AND_ASSIGN(ScratchBuffer);
};

// FixedBuffer provides a simple way to allocate objects within a fixed chunk
// of memory. Objects are allocated by calling the |Allocate| method, which
// extends the buffer accordingly. Objects allocated in this way are not freed
// explicitly. Instead, they remain valid so long as the FixedBuffer remains
// valid.  The Leak method may be used to steal the underlying memory from the
// FixedBuffer.
//
// Typical usage:
//
//   {
//     FixedBuffer buf(8 + 8);
//
//     int* a = static_cast<int*>(buf->Allocate(sizeof(int)));
//     *a = 2;
//
//     double* b = static_cast<double*>(buf->Allocate(sizeof(double)));
//     *b = 3.14f;
//
//     void* data = buf.Leak();
//     Process(data);
//
//     free(data);
//   }
//
class FixedBuffer : public Buffer {
 public:
  explicit FixedBuffer(size_t size);
  virtual ~FixedBuffer();

  // Grows the buffer by |num_bytes| and returns a pointer to the start of the
  // addition. The resulting address is 8-byte aligned, and the content of the
  // memory is zero-filled.
  virtual void* Allocate(size_t num_bytes, Destructor func = NULL)
      MOJO_OVERRIDE;

  size_t size() const { return size_; }

  // Returns the internal memory owned by the Buffer to the caller. The Buffer
  // relinquishes its pointer, effectively resetting the state of the Buffer
  // and leaving the caller responsible for freeing the returned memory address
  // when no longer needed.
  void* Leak();

 private:
  char* ptr_;
  size_t cursor_;
  size_t size_;

  MOJO_DISALLOW_COPY_AND_ASSIGN(FixedBuffer);
};

}  // namespace internal

class AllocationScope {
 public:
  AllocationScope() {}
  ~AllocationScope() {}

  Buffer* buffer() { return &buffer_; }

 private:
  internal::ScratchBuffer buffer_;

  MOJO_DISALLOW_COPY_AND_ASSIGN(AllocationScope);
};

}  // namespace mojo

#endif  // MOJO_PUBLIC_BINDINGS_LIB_BUFFER_H_