• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 // Author: kenton@google.com (Kenton Varda)
9 //  Based on original Protocol Buffers design by
10 //  Sanjay Ghemawat, Jeff Dean, and others.
11 //
12 // This file contains the ZeroCopyInputStream and ZeroCopyOutputStream
13 // interfaces, which represent abstract I/O streams to and from which
14 // protocol buffers can be read and written.  For a few simple
15 // implementations of these interfaces, see zero_copy_stream_impl.h.
16 //
17 // These interfaces are different from classic I/O streams in that they
18 // try to minimize the amount of data copying that needs to be done.
19 // To accomplish this, responsibility for allocating buffers is moved to
20 // the stream object, rather than being the responsibility of the caller.
21 // So, the stream can return a buffer which actually points directly into
22 // the final data structure where the bytes are to be stored, and the caller
23 // can interact directly with that buffer, eliminating an intermediate copy
24 // operation.
25 //
26 // As an example, consider the common case in which you are reading bytes
27 // from an array that is already in memory (or perhaps an mmap()ed file).
28 // With classic I/O streams, you would do something like:
29 //   char buffer[BUFFER_SIZE];
30 //   input->Read(buffer, BUFFER_SIZE);
31 //   DoSomething(buffer, BUFFER_SIZE);
32 // Then, the stream basically just calls memcpy() to copy the data from
33 // the array into your buffer.  With a ZeroCopyInputStream, you would do
34 // this instead:
35 //   const void* buffer;
36 //   int size;
37 //   input->Next(&buffer, &size);
38 //   DoSomething(buffer, size);
39 // Here, no copy is performed.  The input stream returns a pointer directly
40 // into the backing array, and the caller ends up reading directly from it.
41 //
42 // If you want to be able to read the old-fashion way, you can create
43 // a CodedInputStream or CodedOutputStream wrapping these objects and use
44 // their ReadRaw()/WriteRaw() methods.  These will, of course, add a copy
45 // step, but Coded*Stream will handle buffering so at least it will be
46 // reasonably efficient.
47 //
48 // ZeroCopyInputStream example:
49 //   // Read in a file and print its contents to stdout.
50 //   int fd = open("myfile", O_RDONLY);
51 //   ZeroCopyInputStream* input = new FileInputStream(fd);
52 //
53 //   const void* buffer;
54 //   int size;
55 //   while (input->Next(&buffer, &size)) {
56 //     cout.write(buffer, size);
57 //   }
58 //
59 //   delete input;
60 //   close(fd);
61 //
62 // ZeroCopyOutputStream example:
63 //   // Copy the contents of "infile" to "outfile", using plain read() for
64 //   // "infile" but a ZeroCopyOutputStream for "outfile".
65 //   int infd = open("infile", O_RDONLY);
66 //   int outfd = open("outfile", O_WRONLY);
67 //   ZeroCopyOutputStream* output = new FileOutputStream(outfd);
68 //
69 //   void* buffer;
70 //   int size;
71 //   while (output->Next(&buffer, &size)) {
72 //     int bytes = read(infd, buffer, size);
73 //     if (bytes < size) {
74 //       // Reached EOF.
75 //       output->BackUp(size - bytes);
76 //       break;
77 //     }
78 //   }
79 //
80 //   delete output;
81 //   close(infd);
82 //   close(outfd);
83 
84 #ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
85 #define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
86 
87 #include "google/protobuf/stubs/common.h"
88 #include "absl/strings/cord.h"
89 #include "google/protobuf/port.h"
90 
91 
92 // Must be included last.
93 #include "google/protobuf/port_def.inc"
94 
95 namespace google {
96 namespace protobuf {
97 namespace io {
98 
99 // Abstract interface similar to an input stream but designed to minimize
100 // copying.
101 class PROTOBUF_EXPORT ZeroCopyInputStream {
102  public:
103   ZeroCopyInputStream() = default;
104   virtual ~ZeroCopyInputStream() = default;
105 
106   ZeroCopyInputStream(const ZeroCopyInputStream&) = delete;
107   ZeroCopyInputStream& operator=(const ZeroCopyInputStream&) = delete;
108   ZeroCopyInputStream(ZeroCopyInputStream&&) = delete;
109   ZeroCopyInputStream& operator=(ZeroCopyInputStream&&) = delete;
110 
111   // Obtains a chunk of data from the stream.
112   //
113   // Preconditions:
114   // * "size" and "data" are not NULL.
115   //
116   // Postconditions:
117   // * If the returned value is false, there is no more data to return or
118   //   an error occurred.  All errors are permanent.
119   // * Otherwise, "size" points to the actual number of bytes read and "data"
120   //   points to a pointer to a buffer containing these bytes.
121   // * Ownership of this buffer remains with the stream, and the buffer
122   //   remains valid only until some other method of the stream is called
123   //   or the stream is destroyed.
124   // * It is legal for the returned buffer to have zero size, as long
125   //   as repeatedly calling Next() eventually yields a buffer with non-zero
126   //   size.
127   virtual bool Next(const void** data, int* size) = 0;
128 
129   // Backs up a number of bytes, so that the next call to Next() returns
130   // data again that was already returned by the last call to Next().  This
131   // is useful when writing procedures that are only supposed to read up
132   // to a certain point in the input, then return.  If Next() returns a
133   // buffer that goes beyond what you wanted to read, you can use BackUp()
134   // to return to the point where you intended to finish.
135   //
136   // Preconditions:
137   // * The last method called must have been Next().
138   // * count must be less than or equal to the size of the last buffer
139   //   returned by Next().
140   //
141   // Postconditions:
142   // * The last "count" bytes of the last buffer returned by Next() will be
143   //   pushed back into the stream.  Subsequent calls to Next() will return
144   //   the same data again before producing new data.
145   virtual void BackUp(int count) = 0;
146 
147   // Skips `count` number of bytes.
148   // Returns true on success, or false if some input error occurred, or `count`
149   // exceeds the end of the stream. This function may skip up to `count - 1`
150   // bytes in case of failure.
151   //
152   // Preconditions:
153   // * `count` is non-negative.
154   //
155   virtual bool Skip(int count) = 0;
156 
157   // Returns the total number of bytes read since this object was created.
158   virtual int64_t ByteCount() const = 0;
159 
160   // Read the next `count` bytes and append it to the given Cord.
161   //
162   // In the case of a read error, the method reads as much data as possible into
163   // the cord before returning false. The default implementation iterates over
164   // the buffers and appends up to `count` bytes of data into `cord` using the
165   // `absl::CordBuffer` API.
166   //
167   // Some streams may implement this in a way that avoids copying by sharing or
168   // reference counting existing data managed by the stream implementation.
169   //
170   virtual bool ReadCord(absl::Cord* cord, int count);
171 
172 };
173 
174 // Abstract interface similar to an output stream but designed to minimize
175 // copying.
176 class PROTOBUF_EXPORT ZeroCopyOutputStream {
177  public:
ZeroCopyOutputStream()178   ZeroCopyOutputStream() {}
179   ZeroCopyOutputStream(const ZeroCopyOutputStream&) = delete;
180   ZeroCopyOutputStream& operator=(const ZeroCopyOutputStream&) = delete;
~ZeroCopyOutputStream()181   virtual ~ZeroCopyOutputStream() {}
182 
183   // Obtains a buffer into which data can be written.  Any data written
184   // into this buffer will eventually (maybe instantly, maybe later on)
185   // be written to the output.
186   //
187   // Preconditions:
188   // * "size" and "data" are not NULL.
189   //
190   // Postconditions:
191   // * If the returned value is false, an error occurred.  All errors are
192   //   permanent.
193   // * Otherwise, "size" points to the actual number of bytes in the buffer
194   //   and "data" points to the buffer.
195   // * Ownership of this buffer remains with the stream, and the buffer
196   //   remains valid only until some other method of the stream is called
197   //   or the stream is destroyed.
198   // * Any data which the caller stores in this buffer will eventually be
199   //   written to the output (unless BackUp() is called).
200   // * It is legal for the returned buffer to have zero size, as long
201   //   as repeatedly calling Next() eventually yields a buffer with non-zero
202   //   size.
203   virtual bool Next(void** data, int* size) = 0;
204 
205   // Backs up a number of bytes, so that the end of the last buffer returned
206   // by Next() is not actually written.  This is needed when you finish
207   // writing all the data you want to write, but the last buffer was bigger
208   // than you needed.  You don't want to write a bunch of garbage after the
209   // end of your data, so you use BackUp() to back up.
210   //
211   // This method can be called with `count = 0` to finalize (flush) any
212   // previously returned buffer. For example, a file output stream can
213   // flush buffers returned from a previous call to Next() upon such
214   // BackUp(0) invocations. ZeroCopyOutputStream callers should always
215   // invoke BackUp() after a final Next() call, even if there is no
216   // excess buffer data to be backed up to indicate a flush point.
217   //
218   // Preconditions:
219   // * The last method called must have been Next().
220   // * count must be less than or equal to the size of the last buffer
221   //   returned by Next().
222   // * The caller must not have written anything to the last "count" bytes
223   //   of that buffer.
224   //
225   // Postconditions:
226   // * The last "count" bytes of the last buffer returned by Next() will be
227   //   ignored.
228   virtual void BackUp(int count) = 0;
229 
230   // Returns the total number of bytes written since this object was created.
231   virtual int64_t ByteCount() const = 0;
232 
233   // Write a given chunk of data to the output.  Some output streams may
234   // implement this in a way that avoids copying. Check AllowsAliasing() before
235   // calling WriteAliasedRaw(). It will ABSL_CHECK fail if WriteAliasedRaw() is
236   // called on a stream that does not allow aliasing.
237   //
238   // NOTE: It is caller's responsibility to ensure that the chunk of memory
239   // remains live until all of the data has been consumed from the stream.
240   virtual bool WriteAliasedRaw(const void* data, int size);
AllowsAliasing()241   virtual bool AllowsAliasing() const { return false; }
242 
243   // Writes the given Cord to the output.
244   //
245   // The default implementation iterates over all Cord chunks copying all cord
246   // data into the buffer(s) returned by the stream's `Next()` method.
247   //
248   // Some streams may implement this in a way that avoids copying the cord
249   // data by copying and managing a copy of the provided cord instead.
250   virtual bool WriteCord(const absl::Cord& cord);
251 
252 };
253 
254 }  // namespace io
255 }  // namespace protobuf
256 }  // namespace google
257 
258 #include "google/protobuf/port_undef.inc"
259 
260 #endif  // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
261