| /* |
| * Copyright 2011 Google Inc. |
| * |
| * 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. |
| */ |
| |
| // Author: fangfei@google.com (Fangfei Zhou) |
| |
| #include <cstdlib> // for malloc |
| #include <algorithm> // for min |
| #include "base/logging.h" // for DCHECK |
| #include "pagespeed/kernel/base/circular_buffer.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_writer.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| |
| namespace net_instaweb { |
| |
| class MessageHandler; |
| |
| CircularBuffer* CircularBuffer::Create(const int capacity) { |
| int total = Sizeof(capacity); |
| CircularBuffer* cb = static_cast<CircularBuffer*>(malloc(total)); |
| cb->capacity_ = capacity; |
| cb->wrapped_ = false; |
| cb->offset_ = 0; |
| return cb; |
| } |
| |
| CircularBuffer* CircularBuffer::Init(bool parent, void* block, |
| const int block_size, |
| const int capacity) { |
| // Check if the pre-allocated block has right size for CircularBuffer. |
| DCHECK(block_size == Sizeof(capacity)); |
| CircularBuffer* cb = static_cast<CircularBuffer*>(block); |
| if (parent) { |
| // In root process, initialize the variables. |
| cb->capacity_ = capacity; |
| cb->wrapped_ = false; |
| cb->offset_ = 0; |
| } |
| return cb; |
| } |
| |
| void CircularBuffer::Clear() { |
| offset_ = 0; |
| wrapped_ = false; |
| } |
| |
| bool CircularBuffer::Write(const StringPiece& message) { |
| const char* data = message.data(); |
| int size = message.size(); |
| // Left-truncate the message if its size is larger than buffer. |
| if (size > capacity_) { |
| data += size - capacity_; |
| size = capacity_; |
| memcpy(buffer_, data, size); |
| offset_ = 0; |
| wrapped_ = true; |
| return true; |
| } |
| // Otherwise, start to write the message at offset. |
| if (offset_ == capacity_) { |
| offset_ = 0; |
| wrapped_ = true; |
| } |
| int rest = capacity_ - offset_; |
| int len = std::min(rest, size); |
| memcpy(buffer_ + offset_, data, len); |
| offset_ += len; |
| // If available size < message size < buffer capacity, |
| // write the rest of the data at the beginning of the buffer. |
| if (len < size) { |
| memcpy(buffer_, data + len, size - len); |
| offset_ = size - len; |
| wrapped_ = true; |
| } |
| return true; |
| } |
| |
| GoogleString CircularBuffer::ToString(MessageHandler* handler) { |
| GoogleString result; |
| StringWriter writer(&result); |
| writer.Write(FirstChunk(), handler); |
| writer.Write(SecondChunk(), handler); |
| return result; |
| } |
| |
| StringPiece CircularBuffer::FirstChunk() { |
| if (!wrapped_) { |
| return StringPiece(); |
| } |
| return StringPiece(buffer_ + offset_, capacity_ - offset_); |
| } |
| |
| StringPiece CircularBuffer::SecondChunk() { |
| return StringPiece(buffer_, offset_); |
| } |
| |
| } // namespace net_instaweb |