#ifndef EINA_JS_CONTAINER_HH #define EINA_JS_CONTAINER_HH #include #include #include #include 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 eina_container_base* concat(T const& self, eina_container_base const& other) { T const& rhs = static_cast(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 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 int push(v8::Isolate* isolate, C& self, v8::Local v) { try { W value = container_wrap(get_value_from_javascript(v, isolate, "", value_tag())); self._container.push_back(value); } catch (std::logic_error const&) { return -1; } return self.size(); } template v8::Local 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(eina::js::container_unwrap(self._container.back()), eina::js::value_tag{}) , isolate , K::class_name()); self._container.pop_back(); return value; } template v8::Local set(v8::Isolate* isolate, C& self, std::size_t index, v8::Local v) { using notag_type = typename remove_tag::type; try { W value = container_wrap(get_value_from_javascript(v, isolate, "", value_tag())); 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 inline InputIterator find_element(InputIterator first, InputIterator last, T const& value, typename std::enable_if::value>::type* = 0) { return std::find(first, last, value); } template inline InputIterator find_element(InputIterator first, InputIterator last, T const& value, typename std::enable_if::value>::type* = 0) { return std::find_if(first, last, [&](T const& e){ return &e == &value; }); } template inline InputIterator find_element(InputIterator first, InputIterator last, char * value) { return std::find_if(first, last, [=](char* e){ return strcmp(e, value) == 0; }); } template inline void stream_element(std::basic_ostream& s, T const& value, typename std::enable_if::value>::type* = 0) { s << value; } template inline void stream_element(std::basic_ostream& s, T const& value, typename std::enable_if::value>::type* = 0) { s << &value; } template inline void stream_element(std::basic_ostream& s, Eina_Bool value) { s << (value ? "true" : "false"); } template struct eina_container_common; template struct eina_container_type_specific : eina_container_base { v8::Local 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(eina::js::container_unwrap(*std::next(container_get().begin(), index)), eina::js::value_tag{}) , isolate , K::class_name()); } int index_of(v8::Isolate* isolate, v8::Local v) const { try { V value = container_wrap(get_value_from_javascript( v, isolate, K::class_name(), eina::js::value_tag{}, 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 v) const { try { V value = container_wrap(get_value_from_javascript( v, isolate, K::class_name(), eina::js::value_tag{}, 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(h); } void const* get_container_native_handle() const { return container_get().native_handle(); } C& container_get() { return static_cast&>(*this)._container; } C const& container_get() const { return static_castconst&>(*this)._container; } }; template struct eina_container_common : eina_container_type_specific { 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 to_string(v8::Isolate* isolate) const { return join(isolate, compatibility_new(isolate, ",")); } v8::Local join(v8::Isolate* isolate, v8::Local 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(isolate, "Invalid separator."))); return compatibility_new(isolate, ""); } } else if (!separator_js->IsUndefined()) // Called join without arguments. { eina::js::compatibility_throw( isolate, v8::Exception::TypeError( eina::js::compatibility_new(isolate, "Separator must be a string."))); return compatibility_new(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(isolate, s.str().c_str()); } // Default implementation of some methods int push(v8::Isolate* isolate, v8::Local) { eina::js::compatibility_throw (isolate, v8::Exception::TypeError (eina::js::compatibility_new(isolate, "Push method was not implemented."))); return -1; } v8::Local pop(v8::Isolate* isolate) { eina::js::compatibility_throw (isolate, v8::Exception::TypeError (eina::js::compatibility_new(isolate, "Pop method was not implemented."))); return v8::Undefined(isolate); } v8::Local set(v8::Isolate* isolate, std::size_t, v8::Local) { eina::js::compatibility_throw (isolate, v8::Exception::TypeError (eina::js::compatibility_new(isolate, "Indexed attribution was not implemented."))); return v8::Undefined(isolate); } typename C::native_handle_type release_native_handle() { return _container.release_native_handle(); } 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) const { return -1; } int last_index_of(v8::Isolate*, v8::Local) const { return -1; } v8::Local get(v8::Isolate* isolate, std::size_t) const { return v8::Undefined(isolate); } v8::Local set(v8::Isolate* isolate, std::size_t, v8::Local) { return v8::Undefined(isolate); } int push(v8::Isolate*, v8::Local) { return -1; } v8::Local pop(v8::Isolate* isolate) { return v8::Undefined(isolate); } v8::Local to_string(v8::Isolate* isolate) const { return compatibility_new(isolate, ""); } v8::Local join(v8::Isolate* isolate, v8::Local) const { return compatibility_new(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 exports, v8::Isolate* isolate); #endif