blob: 7ea4aa8cc02c312e384f53a9a23e6ccf087ae38a [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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 DATASTAX_INTERNAL_SERIALIZATION_HPP
#define DATASTAX_INTERNAL_SERIALIZATION_HPP
#include "address.hpp"
#include "cassandra.h"
#include "map.hpp"
#include "string.hpp"
#include "string_ref.hpp"
#include "utils.hpp"
#include <uv.h>
#include <assert.h>
#include <limits>
#include <string.h>
namespace datastax { namespace internal {
// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
// This frees us from having to deal with endian stuff on every platform.
// If it's not fast enough then we can go back to using the bytes swaps.
// TODO(mpenick): Use output pointers instead of references and make input const
// "decode_byte(input, &value)" is clearer than "decode_byte(input, value)"
inline char* encode_byte(char* output, uint8_t value) {
output[0] = static_cast<char>(value);
return output + sizeof(uint8_t);
}
inline const char* decode_byte(const char* input, uint8_t& output) {
output = static_cast<uint8_t>(input[0]);
return input + sizeof(uint8_t);
}
inline char* encode_int8(char* output, int8_t value) {
output[0] = static_cast<char>(value);
return output + sizeof(int8_t);
}
inline const char* decode_int8(const char* input, int8_t& output) {
output = static_cast<int8_t>(input[0]);
return input + sizeof(int8_t);
}
inline char* encode_uint16(char* output, uint16_t value) {
output[0] = static_cast<char>(value >> 8);
output[1] = static_cast<char>(value >> 0);
return output + sizeof(uint16_t);
}
inline const char* decode_uint16(const char* input, uint16_t& output) {
output = static_cast<uint16_t>((static_cast<uint16_t>(static_cast<uint8_t>(input[1])) << 0) |
(static_cast<uint16_t>(static_cast<uint8_t>(input[0])) << 8));
return input + sizeof(uint16_t);
}
inline char* encode_int16(char* output, int16_t value) {
output[0] = static_cast<char>(value >> 8);
output[1] = static_cast<char>(value >> 0);
return output + sizeof(int16_t);
}
inline const char* decode_int16(const char* input, int16_t& output) {
output = static_cast<int16_t>((static_cast<int16_t>(static_cast<uint8_t>(input[1])) << 0) |
(static_cast<int16_t>(static_cast<uint8_t>(input[0])) << 8));
return input + sizeof(int16_t);
}
inline char* encode_uint32(char* output, uint32_t value) {
output[0] = static_cast<char>(value >> 24);
output[1] = static_cast<char>(value >> 16);
output[2] = static_cast<char>(value >> 8);
output[3] = static_cast<char>(value >> 0);
return output + sizeof(uint32_t);
}
inline const char* decode_uint32(const char* input, uint32_t& output) {
output = (static_cast<uint32_t>(static_cast<uint8_t>(input[3])) << 0) |
(static_cast<uint32_t>(static_cast<uint8_t>(input[2])) << 8) |
(static_cast<uint32_t>(static_cast<uint8_t>(input[1])) << 16) |
(static_cast<uint32_t>(static_cast<uint8_t>(input[0])) << 24);
return input + sizeof(uint32_t);
}
inline char* encode_int32(char* output, int32_t value) {
output[0] = static_cast<char>(value >> 24);
output[1] = static_cast<char>(value >> 16);
output[2] = static_cast<char>(value >> 8);
output[3] = static_cast<char>(value >> 0);
return output + sizeof(int32_t);
}
inline const char* decode_int32(const char* input, int32_t& output) {
output = (static_cast<int32_t>(static_cast<uint8_t>(input[3])) << 0) |
(static_cast<int32_t>(static_cast<uint8_t>(input[2])) << 8) |
(static_cast<int32_t>(static_cast<uint8_t>(input[1])) << 16) |
(static_cast<int32_t>(static_cast<uint8_t>(input[0])) << 24);
return input + sizeof(int32_t);
}
inline char* encode_int64(char* output, int64_t value) {
STATIC_ASSERT(sizeof(int64_t) == 8);
output[0] = static_cast<char>(value >> 56);
output[1] = static_cast<char>(value >> 48);
output[2] = static_cast<char>(value >> 40);
output[3] = static_cast<char>(value >> 32);
output[4] = static_cast<char>(value >> 24);
output[5] = static_cast<char>(value >> 16);
output[6] = static_cast<char>(value >> 8);
output[7] = static_cast<char>(value >> 0);
return output + sizeof(int64_t);
}
inline const char* decode_int64(const char* input, int64_t& output) {
STATIC_ASSERT(sizeof(int64_t) == 8);
output = (static_cast<int64_t>(static_cast<uint8_t>(input[7])) << 0) |
(static_cast<int64_t>(static_cast<uint8_t>(input[6])) << 8) |
(static_cast<int64_t>(static_cast<uint8_t>(input[5])) << 16) |
(static_cast<int64_t>(static_cast<uint8_t>(input[4])) << 24) |
(static_cast<int64_t>(static_cast<uint8_t>(input[3])) << 32) |
(static_cast<int64_t>(static_cast<uint8_t>(input[2])) << 40) |
(static_cast<int64_t>(static_cast<uint8_t>(input[1])) << 48) |
(static_cast<int64_t>(static_cast<uint8_t>(input[0])) << 56);
return input + sizeof(int64_t);
}
inline char* encode_float(char* output, float value) {
STATIC_ASSERT(std::numeric_limits<float>::is_iec559);
return encode_int32(output, copy_cast<float, int32_t>(value));
}
inline const char* decode_float(const char* input, float& output) {
STATIC_ASSERT(std::numeric_limits<float>::is_iec559);
int32_t int_value;
const char* pos = decode_int32(input, int_value);
output = copy_cast<int32_t, float>(int_value);
return pos;
}
inline char* encode_double(char* output, double value) {
STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
return encode_int64(output, copy_cast<double, int64_t>(value));
}
inline const char* decode_double(const char* input, double& output) {
STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
int64_t int_value;
const char* pos = decode_int64(input, int_value);
output = copy_cast<int64_t, double>(int_value);
return pos;
}
inline char* encode_uuid(char* output, CassUuid uuid) {
uint64_t time_and_version = uuid.time_and_version;
output[3] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[2] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[1] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[0] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[5] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[4] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[7] = static_cast<char>(time_and_version & 0x00000000000000FFLL);
time_and_version >>= 8;
output[6] = static_cast<char>(time_and_version & 0x000000000000000FFLL);
uint64_t clock_seq_and_node = uuid.clock_seq_and_node;
for (size_t i = 0; i < 8; ++i) {
output[15 - i] = static_cast<char>(clock_seq_and_node & 0x00000000000000FFL);
clock_seq_and_node >>= 8;
}
// UUID is 128-bit, which is 16 bytes.
return output + 16;
}
inline const char* decode_uuid(const char* input, CassUuid* output) {
output->time_and_version = static_cast<uint64_t>(static_cast<uint8_t>(input[3]));
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[2])) << 8;
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[1])) << 16;
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[0])) << 24;
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[5])) << 32;
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[4])) << 40;
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[7])) << 48;
output->time_and_version |= static_cast<uint64_t>(static_cast<uint8_t>(input[6])) << 56;
output->clock_seq_and_node = 0;
for (size_t i = 0; i < 8; ++i) {
output->clock_seq_and_node |= static_cast<uint64_t>(static_cast<uint8_t>(input[15 - i]))
<< (8 * i);
}
return input + 16;
}
inline int64_t decode_zig_zag(uint64_t n) {
// n is an unsigned long because we want a logical shift right
// (it should 0-fill high order bits), not arithmetic shift right.
return (n >> 1) ^ -static_cast<int64_t>(n & 1);
}
inline uint64_t encode_zig_zag(int64_t n) { return (n << 1) ^ (n >> 63); }
}} // namespace datastax::internal
#endif