C++程序  |  143行  |  4.71 KB

/*
 * 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_