Skip to content
This repository has been archived by the owner on Oct 4, 2019. It is now read-only.

Commit

Permalink
More fixed_string endiannes changes #4
Browse files Browse the repository at this point in the history
  • Loading branch information
nemothenoone committed Nov 21, 2017
1 parent b478094 commit 9115345
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 85 deletions.
188 changes: 105 additions & 83 deletions include/fc/fixed_string.hpp
Original file line number Diff line number Diff line change
@@ -1,56 +1,120 @@
#pragma once

#include <fc/uint128_t.hpp>
#include <fc/io/raw_fwd.hpp>

#include <boost/endian/conversion.hpp>

namespace fc {
/**
* This class is designed to offer in-place memory allocation of a string up to Length equal to
* sizeof(Storage).
* Endian-reversible pair class.
*/

template<typename A, typename B>
struct erpair {
erpair() {
}

erpair(const A &a, const B &b) : first(a), second(b) {
}

friend bool operator<(const erpair &a, const erpair &b) {
return std::tie(a.first, a.second) < std::tie(b.first, b.second);
}

friend bool operator<=(const erpair &a, const erpair &b) {
return std::tie(a.first, a.second) <= std::tie(b.first, b.second);
}

friend bool operator>(const erpair &a, const erpair &b) {
return std::tie(a.first, a.second) > std::tie(b.first, b.second);
}

friend bool operator>=(const erpair &a, const erpair &b) {
return std::tie(a.first, a.second) >= std::tie(b.first, b.second);
}

friend bool operator==(const erpair &a, const erpair &b) {
return std::tie(a.first, a.second) == std::tie(b.first, b.second);
}

friend bool operator!=(const erpair &a, const erpair &b) {
return std::tie(a.first, a.second) != std::tie(b.first, b.second);
}

A first{};
B second{};
};

template<typename A, typename B>
erpair<A, B> make_erpair(const A &a, const B &b) {
return erpair<A, B>(a, b);
}

template<typename T>
T endian_reverse(const T &x) {
return boost::endian::endian_reverse(x);
}

template<>
inline uint128_t endian_reverse(const uint128_t &u) {
return uint128_t(boost::endian::endian_reverse(u.hi), boost::endian::endian_reverse(u.lo));
}

template<typename A, typename B>
erpair<A, B> endian_reverse(const erpair<A, B> &p) {
return make_erpair(endian_reverse(p.first), endian_reverse(p.second));
}

/**
* This class is an in-place memory allocation of a fixed length character string.
*
* The string will serialize the same way as std::string for variant and raw formats
* The string will sort according to the comparison operators defined for Storage, this enables effecient
* sorting.
* The string will serialize the same way as std::string for variant and raw formats.
*/
template<typename Storage = std::pair<uint64_t, uint64_t> >
template<typename Storage = fc::uint128_t>
class fixed_string {
public:
fixed_string() {
memset((char *) &data, 0, sizeof(data));
}

fixed_string(const fixed_string &c) : data(c.data) {
}

fixed_string(const char *str) : fixed_string(std::string(str)) {
}

fixed_string(const std::string &str) {
memset((char *) &data, 0, sizeof(data));
if (str.size() < sizeof(data)) {
memcpy((char *) &data, str.c_str(), str.size());
Storage d;
if (str.size() <= sizeof(d)) {
memcpy((char *) &d, str.c_str(), str.size());
} else {
memcpy((char *) &data, str.c_str(), sizeof(data));
memcpy((char *) &d, str.c_str(), sizeof(d));
}

data = d;
}

fixed_string(const char *str) {
memset((char *) &data, 0, sizeof(data));
auto l = strlen(str);
if (l < sizeof(data)) {
memcpy((char *) &data, str, l);
operator std::string() const {
Storage d = data;
size_t s;

if (*(((const char *) &d) + sizeof(d) - 1)) {
s = sizeof(d);
} else {
memcpy((char *) &data, str, sizeof(data));
s = strnlen((const char *) &d, sizeof(d));
}
}

operator std::string() const {
const char *self = (const char *) &data;
return std::string(self, self + size());
const char *self = (const char *) &d;

return std::string(self, self + s);
}

uint32_t size() const {
if (*(((const char *) &data) + sizeof(data) - 1)) {
return sizeof(data);
Storage d = data;
if (*(((const char *) &d) + sizeof(d) - 1)) {
return sizeof(d);
}
return strnlen((const char *) &data, sizeof(data));
return strnlen((const char *) &d, sizeof(d));
}

uint32_t length() const {
Expand All @@ -63,16 +127,12 @@ namespace fc {
}

fixed_string &operator=(const char *str) {
return *this = fixed_string(str);
*this = fixed_string(str);
return *this;
}

fixed_string &operator=(const std::string &str) {
memset((char *) &data, 0, sizeof(data));
if (str.size() < sizeof(data)) {
memcpy((char *) &data, str.c_str(), str.size());
} else {
memcpy((char *) &data, str.c_str(), sizeof(data));
}
*this = fixed_string(str);
return *this;
}

Expand Down Expand Up @@ -108,67 +168,29 @@ namespace fc {
return a.data != b.data;
}

friend std::ostream &operator<<(std::ostream &out, const fixed_string &str) {
return out << std::string(str);
}

//private:
Storage data;
};

// These storage types work with memory layout and should be used instead of a custom template.
typedef fixed_string<fc::uint128_t> fixed_string_16;
typedef fixed_string<fc::erpair<fc::uint128_t, uint64_t>> fixed_string_24;
typedef fixed_string<fc::erpair<fc::uint128_t, fc::uint128_t>> fixed_string_32;

namespace raw {
template<typename Stream, typename Storage>
inline void pack(Stream &s, const fc::fixed_string<Storage> &u) {
unsigned_int size = u.size();
pack(s, size);
s.write((const char *) &u.data, size);
}

template<typename Stream, typename Storage>
inline void unpack(Stream &s, fc::fixed_string<Storage> &u) {
unsigned_int size;
fc::raw::unpack(s, size);
if (size.value > 0) {
if (size.value > sizeof(Storage)) {
s.read((char *) &u.data, sizeof(Storage));
char buf[1024];
size_t left = size.value - sizeof(Storage);
while (left >= 1024) {
s.read(buf, 1024);
left -= 1024;
}
s.read(buf, left);

/*
s.seekp( s.tellp() + (size.value - sizeof(Storage)) );
char tmp;
size.value -= sizeof(storage);
while( size.value ){ s.read( &tmp, 1 ); --size.value; }
*/
// s.skip( size.value - sizeof(Storage) );
} else {
s.read((char *) &u.data, size.value);
}
}
inline void pack(Stream &s, const fixed_string<Storage> &u) {
pack(s, std::string(u));
}

/*
template<typename Stream, typename... Args>
inline void pack( Stream& s, const boost::multiprecision::number<Args...>& d ) {
s.write( (const char*)&d, sizeof(d) );
}
template<typename Stream, typename... Args>
inline void unpack( Stream& s, boost::multiprecision::number<Args...>& u ) {
s.read( (const char*)&u, sizeof(u) );
template<typename Stream, typename Storage>
inline void unpack(Stream &s, fixed_string<Storage> &u) {
std::string str;
unpack(s, str);
u = str;
}
*/
}
}

#include <fc/variant.hpp>

namespace fc {
} // raw
template<typename Storage>
void to_variant(const fixed_string<Storage> &s, variant &v) {
v = std::string(s);
Expand All @@ -178,4 +200,4 @@ namespace fc {
void from_variant(const variant &v, fixed_string<Storage> &s) {
s = v.as_string();
}
}
} // fc
2 changes: 0 additions & 2 deletions include/fc/uint128_t.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,6 @@ namespace fc {

static_assert(sizeof(uint128_t) == 2 * sizeof(uint64_t), "validate packing assumptions");

typedef uint128_t uint128_t;

class variant;

void to_variant(const uint128_t &var, variant &vo);
Expand Down

0 comments on commit 9115345

Please sign in to comment.