blob: e062d5b91154a470e9c8921dbcb0465fc0e3c4b3 [file] [log] [blame]
/*
* 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