// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef VM_DATASTREAM_H_ #define VM_DATASTREAM_H_ #include "platform/assert.h" #include "platform/utils.h" #include "vm/allocation.h" #include "vm/exceptions.h" #include "vm/globals.h" namespace dart { static const int8_t kDataBitsPerByte = 7; static const int8_t kByteMask = (1 << kDataBitsPerByte) - 1; static const int8_t kMaxUnsignedDataPerByte = kByteMask; static const int8_t kMinDataPerByte = -(1 << (kDataBitsPerByte - 1)); static const int8_t kMaxDataPerByte = (~kMinDataPerByte & kByteMask); static const uint8_t kEndByteMarker = (255 - kMaxDataPerByte); static const uint8_t kEndUnsignedByteMarker = (255 - kMaxUnsignedDataPerByte); typedef uint8_t* (*ReAlloc)(uint8_t* ptr, intptr_t old_size, intptr_t new_size); // Stream for reading various types from a buffer. class ReadStream : public ValueObject { public: ReadStream(const uint8_t* buffer, intptr_t size) : buffer_(buffer), current_(buffer), end_(buffer + size) {} void SetStream(const uint8_t* buffer, intptr_t size) { buffer_ = buffer; current_ = buffer; end_ = buffer + size; } template class Raw { }; template class Raw<1, T> { public: static T Read(ReadStream* st) { return bit_cast(st->ReadByte()); } }; template class Raw<2, T> { public: static T Read(ReadStream* st) { return bit_cast(st->Read()); } }; template class Raw<4, T> { public: static T Read(ReadStream* st) { return bit_cast(st->Read()); } }; template class Raw<8, T> { public: static T Read(ReadStream* st) { return bit_cast(st->Read()); } }; // Reads 'len' bytes from the stream. void ReadBytes(uint8_t* addr, intptr_t len) { ASSERT((end_ - current_) >= len); memmove(addr, current_, len); current_ += len; } intptr_t ReadUnsigned() { return Read(kEndUnsignedByteMarker); } intptr_t Position() const { return current_ - buffer_; } void SetPosition(intptr_t value) { ASSERT((end_ - buffer_) > value); current_ = buffer_ + value; } const uint8_t* AddressOfCurrentPosition() const { return current_; } void Advance(intptr_t value) { ASSERT((end_ - current_) > value); current_ = current_ + value; } private: template T Read() { return Read(kEndByteMarker); } template T Read(uint8_t end_byte_marker) { uint8_t b = ReadByte(); if (b > kMaxUnsignedDataPerByte) { return static_cast(b) - end_byte_marker; } T r = 0; uint8_t s = 0; do { r |= static_cast(b) << s; s += kDataBitsPerByte; b = ReadByte(); } while (b <= kMaxUnsignedDataPerByte); return r | ((static_cast(b) - end_byte_marker) << s); } uint8_t ReadByte() { ASSERT(current_ < end_); return *current_++; } private: const uint8_t* buffer_; const uint8_t* current_; const uint8_t* end_; DISALLOW_COPY_AND_ASSIGN(ReadStream); }; // Stream for writing various types into a buffer. class WriteStream : public ValueObject { public: WriteStream(uint8_t** buffer, ReAlloc alloc, intptr_t initial_size) : buffer_(buffer), end_(NULL), current_(NULL), current_size_(0), alloc_(alloc), initial_size_(initial_size) { ASSERT(buffer != NULL); ASSERT(alloc != NULL); *buffer_ = reinterpret_cast(alloc_(NULL, 0, initial_size_)); if (*buffer_ == NULL) { Exceptions::ThrowOOM(); } current_ = *buffer_; current_size_ = initial_size_; end_ = *buffer_ + initial_size_; } uint8_t* buffer() const { return *buffer_; } int bytes_written() const { return current_ - *buffer_; } void set_current(uint8_t* value) { current_ = value; } template class Raw { }; template class Raw<1, T> { public: static void Write(WriteStream* st, T value) { st->WriteByte(bit_cast(value)); } }; template class Raw<2, T> { public: static void Write(WriteStream* st, T value) { st->Write(bit_cast(value)); } }; template class Raw<4, T> { public: static void Write(WriteStream* st, T value) { st->Write(bit_cast(value)); } }; template class Raw<8, T> { public: static void Write(WriteStream* st, T value) { st->Write(bit_cast(value)); } }; void WriteUnsigned(intptr_t value) { ASSERT((value >= 0) && (value <= kIntptrMax)); while (value > kMaxUnsignedDataPerByte) { WriteByte(static_cast(value & kByteMask)); value = value >> kDataBitsPerByte; } WriteByte(static_cast(value + kEndUnsignedByteMarker)); } void WriteBytes(const uint8_t* addr, intptr_t len) { if ((end_ - current_) < len) { Resize(len); } ASSERT((end_ - current_) >= len); memmove(current_, addr, len); current_ += len; } private: template void Write(T value) { T v = value; while (v < kMinDataPerByte || v > kMaxDataPerByte) { WriteByte(static_cast(v & kByteMask)); v = v >> kDataBitsPerByte; } WriteByte(static_cast(v + kEndByteMarker)); } DART_FORCE_INLINE void WriteByte(uint8_t value) { if (current_ >= end_) { Resize(1); } ASSERT(current_ < end_); *current_++ = value; } void Resize(intptr_t size_needed) { intptr_t position = current_ - *buffer_; intptr_t increment_size = current_size_; if (size_needed > increment_size) { increment_size = Utils::RoundUp(size_needed, initial_size_); } intptr_t new_size = current_size_ + increment_size; ASSERT(new_size > current_size_); *buffer_ = reinterpret_cast(alloc_(*buffer_, current_size_, new_size)); if (*buffer_ == NULL) { Exceptions::ThrowOOM(); } current_ = *buffer_ + position; current_size_ = new_size; end_ = *buffer_ + new_size; ASSERT(end_ > *buffer_); } private: uint8_t** const buffer_; uint8_t* end_; uint8_t* current_; intptr_t current_size_; ReAlloc alloc_; intptr_t initial_size_; DISALLOW_COPY_AND_ASSIGN(WriteStream); }; } // namespace dart #endif // VM_DATASTREAM_H_