forked from enlightenment/efl
352 lines
10 KiB
C++
352 lines
10 KiB
C++
#ifndef EINA_JS_CONTAINER_HH
|
|
#define EINA_JS_CONTAINER_HH
|
|
|
|
#include <algorithm>
|
|
|
|
#include <eina_js_compatibility.hh>
|
|
#include <eina_js_get_value.hh>
|
|
#include <eina_js_get_value_from_c.hh>
|
|
|
|
struct _Elm_Calendar_Mark;
|
|
struct Elm_Gen_Item;
|
|
struct _Eina_Rectangle;
|
|
struct _Evas_Textblock_Rectangle;
|
|
struct _Elm_Map_Overlay;
|
|
|
|
namespace efl { namespace eina { namespace js {
|
|
|
|
namespace detail {
|
|
|
|
template <typename T>
|
|
eina_container_base* concat(T const& self, eina_container_base const& other)
|
|
{
|
|
T const& rhs = static_cast<T const&>(other);
|
|
typedef typename T::container_type container_type;
|
|
container_type container(self._container.begin(), self._container.end());
|
|
container.insert(container.end(), rhs._container.begin(), rhs._container.end());
|
|
return new T(container.release_native_handle());
|
|
}
|
|
|
|
template <typename T>
|
|
eina_container_base* slice(T const& self, std::int64_t i, std::int64_t j)
|
|
{
|
|
typedef typename T::container_type container_type;
|
|
container_type container(std::next(self._container.begin(), i), std::next(self._container.begin(), j));
|
|
return new T(container.release_native_handle());
|
|
}
|
|
|
|
// T, W from the container instantiation
|
|
template<typename T, typename W, typename C>
|
|
int push(v8::Isolate* isolate, C& self, v8::Local<v8::Value> v)
|
|
{
|
|
try
|
|
{
|
|
W value = container_wrap(get_value_from_javascript(v, isolate, "", value_tag<T>()));
|
|
self._container.push_back(value);
|
|
}
|
|
catch (std::logic_error const&)
|
|
{
|
|
return -1;
|
|
}
|
|
return self.size();
|
|
}
|
|
|
|
template<typename T, typename W, typename K, typename C>
|
|
v8::Local<v8::Value> pop(v8::Isolate* isolate, C& self)
|
|
{
|
|
|
|
if (self._container.empty())
|
|
return v8::Undefined(isolate);
|
|
|
|
auto value = eina::js::get_value_from_c(
|
|
eina::js::wrap_value<T>(eina::js::container_unwrap(self._container.back()), eina::js::value_tag<T>{})
|
|
, isolate
|
|
, K::class_name());
|
|
self._container.pop_back();
|
|
return value;
|
|
}
|
|
template<typename T, typename W, typename C>
|
|
v8::Local<v8::Value> set(v8::Isolate* isolate, C& self, std::size_t index, v8::Local<v8::Value> v)
|
|
{
|
|
using notag_type = typename remove_tag<T>::type;
|
|
try
|
|
{
|
|
W value = container_wrap(get_value_from_javascript(v, isolate, "", value_tag<T>()));
|
|
|
|
if (index >= self.size())
|
|
{
|
|
std::size_t items_to_add = index - self.size() + 1;
|
|
for (int i = items_to_add; i; i--)
|
|
{
|
|
self._container.push_back(container_wrap(notag_type{}));
|
|
}
|
|
}
|
|
|
|
auto v2 = std::next(self._container.begin(), index);
|
|
*v2 = value;
|
|
}
|
|
catch (std::logic_error const&)
|
|
{
|
|
return v8::Undefined(isolate);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
}
|
|
|
|
template <typename InputIterator, typename T>
|
|
inline InputIterator find_element(InputIterator first, InputIterator last, T const& value, typename std::enable_if<is_handable_by_value<T>::value>::type* = 0)
|
|
{
|
|
return std::find(first, last, value);
|
|
}
|
|
|
|
template <typename InputIterator, typename T>
|
|
inline InputIterator find_element(InputIterator first, InputIterator last, T const& value, typename std::enable_if<!is_handable_by_value<T>::value>::type* = 0)
|
|
{
|
|
return std::find_if(first, last, [&](T const& e){ return &e == &value; });
|
|
}
|
|
|
|
template <typename InputIterator>
|
|
inline InputIterator find_element(InputIterator first, InputIterator last, char * value)
|
|
{
|
|
return std::find_if(first, last, [=](char* e){ return strcmp(e, value) == 0; });
|
|
}
|
|
|
|
template <typename CharT, typename T>
|
|
inline void stream_element(std::basic_ostream<CharT>& s, T const& value, typename std::enable_if<is_handable_by_value<T>::value>::type* = 0)
|
|
{
|
|
s << value;
|
|
}
|
|
|
|
template <typename CharT, typename T>
|
|
inline void stream_element(std::basic_ostream<CharT>& s, T const& value, typename std::enable_if<!is_handable_by_value<T>::value>::type* = 0)
|
|
{
|
|
s << &value;
|
|
}
|
|
|
|
template <typename CharT>
|
|
inline void stream_element(std::basic_ostream<CharT>& s, Eina_Bool value)
|
|
{
|
|
s << (value ? "true" : "false");
|
|
}
|
|
|
|
template <typename C, typename T, typename K>
|
|
struct eina_container_common;
|
|
|
|
|
|
template <typename C, typename V, typename T, typename K, typename Enable = void>
|
|
struct eina_container_type_specific
|
|
: eina_container_base
|
|
{
|
|
v8::Local<v8::Value> get(v8::Isolate* isolate, std::size_t index) const
|
|
{
|
|
if(index >= this->size())
|
|
return v8::Undefined(isolate);
|
|
return eina::js::get_value_from_c(
|
|
eina::js::wrap_value<T>(eina::js::container_unwrap(*std::next(container_get().begin(), index)), eina::js::value_tag<T>{})
|
|
, isolate
|
|
, K::class_name());
|
|
}
|
|
int index_of(v8::Isolate* isolate, v8::Local<v8::Value> v) const
|
|
{
|
|
try
|
|
{
|
|
V value = container_wrap(get_value_from_javascript(
|
|
v, isolate, K::class_name(), eina::js::value_tag<T>{}, false));
|
|
typedef typename C::const_iterator iterator;
|
|
iterator first = container_get().cbegin()
|
|
, last = container_get().cend()
|
|
, found = find_element(first, last, value);
|
|
if(found == last)
|
|
return -1;
|
|
else
|
|
return std::distance(first, found);
|
|
}
|
|
catch (std::logic_error const&)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
int last_index_of(v8::Isolate* isolate, v8::Local<v8::Value> v) const
|
|
{
|
|
try
|
|
{
|
|
V value = container_wrap(get_value_from_javascript(
|
|
v, isolate, K::class_name(), eina::js::value_tag<T>{}, false));
|
|
auto last = container_get().crend()
|
|
, found = find_element(container_get().crbegin(), last, value);
|
|
if(found == last)
|
|
return -1;
|
|
else
|
|
return std::distance(container_get().cbegin(), found.base()) -1;
|
|
}
|
|
catch (std::logic_error const&)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
void* get_container_native_handle()
|
|
{
|
|
void const* h = container_get().native_handle();
|
|
return const_cast<void*>(h);
|
|
}
|
|
void const* get_container_native_handle() const
|
|
{
|
|
return container_get().native_handle();
|
|
}
|
|
C& container_get() { return static_cast<eina_container_common<C, T, K>&>(*this)._container; }
|
|
C const& container_get() const { return static_cast<eina_container_common<C, T, K>const&>(*this)._container; }
|
|
};
|
|
|
|
template <typename C, typename T, typename K>
|
|
struct eina_container_common : eina_container_type_specific<C, typename C::value_type, T, K>
|
|
{
|
|
eina_container_common() : _container() {}
|
|
eina_container_common(typename C::native_handle_type raw) : _container(raw) {}
|
|
|
|
std::size_t size() const { return _container.size(); }
|
|
v8::Local<v8::String> to_string(v8::Isolate* isolate) const
|
|
{
|
|
return join(isolate, compatibility_new<v8::String>(isolate, ","));
|
|
}
|
|
|
|
v8::Local<v8::String> join(v8::Isolate* isolate, v8::Local<v8::Value> separator_js) const
|
|
{
|
|
std::string separator = ",";
|
|
typedef typename container_type::const_iterator iterator;
|
|
std::stringstream s;
|
|
|
|
if (separator_js->IsString())
|
|
{
|
|
v8::String::Utf8Value str(separator_js);
|
|
if (*str)
|
|
{
|
|
separator = *str;
|
|
}
|
|
else
|
|
{
|
|
eina::js::compatibility_throw(
|
|
isolate, v8::Exception::TypeError(
|
|
eina::js::compatibility_new<v8::String>(isolate, "Invalid separator.")));
|
|
return compatibility_new<v8::String>(isolate, "");
|
|
}
|
|
}
|
|
else if (!separator_js->IsUndefined()) // Called join without arguments.
|
|
{
|
|
eina::js::compatibility_throw(
|
|
isolate, v8::Exception::TypeError(
|
|
eina::js::compatibility_new<v8::String>(isolate, "Separator must be a string.")));
|
|
return compatibility_new<v8::String>(isolate, "");
|
|
}
|
|
|
|
for(iterator first = _container.begin()
|
|
, last = _container.end()
|
|
, last_elem = std::next(last, -1); first != last; ++first)
|
|
{
|
|
stream_element(s, *first);
|
|
if(first != last_elem)
|
|
s << separator;
|
|
}
|
|
return compatibility_new<v8::String>(isolate, s.str().c_str());
|
|
}
|
|
|
|
// Default implementation of some methods
|
|
int push(v8::Isolate* isolate, v8::Local<v8::Value>)
|
|
{
|
|
eina::js::compatibility_throw
|
|
(isolate, v8::Exception::TypeError
|
|
(eina::js::compatibility_new<v8::String>(isolate, "Push method was not implemented.")));
|
|
return -1;
|
|
}
|
|
v8::Local<v8::Value> pop(v8::Isolate* isolate)
|
|
{
|
|
eina::js::compatibility_throw
|
|
(isolate, v8::Exception::TypeError
|
|
(eina::js::compatibility_new<v8::String>(isolate, "Pop method was not implemented.")));
|
|
return v8::Undefined(isolate);
|
|
}
|
|
v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t, v8::Local<v8::Value>)
|
|
{
|
|
eina::js::compatibility_throw
|
|
(isolate, v8::Exception::TypeError
|
|
(eina::js::compatibility_new<v8::String>(isolate, "Indexed attribution was not implemented.")));
|
|
return v8::Undefined(isolate);
|
|
}
|
|
C _container;
|
|
typedef C container_type;
|
|
};
|
|
|
|
|
|
// Specialization for problematic types
|
|
struct empty_container_base
|
|
: eina_container_base
|
|
{
|
|
empty_container_base() {}
|
|
virtual ~empty_container_base() {}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return 0;
|
|
}
|
|
eina_container_base* concat(eina_container_base const& ) const
|
|
{
|
|
return new empty_container_base;
|
|
}
|
|
eina_container_base* slice(std::int64_t , std::int64_t ) const
|
|
{
|
|
return new empty_container_base;
|
|
}
|
|
int index_of(v8::Isolate*, v8::Local<v8::Value>) const
|
|
{
|
|
return -1;
|
|
}
|
|
int last_index_of(v8::Isolate*, v8::Local<v8::Value>) const
|
|
{
|
|
return -1;
|
|
}
|
|
v8::Local<v8::Value> get(v8::Isolate* isolate, std::size_t) const
|
|
{
|
|
return v8::Undefined(isolate);
|
|
}
|
|
v8::Local<v8::Value> set(v8::Isolate* isolate, std::size_t, v8::Local<v8::Value>)
|
|
{
|
|
return v8::Undefined(isolate);
|
|
}
|
|
int push(v8::Isolate*, v8::Local<v8::Value>)
|
|
{
|
|
return -1;
|
|
}
|
|
v8::Local<v8::Value> pop(v8::Isolate* isolate)
|
|
{
|
|
return v8::Undefined(isolate);
|
|
}
|
|
v8::Local<v8::String> to_string(v8::Isolate* isolate) const
|
|
{
|
|
return compatibility_new<v8::String>(isolate, "");
|
|
}
|
|
v8::Local<v8::String> join(v8::Isolate* isolate, v8::Local<v8::Value>) const
|
|
{
|
|
return compatibility_new<v8::String>(isolate, "");
|
|
}
|
|
container_type get_container_type() const
|
|
{
|
|
throw std::runtime_error("get_container_type of container with unmanagable type");
|
|
return container_type_size;
|
|
}
|
|
void* get_container_native_handle()
|
|
{
|
|
return nullptr;
|
|
}
|
|
void const* get_container_native_handle() const
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
} } }
|
|
|
|
EAPI void eina_container_register(v8::Handle<v8::Object> exports, v8::Isolate* isolate);
|
|
|
|
#endif
|