Home | History | Annotate | Download | only in memory_image
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
     18 #define LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
     19 
     20 #include <string.h>
     21 
     22 #include <string>
     23 
     24 #include "base.h"
     25 #include "common/memory_image/memory-image-common.h"
     26 #include "util/base/integral_types.h"
     27 #include "util/base/logging.h"
     28 
     29 namespace libtextclassifier {
     30 namespace nlp_core {
     31 
     32 class LowLevelMemReader {
     33  public:
     34   // Constructs a MemReader instance that reads at most num_available_bytes
     35   // starting from address start.
     36   LowLevelMemReader(const void *start, uint64 num_available_bytes)
     37       : current_(reinterpret_cast<const char *>(start)),
     38         // 0 bytes available if start == nullptr
     39         num_available_bytes_(start ? num_available_bytes : 0),
     40         num_loaded_bytes_(0) {
     41   }
     42 
     43   // Copies length bytes of data to address target.  Advances current position
     44   // and returns true on success and false otherwise.
     45   bool Read(void *target, uint64 length) {
     46     if (length > num_available_bytes_) {
     47       TC_LOG(WARNING) << "Not enough bytes: available " << num_available_bytes_
     48                       << " < required " << length;
     49       return false;
     50     }
     51     memcpy(target, current_, length);
     52     Advance(length);
     53     return true;
     54   }
     55 
     56   // Reads the string encoded at the current position.  The bytes starting at
     57   // current position should contain (1) little-endian uint32 size (in bytes) of
     58   // the actual string and next (2) the actual bytes of the string.  Advances
     59   // the current position and returns true if successful, false otherwise.
     60   //
     61   // On success, sets *view to be a view of the relevant bytes: view.data()
     62   // points to the beginning of the string bytes, and view.size() is the number
     63   // of such bytes.
     64   bool ReadString(DataBlobView *view) {
     65     uint32 size;
     66     if (!Read(&size, sizeof(size))) {
     67       TC_LOG(ERROR) << "Unable to read std::string size";
     68       return false;
     69     }
     70     size = LittleEndian::ToHost32(size);
     71     if (size > num_available_bytes_) {
     72       TC_LOG(WARNING) << "Not enough bytes: " << num_available_bytes_
     73                       << " available < " << size << " required ";
     74       return false;
     75     }
     76     *view = DataBlobView(current_, size);
     77     Advance(size);
     78     return true;
     79   }
     80 
     81   // Like ReadString(DataBlobView *) but reads directly into a C++ string,
     82   // instead of a DataBlobView (StringPiece-like object).
     83   bool ReadString(std::string *target) {
     84     DataBlobView view;
     85     if (!ReadString(&view)) {
     86       return false;
     87     }
     88     *target = view.ToString();
     89     return true;
     90   }
     91 
     92   // Returns current position.
     93   const char *GetCurrent() const { return current_; }
     94 
     95   // Returns remaining number of available bytes.
     96   uint64 GetNumAvailableBytes() const { return num_available_bytes_; }
     97 
     98   // Returns number of bytes read ("loaded") so far.
     99   uint64 GetNumLoadedBytes() const { return num_loaded_bytes_; }
    100 
    101   // Advance the current read position by indicated number of bytes.  Returns
    102   // true on success, false otherwise (e.g., if there are not enough available
    103   // bytes to advance num_bytes).
    104   bool Advance(uint64 num_bytes) {
    105     if (num_bytes > num_available_bytes_) {
    106       return false;
    107     }
    108 
    109     // Next line never results in an underflow of the unsigned
    110     // num_available_bytes_, due to the previous if.
    111     num_available_bytes_ -= num_bytes;
    112     current_ += num_bytes;
    113     num_loaded_bytes_ += num_bytes;
    114     return true;
    115   }
    116 
    117   // Advance current position to nearest multiple of alignment.  Returns false
    118   // if not enough bytes available to do that, true (success) otherwise.
    119   bool SkipToAlign(int alignment) {
    120     int num_extra_bytes = num_loaded_bytes_ % alignment;
    121     if (num_extra_bytes == 0) {
    122       return true;
    123     }
    124     return Advance(alignment - num_extra_bytes);
    125   }
    126 
    127  private:
    128   // Current position in the in-memory data.  Next call to Read() will read from
    129   // this address.
    130   const char *current_;
    131 
    132   // Number of available bytes we can still read.
    133   uint64 num_available_bytes_;
    134 
    135   // Number of bytes read ("loaded") so far.
    136   uint64 num_loaded_bytes_;
    137 };
    138 
    139 }  // namespace nlp_core
    140 }  // namespace libtextclassifier
    141 
    142 #endif  // LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
    143