C++程序  |  132行  |  3.68 KB

/*
 * Copyright 2019 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.
 */

#include "annotation_util.h"

#include <cstdlib>

#define LOG_TAG "TuningFork"
#include "Log.h"

namespace annotation_util {

typedef uint64_t AnnotationId;

// This is a protobuf 1-based index
int GetKeyIndex(uint8_t b) {
    int type = b & 0x7;
    if (type != 0) return kKeyError;
    return b >> 3;
}

uint64_t GetBase128IntegerFromByteStream(const std::vector<uint8_t> &bytes, int &index) {
    uint64_t m = 0;
    uint64_t r = 0;
    while (index < bytes.size() && m <= (64 - 7)) {
        auto b = bytes[index];
        r |= (((uint64_t) b) & 0x7f) << m;
        if ((b & 0x80) != 0) m += 7;
        else return r;
        ++index;
    }
    return kStreamError;
}

void WriteBase128IntToStream(uint64_t x, std::vector<uint8_t> &bytes) {
    do {
        uint8_t a = x & 0x7f;
        int b = x & 0xffffffffffffff80;
        if (b) {
            bytes.push_back(a | 0x80);
            x >>= 7;
        } else {
            bytes.push_back(a);
            return;
        }
    } while(x);
}

AnnotationId DecodeAnnotationSerialization(const SerializedAnnotation &ser,
                                           const std::vector<int>& radix_mult) {
    AnnotationId result = 0;
    for (int i = 0; i < ser.size(); ++i) {
        int key = GetKeyIndex(ser[i]);
        if (key == kKeyError)
            return kAnnotationError;
        // Convert to 0-based index
        --key;
        if (key >= radix_mult.size())
            return kAnnotationError;
        ++i;
        if (i >= ser.size())
            return kAnnotationError;
        uint64_t value = GetBase128IntegerFromByteStream(ser, i);
        if (value == kStreamError)
            return kAnnotationError;
        // Check the range of the value
        if (value == 0 || value >= radix_mult[key])
            return kAnnotationError;
        // We don't allow enums with more that 255 values
        if (value > 0xff)
            return kAnnotationError;
        if (key > 0)
            result += radix_mult[key - 1] * value;
        else
            result += value;
    }
    return result;
}

int SerializeAnnotationId(uint64_t id, SerializedAnnotation& ser,
                          const std::vector<int>& radix_mult) {
  int err = 0;
  uint64_t x = id;
  for (int i = 0; i < radix_mult.size(); ++i) {
    auto r = ::div(x, radix_mult[i]);
    int value = r.rem;
    if (value > 0) {
      int key = (i + 1) << 3;
      ser.push_back(key);
      WriteBase128IntToStream(value, ser);
    }
    x = r.quot;
  }
  return err;
}

void SetUpAnnotationRadixes( std::vector<int>& radix_mult,
                             const std::vector<int>& enum_sizes) {
    ALOGV("Settings::annotation_enum_size");
    for(int i=0; i< enum_sizes.size();++i) {
      ALOGV("%d", enum_sizes[i]);
    }
    int n = enum_sizes.size();
    if (n == 0) {
        // With no annotations, we just have 1 possible prong per key
        radix_mult.resize(1);
        radix_mult[0] = 1;
    } else {
        radix_mult.resize(n);
        int r = 1;
        for (int i = 0; i < n; ++i) {
            r *= enum_sizes[i] + 1;
            radix_mult[i] = r;
        }
    }
}

} // namespace annotation_util