blob: 86d4871d4a176992689a51667a645db0f8a4af6c [file]
/*
Copyright 2014 DataStax
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 __CASS_SERIALIZATION_HPP_INCLUDED__
#define __CASS_SERIALIZATION_HPP_INCLUDED__
#include "cassandra.h"
#include "third_party/boost/boost/limits.hpp"
#include "third_party/boost/boost/cstdint.hpp"
#include <assert.h>
#include <string.h>
#include <list>
#include <map>
#include <string>
namespace cass {
// 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 char* decode_byte(char* input, uint8_t& output) {
output = static_cast<uint8_t>(input[0]);
return input + sizeof(uint8_t);
}
inline void encode_uint16(char* output, uint16_t value) {
output[0] = static_cast<char>(value >> 8);
output[1] = static_cast<char>(value >> 0);
}
inline char* decode_uint16(char* input, uint16_t& output) {
output = (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 void 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);
}
inline char* decode_int32(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 void encode_int64(char* output, int64_t value) {
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);
}
inline char* decode_int64(char* input, int64_t& output) {
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 void encode_float(char* output, float value) {
assert(std::numeric_limits<float>::is_iec559);
assert(sizeof(float) == sizeof(int32_t));
encode_int32(output, *reinterpret_cast<int32_t*>(&value));
}
inline char* decode_float(char* input, float& output) {
assert(std::numeric_limits<float>::is_iec559);
assert(sizeof(float) == sizeof(int32_t));
return decode_int32(input, *reinterpret_cast<int32_t*>(&output));
}
inline void encode_double(char* output, double value) {
assert(std::numeric_limits<double>::is_iec559);
assert(sizeof(double) == sizeof(int64_t));
encode_int64(output, *reinterpret_cast<int64_t*>(&value));
}
inline char* decode_double(char* input, double& output) {
assert(std::numeric_limits<double>::is_iec559);
assert(sizeof(double) == sizeof(int64_t));
return decode_int64(input, *reinterpret_cast<int64_t*>(&output));
}
inline char* decode_string(char* input, char** output, size_t& size) {
*output = decode_uint16(input, ((uint16_t&)size));
return *output + size;
}
inline char* decode_long_string(char* input, char** output, size_t& size) {
*output = decode_int32(input, ((int32_t&)size));
return *output + size;
}
inline char* decode_string_map(char* input,
std::map<std::string, std::string>& map) {
map.clear();
uint16_t len = 0;
char* buffer = decode_uint16(input, len);
for (int i = 0; i < len; i++) {
char* key = 0;
size_t key_size = 0;
char* value = 0;
size_t value_size = 0;
buffer = decode_string(buffer, &key, key_size);
buffer = decode_string(buffer, &value, value_size);
map.insert(std::make_pair(std::string(key, key_size),
std::string(value, value_size)));
}
return buffer;
}
inline char* decode_stringlist(char* input, std::list<std::string>& output) {
output.clear();
uint16_t len = 0;
char* buffer = decode_uint16(input, len);
for (int i = 0; i < len; i++) {
char* s = NULL;
size_t s_size = 0;
buffer = decode_string(buffer, &s, s_size);
output.push_back(std::string(s, s_size));
}
return buffer;
}
typedef std::map<std::string, std::list<std::string> > StringMultimap;
inline char* decode_string_multimap(char* input, StringMultimap& output) {
output.clear();
uint16_t len = 0;
char* buffer = decode_uint16(input, len);
for (int i = 0; i < len; i++) {
char* key = 0;
size_t key_size = 0;
std::list<std::string> value;
buffer = decode_string(buffer, &key, key_size);
buffer = decode_stringlist(buffer, value);
output.insert(std::make_pair(std::string(key, key_size), value));
}
return buffer;
}
inline char* decode_option(char* input, uint16_t& type, char** class_name,
size_t& class_name_size) {
char* buffer = decode_uint16(input, type);
if (type == CASS_VALUE_TYPE_CUSTOM) {
buffer = decode_string(buffer, class_name, class_name_size);
}
return buffer;
}
} // namespace cass
#endif