sinksource.h
1 // Copyright 2013, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 
5 #ifndef UTIL_SINKSOURCE_H
6 #define UTIL_SINKSOURCE_H
7 
8 #include <memory>
9 #include <string>
10 #include "base/integral_types.h"
11 #include "base/pod_array.h"
12 
13 #include "strings/stringpiece.h"
14 #include "util/status.h"
15 
16 // We prefer Sink and Source (like in snappy and icu) over ZeroCopy streams like in protobuf.
17 // The reason for this is not convenient corner cases where you have few bytes left in the buffers
18 // returned by ZeroCopy streams and you need to write a special code in order to serialize your
19 // primitives whcih require more space.
20 // Sinks solve this problem by allowing scratch buffers.
21 
22 namespace util {
23 
24 class Sink {
25  public:
26  typedef strings::MutableByteRange WritableBuffer;
27 
28  Sink() {}
29  virtual ~Sink() {}
30 
31  // Appends slice to sink.
32  virtual Status Append(const strings::ByteRange& slice) = 0;
33 
34  // Returns a writable buffer for appending .
35  // Guarantees that result.capacity >=min_capacity.
36  // May return a pointer to the caller-owned scratch buffer which must have capacity >=min_capacity.
37  // The returned buffer is only valid until the next operation on this Sink.
38  // After writing at most result.capacity bytes, call Append() with the pointer returned from this
39  // function (result.first) and the number of bytes written. Many Append() implementations will
40  // avoid copying bytes if this function returned an internal buffer (by just returning
41  // WritableBuffer object or calling its Prefix function.)
42  // Partial usage example:
43  // WritableBuffer buf = sink->GetAppendBuffer(min_capacity, scracth_buffer);
44  // ... Write n bytes into buf, with n <= buf.capacity.
45  // sink->Append(buf.Prefix(n));
46  // In many implementations, that call to Append will avoid copying bytes.
47  // If the Sink allocates or reallocates an internal buffer, it should use the desired_capacity_hint
48  // if appropriate.
49  // If a non-scratch buffer is returned, the caller may only pass its prefix to Append().
50  // That is, it is not correct to pass an interior pointer to Append().
51  // The default implementation always returns the scratch buffer.
52  virtual WritableBuffer GetAppendBuffer(
53  size_t min_capacity,
54  WritableBuffer scratch,
55  size_t desired_capacity_hint = 0);
56 
57  // Flushes internal buffers. The default implemenation does nothing. Sink
58  // subclasses may use internal buffers that require calling Flush() at the end
59  // of writing to the stream.
60  virtual Status Flush();
61 
62  private:
63  DISALLOW_COPY_AND_ASSIGN(Sink);
64 };
65 
66 
67 class ZeroCopySink : public Sink {
68  public:
69  explicit ZeroCopySink(void* dest) : dest_(reinterpret_cast<uint8*>(dest)) {}
70 
71  Status Append(const strings::ByteRange& slice) {
72  memcpy(dest_ + offset_, slice.data(), slice.size());
73  offset_ += slice.size();
74  return Status::OK;
75  }
76 
77  size_t written() const { return offset_; }
78  private:
79  size_t offset_ = 0;
80  uint8* dest_;
81 };
82 
83 class StringSink : public Sink {
84  std::string contents_;
85 public:
86  Status Append(const strings::ByteRange& slice) {
87  contents_.append(strings::charptr(slice.data()), slice.size());
88  return Status::OK;
89  }
90 
91  std::string& contents() { return contents_; }
92  const std::string& contents() const { return contents_; }
93 };
94 
95 
96 
97 // Source classes. Allow synchronous reads from an abstract source.
98 class Source {
99  public:
100  Source() {}
101  virtual ~Source() {}
102 
110  StatusObject<size_t> Read(const strings::MutableByteRange& range);
111 
112  void Prepend(const strings::ByteRange& range) {
113  prepend_buf_.insert(prepend_buf_.begin(), range.begin(), range.end());
114  }
115 
116  protected:
120  virtual StatusObject<size_t> ReadInternal(const strings::MutableByteRange& range) = 0;
121 
122  private:
123 
124  DISALLOW_COPY_AND_ASSIGN(Source);
125 
126  base::PODArray<uint8> prepend_buf_;
127  bool eof_ = false;
128 };
129 
130 class StringSource : public Source {
131 public:
132  // block_size is used to simulate paging reads, usually in tests.
133  // input must exists all the time StringSource is used. It should not be
134  // changed either since StringSource wraps its internal buffer during the construction.
135  explicit StringSource(const std::string& input, uint32 block_size = kuint32max)
136  : input_(input), block_size_(block_size) {}
137 
138  size_t Available() const {return input_.size();};
139 
140 private:
141  StatusObject<size_t> ReadInternal(const strings::MutableByteRange& range) override;
142 
143  StringPiece input_;
144  uint32 block_size_;
145 };
146 
147 
148 } // namespace util
149 
150 #endif // UTIL_SINKSOURCE_H
virtual StatusObject< size_t > ReadInternal(const strings::MutableByteRange &range)=0
StatusObject< size_t > Read(const strings::MutableByteRange &range)
Reads source into mutable range.
Definition: sinksource.cc:19