Skip to content

Commit

Permalink
Re-implemented poor man's version of vector, array, and pair from C++…
Browse files Browse the repository at this point in the history
… standard lib to work in restricted C++ environment (no exceptions, no standard lib) in preparation for later getting the serialization/deserialization code to run within WebAssembly (for EOSIO/eos#354)
  • Loading branch information
arhag committed Oct 2, 2017
1 parent 1ec04ec commit b5bebea
Show file tree
Hide file tree
Showing 21 changed files with 2,573 additions and 64 deletions.
2 changes: 1 addition & 1 deletion libraries/table/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

file(GLOB HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/eos/table/*.hpp")

add_definitions(-DBOOST_PP_VARIADICS)
add_definitions(-DBOOST_PP_VARIADICS -DEOS_TYPES_FULL_CAPABILITY)

add_library( eos_table
dynamic_object.cpp
Expand Down
99 changes: 99 additions & 0 deletions libraries/types/include/eos/eoslib/array.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#pragma once

// Derived from: https://github.com/llvm-mirror/libcxx/blob/master/include/array
// Using MIT License. See: https://github.com/llvm-mirror/libcxx/blob/master/LICENSE.TXT

#include <eos/eoslib/type_traits.hpp>
#include <eos/eoslib/cstddef.hpp>
#include <eos/eoslib/iterator.hpp>
#include <eos/eoslib/exceptions.hpp>

namespace eoslib {

template <class _Tp, size_t _Size>
struct array
{
// types:
typedef array __self;
typedef _Tp value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef size_t size_type;
typedef ptrdiff_t difference_type;

value_type __elems_[_Size > 0 ? _Size : 1];

// No explicit construct/copy/destroy for aggregate type
void fill(const value_type& __u)
{
for( size_type i = 0; i < _Size; ++i )
__elems_[i] = __u;
}

/*
void swap(array& __a)
{
__swap_dispatch((std::integral_constant<bool, _Size == 0>()), __a);
}
void __swap_dispatch(std::true_type, array&) {}
void __swap_dispatch(std::false_type, array& __a)
{
swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);
}
*/

iterator begin() { return iterator(__elems_); }
const_iterator begin()const { return const_iterator(__elems_); }
iterator end() { return iterator(__elems_ + _Size); }
const_iterator end()const { return const_iterator(__elems_ + _Size); }

const_iterator cbegin()const { return begin(); }
const_iterator cend()const { return end(); }

constexpr size_type size()const { return _Size; }
constexpr size_type max_size()const { return _Size; }
constexpr bool empty()const { return _Size == 0; }

reference operator[](size_type __n) { return __elems_[__n]; }
constexpr const_reference operator[](size_type __n)const { return __elems_[__n]; }

reference at(size_type __n);
constexpr const_reference at(size_type __n)const;

reference front() { return __elems_[0]; }
constexpr const_reference front()const { return __elems_[0]; }
reference back() { return __elems_[_Size > 0 ? _Size-1 : 0]; }
constexpr const_reference back()const { return __elems_[_Size > 0 ? _Size-1 : 0]; }

value_type* data() { return __elems_; }
const value_type* data()const { return __elems_; }
};

template <class _Tp, size_t _Size>
typename array<_Tp, _Size>::reference
array<_Tp, _Size>::at(size_type __n)
{
if (__n >= _Size)
EOS_ERROR(std::out_of_range, "array::at");

return __elems_[__n];
}

template <class _Tp, size_t _Size>
constexpr
typename array<_Tp, _Size>::const_reference
array<_Tp, _Size>::at(size_type __n) const
{
if (__n >= _Size)
EOS_ERROR(std::out_of_range, "array::at");
return __elems_[__n];
}

}

9 changes: 9 additions & 0 deletions libraries/types/include/eos/eoslib/cstddef.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

namespace eoslib {

typedef decltype(nullptr) nullptr_t;
typedef long unsigned int size_t;
typedef long int ptrdiff_t;

}
26 changes: 13 additions & 13 deletions libraries/types/include/eos/eoslib/deserialize_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ EOS_TYPES_CUSTOM_BUILTIN_MATCH_END
typename enable_if<eos::types::reflector<Container>::is_array::value>::type
operator()(Container& c)const
{
type_id element_tid;
uint32_t num_elements;
std::tie(element_tid, num_elements) = tm.get_container_element_type(tid);
auto res = tm.get_container_element_type(tid);
type_id element_tid = res.first;
uint32_t num_elements = res.second;
if( num_elements < 2 )
EOS_ERROR(std::runtime_error, "Type mismatch");
if( num_elements != c.size() )
Expand All @@ -163,9 +163,9 @@ EOS_TYPES_CUSTOM_BUILTIN_MATCH_END
if( c.size() != 0 )
EOS_ERROR(std::runtime_error, "Expected vector to construct to be initially empty.");

type_id element_tid;
uint32_t num_elements;
std::tie(element_tid, num_elements) = tm.get_container_element_type(tid);
auto res = tm.get_container_element_type(tid);
type_id element_tid = res.first;
uint32_t num_elements = res.second;
if( num_elements != 0 )
EOS_ERROR(std::runtime_error, "Type mismatch");

Expand All @@ -183,15 +183,15 @@ EOS_TYPES_CUSTOM_BUILTIN_MATCH_END
if( (vector_data_offset + (num_elements * stride)) > r.offset_end() )
EOS_ERROR(std::logic_error, "Raw region is too small to contain this type.");

deserialize_visitor vis(tm, r, element_tid, vector_data_offset);
auto itr = std::inserter(c, c.end());
deserialize_visitor vis(tm, r, element_tid, vector_data_offset);
c.clear();
if( extra_zero_at_end )
--num_elements;
for( uint32_t i = 0; i < num_elements; ++i )
{
typename Container::value_type x;
eos::types::reflector<typename Container::value_type>::visit(x, vis);
itr = std::move(x);
c.push_back(eoslib::move(x));
vis.offset += stride;
}
}
Expand All @@ -207,9 +207,9 @@ EOS_TYPES_CUSTOM_BUILTIN_MATCH_END
typename enable_if<eos::types::reflector<Container>::is_optional::value>::type
operator()(Container& c)const
{
type_id element_tid;
uint32_t num_elements;
std::tie(element_tid, num_elements) = tm.get_container_element_type(tid);
auto res = tm.get_container_element_type(tid);
type_id element_tid = res.first;
uint32_t num_elements = res.second;
if( num_elements != 1 )
EOS_ERROR(std::runtime_error, "Type mismatch");

Expand All @@ -223,7 +223,7 @@ EOS_TYPES_CUSTOM_BUILTIN_MATCH_END
typename Container::value_type x;
deserialize_visitor vis(tm, r, element_tid, offset);
eos::types::reflector<typename Container::value_type>::visit(x, vis);
c = std::move(x);
c = eoslib::move(x);
}

};
Expand Down
6 changes: 4 additions & 2 deletions libraries/types/include/eos/eoslib/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include <stdexcept>

#define EOS_ERROR(type, message) do { throw type(message); } while(0)
#define EOS_ERROR(type, message) throw type(message)

#else

Expand All @@ -14,6 +14,8 @@

#include <cassert>

#define EOS_ERROR(type, message) do { assert(0); } while(0)
#define EOS_ERROR(type, message) assert(0)

#endif

#define EOS_ASSERT(x, msg) ((x) ? (void)0 : EOS_ERROR(std::runtime_error, msg))
2 changes: 1 addition & 1 deletion libraries/types/include/eos/eoslib/immutable_region.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace eos { namespace types {
eos::types::reflector<PlainT>::visit(type, vis);
}

inline const vector<byte>& get_raw_data()const { return raw_data.get_raw_data(); }
inline const Vector<byte>& get_raw_data()const { return raw_data.get_raw_data(); }

private:
const full_types_manager& tm;
Expand Down
65 changes: 65 additions & 0 deletions libraries/types/include/eos/eoslib/initializer_list.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once

// Derived from: https://github.com/llvm-mirror/libcxx/blob/master/include/initializer_list
// Using MIT License. See: https://github.com/llvm-mirror/libcxx/blob/master/LICENSE.TXT

// initializer_list is one of few special cases in the C++ standard library. i
// It must be defined as std::initializer_list because that is what the compiler expects.

//#ifndef EOS_TYPES_REFLET_FULL_CAPABILITY

#include <eos/eoslib/cstddef.hpp>

namespace std {

template<class _Ep>
class initializer_list
{
const _Ep* __begin_;
size_t __size_;

constexpr
initializer_list(const _Ep* __b, size_t __s)
: __begin_(__b), __size_(__s)
{}

public:
typedef _Ep value_type;
typedef const _Ep& reference;
typedef const _Ep& const_reference;
typedef size_t size_type;

typedef const _Ep* iterator;
typedef const _Ep* const_iterator;

constexpr initializer_list()
: __begin_(nullptr), __size_(0)
{}

constexpr size_t size()const { return __size_; }

constexpr const _Ep* begin()const { return __begin_; }

constexpr const _Ep* end()const { return __begin_ + __size_; }
};

template<class _Ep>
inline constexpr
const _Ep*
begin(initializer_list<_Ep> __il)
{
return __il.begin();
}

template<class _Ep>
inline constexpr
const _Ep*
end(initializer_list<_Ep> __il)
{
return __il.end();
}

}

//#endif

93 changes: 93 additions & 0 deletions libraries/types/include/eos/eoslib/iterator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#pragma once

// Derived from: https://github.com/llvm-mirror/libcxx/blob/master/include/iterator
// Using MIT License. See: https://github.com/llvm-mirror/libcxx/blob/master/LICENSE.TXT

#include <eos/eoslib/type_traits.hpp>
#include <eos/eoslib/cstddef.hpp>

namespace eoslib {

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

template <class _Tp>
struct __has_iterator_category
{
private:
struct __two {char __lx; char __lxx;};
template <class _Up> static __two __test(...);
template <class _Up> static char __test(typename _Up::iterator_category* = 0);
public:
static const bool value = sizeof(__test<_Tp>(0)) == 1;
};

template <class _Iter, bool> struct __iterator_traits_impl {};

template <class _Iter>
struct __iterator_traits_impl<_Iter, true>
{
typedef typename _Iter::difference_type difference_type;
typedef typename _Iter::value_type value_type;
typedef typename _Iter::pointer pointer;
typedef typename _Iter::reference reference;
typedef typename _Iter::iterator_category iterator_category;
};

template <class _Iter, bool> struct __iterator_traits {};

template <class _Iter>
struct __iterator_traits<_Iter, true> : __iterator_traits_impl<_Iter, is_convertible<typename _Iter::iterator_category, input_iterator_tag>::value ||
is_convertible<typename _Iter::iterator_category, output_iterator_tag>::value>
{};

// iterator_traits<Iterator> will only have the nested types if Iterator::iterator_category
// exists. Else iterator_traits<Iterator> will be an empty class. This is a
// conforming extension which allows some programs to compile and behave as
// the client expects instead of failing at compile time.

template <class _Iter> struct iterator_traits : __iterator_traits<_Iter, __has_iterator_category<_Iter>::value> {};

template<class _Tp>
struct iterator_traits<_Tp*>
{
typedef ptrdiff_t difference_type;
typedef typename remove_const<_Tp>::type value_type;
typedef _Tp* pointer;
typedef _Tp& reference;
typedef random_access_iterator_tag iterator_category;
};

template <class _Tp, class _Up, bool = __has_iterator_category<iterator_traits<_Tp> >::value>
struct __has_iterator_category_convertible_to : public integral_constant<bool, is_convertible<typename iterator_traits<_Tp>::iterator_category, _Up>::value>
{};

template <class _Tp, class _Up> struct __has_iterator_category_convertible_to<_Tp, _Up, false> : public false_type {};

template <class _Tp> struct __is_input_iterator : public __has_iterator_category_convertible_to<_Tp, input_iterator_tag> {};

template <class _Tp> struct __is_forward_iterator : public __has_iterator_category_convertible_to<_Tp, forward_iterator_tag> {};

template <class _Tp> struct __is_bidirectional_iterator : public __has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag> {};

template <class _Tp> struct __is_random_access_iterator : public __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag> {};

template <class _Tp> struct __is_exactly_input_iterator : public integral_constant<bool, __has_iterator_category_convertible_to<_Tp, input_iterator_tag>::value &&
!__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value>
{};

template<class _Category, class _Tp, class _Distance = ptrdiff_t, class _Pointer = _Tp*, class _Reference = _Tp&>
struct iterator
{
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
typedef _Category iterator_category;
};

}

Loading

0 comments on commit b5bebea

Please sign in to comment.