diff options
author | primiano@chromium.org <primiano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-25 09:47:12 +0000 |
---|---|---|
committer | primiano@chromium.org <primiano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-25 09:47:12 +0000 |
commit | 31b7610edd7f86ada422938430dc5feed12cfd0c (patch) | |
tree | 512ee8f209ff6050e0fd0e651dfb4e8d00a86b9b /content/browser | |
parent | 9da2de182cb7d5efb97d9aef1f9003245c72cf83 (diff) | |
download | chromium_src-31b7610edd7f86ada422938430dc5feed12cfd0c.zip chromium_src-31b7610edd7f86ada422938430dc5feed12cfd0c.tar.gz chromium_src-31b7610edd7f86ada422938430dc5feed12cfd0c.tar.bz2 |
Introduced ChunkedByteBuffer class which will be required by next speech recognition CLs (2.x).
BUG=116954
TEST=content_unittest (ChunkedByteBufferTest.BasicTest)
Review URL: http://codereview.chromium.org/10123008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133885 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
-rw-r--r-- | content/browser/speech/chunked_byte_buffer.cc | 131 | ||||
-rw-r--r-- | content/browser/speech/chunked_byte_buffer.h | 76 | ||||
-rw-r--r-- | content/browser/speech/chunked_byte_buffer_unittest.cc | 76 |
3 files changed, 283 insertions, 0 deletions
diff --git a/content/browser/speech/chunked_byte_buffer.cc b/content/browser/speech/chunked_byte_buffer.cc new file mode 100644 index 0000000..123755a --- /dev/null +++ b/content/browser/speech/chunked_byte_buffer.cc @@ -0,0 +1,131 @@ +// Copyright (c) 2012 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. + +#include "content/browser/speech/chunked_byte_buffer.h" + +#include <algorithm> + +#include "base/basictypes.h" +#include "base/lazy_instance.h" +#include "base/logging.h" + +namespace { + +static const size_t kHeaderLength = sizeof(uint32); + +COMPILE_ASSERT(sizeof(size_t) >= kHeaderLength, + ChunkedByteBufferNotSupportedOnThisArchitecture); + +uint32 ReadBigEndian32(const uint8* buffer) { + return (static_cast<uint32>(buffer[3])) | + (static_cast<uint32>(buffer[2]) << 8) | + (static_cast<uint32>(buffer[1]) << 16) | + (static_cast<uint32>(buffer[0]) << 24); +} + +} // namespace + +namespace speech { + +ChunkedByteBuffer::ChunkedByteBuffer() + : partial_chunk_(new Chunk()), + total_bytes_stored_(0) { +} + +ChunkedByteBuffer::~ChunkedByteBuffer() { + Clear(); +} + +void ChunkedByteBuffer::Append(const uint8* start, size_t length) { + DCHECK(length > 0); + size_t remaining_bytes = length; + const uint8* next_data = start; + + while (remaining_bytes > 0) { + DCHECK(partial_chunk_ != NULL); + size_t insert_length = 0; + bool header_completed = false; + bool content_completed = false; + std::vector<uint8>* insert_target; + + if (partial_chunk_->header.size() < kHeaderLength) { + const size_t bytes_to_complete_header = + kHeaderLength - partial_chunk_->header.size(); + insert_length = std::min(bytes_to_complete_header, remaining_bytes); + insert_target = &partial_chunk_->header; + header_completed = (remaining_bytes >= bytes_to_complete_header); + } else { + DCHECK_LT(partial_chunk_->content->size(), + partial_chunk_->ExpectedContentLength()); + const size_t bytes_to_complete_chunk = + partial_chunk_->ExpectedContentLength() - + partial_chunk_->content->size(); + insert_length = std::min(bytes_to_complete_chunk, remaining_bytes); + insert_target = partial_chunk_->content.get(); + content_completed = (remaining_bytes >= bytes_to_complete_chunk); + } + + DCHECK_GT(insert_length, 0U); + DCHECK_LE(insert_length, remaining_bytes); + DCHECK_LE(next_data + insert_length, start + length); + insert_target->insert(insert_target->end(), + next_data, + next_data + insert_length); + next_data += insert_length; + remaining_bytes -= insert_length; + + if (header_completed) { + DCHECK_EQ(partial_chunk_->header.size(), kHeaderLength); + DCHECK_NE(partial_chunk_->ExpectedContentLength(), 0U); + partial_chunk_->content->reserve(partial_chunk_->ExpectedContentLength()); + } else if (content_completed) { + DCHECK_EQ(partial_chunk_->content->size(), + partial_chunk_->ExpectedContentLength()); + chunks_.push_back(partial_chunk_.release()); + partial_chunk_.reset(new Chunk()); + } + } + DCHECK_EQ(next_data, start + length); + total_bytes_stored_ += length; +} + +void ChunkedByteBuffer::Append(const std::string& string) { + Append(reinterpret_cast<const uint8*>(string.data()), string.size()); +} + +bool ChunkedByteBuffer::HasChunks() const { + return !chunks_.empty(); +} + +scoped_ptr< std::vector<uint8> > ChunkedByteBuffer::PopChunk() { + if (chunks_.empty()) + return scoped_ptr< std::vector<uint8> >(); + scoped_ptr<Chunk> chunk(*chunks_.begin()); + chunks_.weak_erase(chunks_.begin()); + DCHECK_EQ(chunk->header.size(), kHeaderLength); + DCHECK_EQ(chunk->content->size(), chunk->ExpectedContentLength()); + total_bytes_stored_ -= chunk->content->size(); + total_bytes_stored_ -= kHeaderLength; + return chunk->content.Pass(); +} + +void ChunkedByteBuffer::Clear() { + chunks_.reset(); + partial_chunk_.reset(new Chunk()); + total_bytes_stored_ = 0; +} + +ChunkedByteBuffer::Chunk::Chunk() + : content(new std::vector<uint8>()) { +} + +ChunkedByteBuffer::Chunk::~Chunk() { +} + +size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const { + DCHECK_EQ(header.size(), kHeaderLength); + return static_cast<size_t>(ReadBigEndian32(&header[0])); +} + +} // namespace speech diff --git a/content/browser/speech/chunked_byte_buffer.h b/content/browser/speech/chunked_byte_buffer.h new file mode 100644 index 0000000..71ccc06 --- /dev/null +++ b/content/browser/speech/chunked_byte_buffer.h @@ -0,0 +1,76 @@ +// Copyright (c) 2012 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 CONTENT_BROWSER_SPEECH_CHUNKED_BYTE_BUFFER_H_ +#define CONTENT_BROWSER_SPEECH_CHUNKED_BYTE_BUFFER_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "content/common/content_export.h" + +namespace speech { + +// Models a chunk-oriented byte buffer. The term chunk is herein defined as an +// arbitrary sequence of bytes that is preceeded by N header bytes, indicating +// its size. Data may be appended to the buffer with no particular respect of +// chunks boundaries. However, chunks can be extracted (FIFO) only when their +// content (according to their header) is fully available in the buffer. +// The current implementation support only 4 byte Big Endian headers. +// Empty chunks (i.e. the sequence 00 00 00 00) are NOT allowed. +// +// E.g. 00 00 00 04 xx xx xx xx 00 00 00 02 yy yy 00 00 00 04 zz zz zz zz +// [----- CHUNK 1 -------] [--- CHUNK 2 ---] [------ CHUNK 3 ------] +class CONTENT_EXPORT ChunkedByteBuffer { + public: + ChunkedByteBuffer(); + ~ChunkedByteBuffer(); + + // Appends |length| bytes starting from |start| to the buffer. + void Append(const uint8* start, size_t length); + + // Appends bytes contained in the |string| to the buffer. + void Append(const std::string& string); + + // Checks whether one or more complete chunks are available in the buffer. + bool HasChunks() const; + + // If enough data is available, reads and removes the first complete chunk + // from the buffer. Returns a NULL pointer if no complete chunk is available. + scoped_ptr< std::vector<uint8> > PopChunk(); + + // Clears all the content of the buffer. + void Clear(); + + // Returns the number of raw bytes (including headers) present. + size_t GetTotalLength() const { return total_bytes_stored_; } + + private: + struct Chunk { + Chunk(); + ~Chunk(); + + std::vector<uint8> header; + scoped_ptr< std::vector<uint8> > content; + size_t ExpectedContentLength() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Chunk); + }; + + ScopedVector<Chunk> chunks_; + scoped_ptr<Chunk> partial_chunk_; + size_t total_bytes_stored_; + + DISALLOW_COPY_AND_ASSIGN(ChunkedByteBuffer); +}; + + +} // namespace speech + +#endif // CONTENT_BROWSER_SPEECH_CHUNKED_BYTE_BUFFER_H_ diff --git a/content/browser/speech/chunked_byte_buffer_unittest.cc b/content/browser/speech/chunked_byte_buffer_unittest.cc new file mode 100644 index 0000000..1633101 --- /dev/null +++ b/content/browser/speech/chunked_byte_buffer_unittest.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2012 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. + +#include <string> +#include <vector> + +#include "content/browser/speech/chunked_byte_buffer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace speech { + +typedef std::vector<uint8> ByteVector; + +TEST(ChunkedByteBufferTest, BasicTest) { + ChunkedByteBuffer buffer; + + const uint8 kChunks[] = { + 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, // Chunk 1: 4 bytes + 0x00, 0x00, 0x00, 0x02, 0x05, 0x06, // Chunk 2: 2 bytes + 0x00, 0x00, 0x00, 0x01, 0x07 // Chunk 3: 1 bytes + }; + + EXPECT_EQ(0U, buffer.GetTotalLength()); + EXPECT_FALSE(buffer.HasChunks()); + + // Append partially chunk 1. + buffer.Append(kChunks, 2); + EXPECT_EQ(2U, buffer.GetTotalLength()); + EXPECT_FALSE(buffer.HasChunks()); + + // Complete chunk 1. + buffer.Append(kChunks + 2, 6); + EXPECT_EQ(8U, buffer.GetTotalLength()); + EXPECT_TRUE(buffer.HasChunks()); + + // Append fully chunk 2. + buffer.Append(kChunks + 8, 6); + EXPECT_EQ(14U, buffer.GetTotalLength()); + EXPECT_TRUE(buffer.HasChunks()); + + // Remove and check chunk 1. + scoped_ptr<ByteVector> chunk; + chunk = buffer.PopChunk(); + EXPECT_TRUE(chunk != NULL); + EXPECT_EQ(4U, chunk->size()); + EXPECT_EQ(0, std::char_traits<uint8>::compare(kChunks + 4, + &(*chunk)[0], + chunk->size())); + EXPECT_EQ(6U, buffer.GetTotalLength()); + EXPECT_TRUE(buffer.HasChunks()); + + // Read and check chunk 2. + chunk = buffer.PopChunk(); + EXPECT_TRUE(chunk != NULL); + EXPECT_EQ(2U, chunk->size()); + EXPECT_EQ(0, std::char_traits<uint8>::compare(kChunks + 12, + &(*chunk)[0], + chunk->size())); + EXPECT_EQ(0U, buffer.GetTotalLength()); + EXPECT_FALSE(buffer.HasChunks()); + + // Append fully chunk 3. + buffer.Append(kChunks + 14, 5); + EXPECT_EQ(5U, buffer.GetTotalLength()); + + // Remove and check chunk 3. + chunk = buffer.PopChunk(); + EXPECT_TRUE(chunk != NULL); + EXPECT_EQ(1U, chunk->size()); + EXPECT_EQ((*chunk)[0], kChunks[18]); + EXPECT_EQ(0U, buffer.GetTotalLength()); + EXPECT_FALSE(buffer.HasChunks()); +} + +} // namespace speech |