blob: 91953d875fb8d7d0f0e94e1ca7518fed43df8006 [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 LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
#define LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
#include <string.h>
#include <string>
#include "base.h"
#include "common/memory_image/memory-image-common.h"
#include "util/base/integral_types.h"
#include "util/base/logging.h"
namespace libtextclassifier {
namespace nlp_core {
class LowLevelMemReader {
public:
// Constructs a MemReader instance that reads at most num_available_bytes
// starting from address start.
LowLevelMemReader(const void *start, uint64 num_available_bytes)
: current_(reinterpret_cast<const char *>(start)),
// 0 bytes available if start == nullptr
num_available_bytes_(start ? num_available_bytes : 0),
num_loaded_bytes_(0) {
}
// Copies length bytes of data to address target. Advances current position
// and returns true on success and false otherwise.
bool Read(void *target, uint64 length) {
if (length > num_available_bytes_) {
TC_LOG(WARNING) << "Not enough bytes: available " << num_available_bytes_
<< " < required " << length;
return false;
}
memcpy(target, current_, length);
Advance(length);
return true;
}
// Reads the string encoded at the current position. The bytes starting at
// current position should contain (1) little-endian uint32 size (in bytes) of
// the actual string and next (2) the actual bytes of the string. Advances
// the current position and returns true if successful, false otherwise.
//
// On success, sets *view to be a view of the relevant bytes: view.data()
// points to the beginning of the string bytes, and view.size() is the number
// of such bytes.
bool ReadString(DataBlobView *view) {
uint32 size;
if (!Read(&size, sizeof(size))) {
TC_LOG(ERROR) << "Unable to read std::string size";
return false;
}
size = LittleEndian::ToHost32(size);
if (size > num_available_bytes_) {
TC_LOG(WARNING) << "Not enough bytes: " << num_available_bytes_
<< " available < " << size << " required ";
return false;
}
*view = DataBlobView(current_, size);
Advance(size);
return true;
}
// Like ReadString(DataBlobView *) but reads directly into a C++ string,
// instead of a DataBlobView (StringPiece-like object).
bool ReadString(std::string *target) {
DataBlobView view;
if (!ReadString(&view)) {
return false;
}
*target = view.ToString();
return true;
}
// Returns current position.
const char *GetCurrent() const { return current_; }
// Returns remaining number of available bytes.
uint64 GetNumAvailableBytes() const { return num_available_bytes_; }
// Returns number of bytes read ("loaded") so far.
uint64 GetNumLoadedBytes() const { return num_loaded_bytes_; }
// Advance the current read position by indicated number of bytes. Returns
// true on success, false otherwise (e.g., if there are not enough available
// bytes to advance num_bytes).
bool Advance(uint64 num_bytes) {
if (num_bytes > num_available_bytes_) {
return false;
}
// Next line never results in an underflow of the unsigned
// num_available_bytes_, due to the previous if.
num_available_bytes_ -= num_bytes;
current_ += num_bytes;
num_loaded_bytes_ += num_bytes;
return true;
}
// Advance current position to nearest multiple of alignment. Returns false
// if not enough bytes available to do that, true (success) otherwise.
bool SkipToAlign(int alignment) {
int num_extra_bytes = num_loaded_bytes_ % alignment;
if (num_extra_bytes == 0) {
return true;
}
return Advance(alignment - num_extra_bytes);
}
private:
// Current position in the in-memory data. Next call to Read() will read from
// this address.
const char *current_;
// Number of available bytes we can still read.
uint64 num_available_bytes_;
// Number of bytes read ("loaded") so far.
uint64 num_loaded_bytes_;
};
} // namespace nlp_core
} // namespace libtextclassifier
#endif // LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_