blob: 0b7f6e46be6592c15771bcd1f9a7e7be28e8a79d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_UTIL_ENCODED_BUFFER_H
#define ANDROID_UTIL_ENCODED_BUFFER_H
#include <stdint.h>
#include <vector>
namespace android {
namespace util {
/**
* A stream of bytes containing a read pointer and a write pointer,
* backed by a set of fixed-size buffers. There are write functions for the
* primitive types stored by protocol buffers, but none of the logic
* for tags, inner objects, or any of that.
*
* Terminology:
* *Pos: Position in the whole data set (as if it were a single buffer).
* *Index: Index of a buffer within the mBuffers list.
* *Offset: Position within a buffer.
*/
class EncodedBuffer
{
public:
EncodedBuffer();
explicit EncodedBuffer(size_t chunkSize);
~EncodedBuffer();
class Pointer {
public:
Pointer();
explicit Pointer(size_t chunkSize);
size_t pos() const;
size_t index() const;
size_t offset() const;
Pointer* move(size_t amt);
inline Pointer* move() { return move(1); };
Pointer* rewind();
Pointer copy() const;
private:
size_t mChunkSize;
size_t mIndex;
size_t mOffset;
};
/**
* Clears the buffer by rewinding its write pointer to avoid de/allocate buffers in heap.
*/
void clear();
/******************************** Write APIs ************************************************/
/**
* Returns the number of bytes written in the buffer
*/
size_t size() const;
/**
* Returns the write pointer.
*/
Pointer* wp();
/**
* Returns the current position of write pointer, if the write buffer is full, it will automatically
* rotate to a new buffer with given chunkSize. If NULL is returned, it means NO_MEMORY
*/
uint8_t* writeBuffer();
/**
* Returns the writeable size in the current write buffer .
*/
size_t currentToWrite();
/**
* Write a single byte to the buffer.
*/
void writeRawByte(uint8_t val);
/**
* Write a varint32 into the buffer. Return the size of the varint.
*/
size_t writeRawVarint32(uint32_t val);
/**
* Write a varint64 into the buffer. Return the size of the varint.
*/
size_t writeRawVarint64(uint64_t val);
/**
* Write Fixed32 into the buffer.
*/
void writeRawFixed32(uint32_t val);
/**
* Write Fixed64 into the buffer.
*/
void writeRawFixed64(uint64_t val);
/**
* Write a protobuf header. Return the size of the header.
*/
size_t writeHeader(uint32_t fieldId, uint8_t wireType);
/********************************* Edit APIs ************************************************/
/**
* Returns the edit pointer.
*/
Pointer* ep();
/**
* Read a single byte at ep, and move ep to next byte;
*/
uint8_t readRawByte();
/**
* Read varint starting at ep, ep will move to pos of next byte.
*/
uint64_t readRawVarint();
/**
* Read 4 bytes starting at ep, ep will move to pos of next byte.
*/
uint32_t readRawFixed32();
/**
* Read 8 bytes starting at ep, ep will move to pos of next byte.
*/
uint64_t readRawFixed64();
/**
* Edit 4 bytes starting at pos.
*/
void editRawFixed32(size_t pos, uint32_t val);
/**
* Copy _size_ bytes of data starting at __srcPos__ to wp, srcPos must be larger than wp.pos().
*/
void copy(size_t srcPos, size_t size);
/********************************* Read APIs ************************************************/
class iterator;
friend class iterator;
class iterator {
public:
explicit iterator(const EncodedBuffer& buffer);
/**
* Returns the number of bytes written in the buffer
*/
size_t size() const;
/**
* Returns the size of total bytes read.
*/
size_t bytesRead() const;
/**
* Returns the read pointer.
*/
Pointer* rp();
/**
* Returns the current position of read pointer, if NULL is returned, it reaches end of buffer.
*/
uint8_t const* readBuffer();
/**
* Returns the readable size in the current read buffer.
*/
size_t currentToRead();
/**
* Returns true if next bytes is available for read.
*/
bool hasNext();
/**
* Reads the current byte and moves pointer 1 bit.
*/
uint8_t next();
/**
* Read varint from iterator, the iterator will point to next available byte.
*/
uint64_t readRawVarint();
private:
const EncodedBuffer& mData;
Pointer mRp;
};
/**
* Returns the iterator of EncodedBuffer so it guarantees consumers won't be able to modified the buffer.
*/
iterator begin() const;
private:
size_t mChunkSize;
std::vector<uint8_t*> mBuffers;
Pointer mWp;
Pointer mEp;
inline uint8_t* at(const Pointer& p) const; // helper function to get value
};
} // util
} // android
#endif // ANDROID_UTIL_ENCODED_BUFFER_H