blob: 1d1f8df0525a128bbf71c675b6b896962f0102b2 [file] [log] [blame]
/*
* Copyright (C) 2016 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 "encoder.h"
#include "schema.h"
#include "stream_writer.h"
#include <cstring>
namespace gapic {
Encoder::Encoder(std::shared_ptr<StreamWriter> output) : mOutput(output), mLastObjectId(0) {
mEntities.insert(std::make_pair(nullptr, 0));
}
void Encoder::Bool(bool v) {
uint8_t b = v ? 1 : 0;
mOutput->write(&b, 1);
}
void Encoder::Int8(int8_t v) {
mOutput->write(&v, 1);
}
void Encoder::Uint8(uint8_t v) {
mOutput->write(&v, 1);
}
void Encoder::Uint16(uint16_t v) {
uint8_t buf[9];
uint16_t space = 0x7f;
uint8_t tag = 0;
for (int o = 8; true; o--) {
if (v <= space) {
buf[o] = uint8_t(v) | uint8_t(tag);
mOutput->write(buf + o, 9 - o);
return;
}
buf[o] = uint8_t(v);
v = v >> 8;
space >>= 1;
tag = (tag >> 1) | 0x80;
}
}
void Encoder::Int16(int16_t v) {
uint16_t uv = uint16_t(v) << 1;
Uint16((v < 0) ? ~uv : uv);
}
void Encoder::Float32(float v) {
uint32_t bits = *reinterpret_cast<uint32_t*>(&v);
uint32_t shuffled =
((bits & 0x000000ff) << 24) |
((bits & 0x0000ff00) << 8) |
((bits & 0x00ff0000) >> 8) |
((bits & 0xff000000) >> 24);
return Uint32(shuffled);
}
void Encoder::Uint32(uint32_t v) {
uint8_t buf[9];
uint32_t space = 0x7f;
uint8_t tag = 0;
for (int o = 8; true; o--) {
if (v <= space) {
buf[o] = uint8_t(v) | uint8_t(tag);
mOutput->write(buf + o, 9 - o);
return;
}
buf[o] = uint8_t(v);
v = v >> 8;
space >>= 1;
tag = (tag >> 1) | 0x80;
}
}
void Encoder::Int32(int32_t v) {
uint32_t uv = uint32_t(v) << 1;
Uint32((v < 0) ? ~uv : uv);
}
void Encoder::Float64(double v) {
uint64_t bits = *reinterpret_cast<uint64_t*>(&v);
uint64_t shuffled =
((bits & 0x00000000000000ffULL) << 56) |
((bits & 0x000000000000ff00ULL) << 40) |
((bits & 0x0000000000ff0000ULL) << 24) |
((bits & 0x00000000ff000000ULL) << 8) |
((bits & 0x000000ff00000000ULL) >> 8) |
((bits & 0x0000ff0000000000ULL) >> 24) |
((bits & 0x00ff000000000000ULL) >> 40) |
((bits & 0xff00000000000000ULL) >> 56);
return Uint64(shuffled);
}
void Encoder::Uint64(uint64_t v) {
uint8_t buf[9];
uint64_t space = 0x7f;
uint8_t tag = 0;
for (int o = 8; true; o--) {
if (v <= space) {
buf[o] = uint8_t(v) | uint8_t(tag);
mOutput->write(buf + o, 9 - o);
return;
}
buf[o] = uint8_t(v);
v = v >> 8;
space >>= 1;
tag = (tag >> 1) | 0x80;
}
}
void Encoder::Int64(int64_t v) {
uint64_t uv = uint64_t(v) << 1;
Uint64((v < 0) ? ~uv : uv);
}
void Encoder::Pointer(const void* p) {
Uint64(reinterpret_cast<uintptr_t>(p));
Uint32(0); // Pool-id
}
void Encoder::String(const char* v) {
uint32_t len = v != nullptr ? static_cast<uint32_t>(strlen(v)) : 0;
Uint32(len);
mOutput->write(v, len);
}
void Encoder::Data(const void* ptr, int32_t size) {
mOutput->write(ptr, size);
}
void Encoder::Entity(const schema::Entity* entity) {
auto ret = mEntities.insert(
std::make_pair(entity, mEntities.size()));
uint32_t sid = ret.first->second;
if (!ret.second) {
Uint32(sid << 1);
} else {
Uint32((sid << 1) | 1);
entity->encode(*this);
}
}
void Encoder::Struct(const Encodable& obj) {
obj.Encode(this);
}
void Encoder::Variant(const Encodable* obj) {
if (obj == nullptr) {
Entity(nullptr);
return;
}
Entity(obj->Schema());
obj->Encode(this);
}
void Encoder::Object(const Encodable* obj) {
if (obj == nullptr) {
Uint32(0);
return;
}
uint32_t sid = ++mLastObjectId;
Uint32((sid << 1) | 1);
Variant(obj);
}
} // namespace gapic