From f279225a6300063c0bc6a47dedd3036ac72e89a6 Mon Sep 17 00:00:00 2001 From: Felipe Magno de Almeida Date: Tue, 25 Feb 2014 17:24:32 -0300 Subject: [PATCH] eina: add a C++ bindings to Eina @feature. The goal of this library is to make the life of C++ developers easier when having to manipulate Eina datatype by providing a layer to abstract those data type in C++. Check examples for now. Documentation will come soon, but we are pushing that rather sooner to get feedback on those bindings. As you will notice, this library is just composed of headers. There is no .so and we do think it is better this way. Reducing ABI and API stability issue for applications developers who are the primary target of this binding. Also please note that you will need to have C++11 to use this binding. Signed-off-by: Cedric Bail --- Makefile.am | 1 + configure.ac | 18 + m4/ax_cxx_compile_stdcxx_11.m4 | 133 +++++ pc/.gitignore | 1 + pc/eina-cxx.pc.in | 12 + src/Makefile.am | 3 + src/Makefile_Eina_Cxx.am | 61 ++ src/examples/eina_cxx/Makefile.am | 45 ++ src/examples/eina_cxx/eina_cxx_list_01.cc | 55 ++ src/examples/eina_cxx/eina_cxx_thread_01.cc | 32 ++ src/lib/eina_cxx/Eina.hh | 44 ++ src/lib/eina_cxx/eina_accessor.hh | 214 +++++++ src/lib/eina_cxx/eina_clone_allocators.hh | 69 +++ src/lib/eina_cxx/eina_error.hh | 105 ++++ src/lib/eina_cxx/eina_inarray.hh | 544 ++++++++++++++++++ src/lib/eina_cxx/eina_inlist.hh | 464 +++++++++++++++ src/lib/eina_cxx/eina_iterator.hh | 101 ++++ src/lib/eina_cxx/eina_lists_auxiliary.hh | 28 + src/lib/eina_cxx/eina_ptrarray.hh | 486 ++++++++++++++++ src/lib/eina_cxx/eina_ptrlist.hh | 495 ++++++++++++++++ src/lib/eina_cxx/eina_ref.hh | 26 + src/lib/eina_cxx/eina_stringshare.hh | 205 +++++++ src/lib/eina_cxx/eina_thread.hh | 356 ++++++++++++ src/lib/eina_cxx/eina_type_traits.hh | 51 ++ src/lib/eina_cxx/eina_value.hh | 371 ++++++++++++ src/tests/eina_cxx/eina_cxx_suite.cc | 125 ++++ src/tests/eina_cxx/eina_cxx_test_accessor.cc | 102 ++++ .../eina_cxx/eina_cxx_test_eina_value.cc | 191 ++++++ src/tests/eina_cxx/eina_cxx_test_error.cc | 72 +++ src/tests/eina_cxx/eina_cxx_test_inarray.cc | 388 +++++++++++++ src/tests/eina_cxx/eina_cxx_test_inlist.cc | 212 +++++++ src/tests/eina_cxx/eina_cxx_test_iterator.cc | 34 ++ src/tests/eina_cxx/eina_cxx_test_ptrarray.cc | 180 ++++++ src/tests/eina_cxx/eina_cxx_test_ptrlist.cc | 212 +++++++ .../eina_cxx/eina_cxx_test_stringshare.cc | 32 ++ src/tests/eina_cxx/eina_cxx_test_thread.cc | 127 ++++ 36 files changed, 5595 insertions(+) create mode 100644 m4/ax_cxx_compile_stdcxx_11.m4 create mode 100644 pc/eina-cxx.pc.in create mode 100644 src/Makefile_Eina_Cxx.am create mode 100644 src/examples/eina_cxx/Makefile.am create mode 100644 src/examples/eina_cxx/eina_cxx_list_01.cc create mode 100644 src/examples/eina_cxx/eina_cxx_thread_01.cc create mode 100644 src/lib/eina_cxx/Eina.hh create mode 100644 src/lib/eina_cxx/eina_accessor.hh create mode 100644 src/lib/eina_cxx/eina_clone_allocators.hh create mode 100644 src/lib/eina_cxx/eina_error.hh create mode 100644 src/lib/eina_cxx/eina_inarray.hh create mode 100644 src/lib/eina_cxx/eina_inlist.hh create mode 100644 src/lib/eina_cxx/eina_iterator.hh create mode 100644 src/lib/eina_cxx/eina_lists_auxiliary.hh create mode 100644 src/lib/eina_cxx/eina_ptrarray.hh create mode 100644 src/lib/eina_cxx/eina_ptrlist.hh create mode 100644 src/lib/eina_cxx/eina_ref.hh create mode 100644 src/lib/eina_cxx/eina_stringshare.hh create mode 100644 src/lib/eina_cxx/eina_thread.hh create mode 100644 src/lib/eina_cxx/eina_type_traits.hh create mode 100644 src/lib/eina_cxx/eina_value.hh create mode 100644 src/tests/eina_cxx/eina_cxx_suite.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_accessor.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_eina_value.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_error.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_inarray.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_inlist.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_iterator.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_ptrarray.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_ptrlist.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_stringshare.cc create mode 100644 src/tests/eina_cxx/eina_cxx_test_thread.cc diff --git a/Makefile.am b/Makefile.am index f4b62572a6..db28c44ec2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,6 +119,7 @@ endif pkgconfig_DATA += \ pc/eina.pc \ +pc/eina-cxx.pc \ pc/eo.pc \ pc/eet.pc \ pc/evas.pc \ diff --git a/configure.ac b/configure.ac index 8f4023e2de..6f95066c93 100644 --- a/configure.ac +++ b/configure.ac @@ -890,6 +890,21 @@ EFL_LIB_END([Eina]) #### End of Eina +#### Eina CXX +EFL_LIB_START([Eina_Cxx]) + +AX_CXX_COMPILE_STDCXX_11([ext]) +if test "x${HAVE_CXX11}" -a "x1"; then + have_cxx11="yes" +else + have_cxx11="no" +fi + +AM_CONDITIONAL([HAVE_CXX11], [test "x${have_cxx11}" -a "xyes"]) + +EFL_LIB_END([Eina_Cxx]) +#### End of Eina CXX + #### Eet EFL_LIB_START([Eet]) @@ -3927,6 +3942,7 @@ src/Makefile src/benchmarks/eina/Makefile src/benchmarks/eo/Makefile src/examples/eina/Makefile +src/examples/eina_cxx/Makefile src/examples/eet/Makefile src/examples/eo/Makefile src/examples/evas/Makefile @@ -3945,6 +3961,7 @@ spec/efl.spec pc/evil.pc pc/escape.pc pc/eina.pc +pc/eina-cxx.pc pc/eet.pc pc/eo.pc pc/evas-fb.pc @@ -4075,6 +4092,7 @@ echo " Threads.......: ${efl_have_threads} (${features_thread})" echo " Cryptography..: ${build_crypto}" echo " X11...........: ${with_x11}" echo " OpenGL........: ${with_opengl}" +echo " C++11.........: ${have_cxx11}" echo "Evas............: yes (${features_evas})" echo " Engines.......: ${features_evas_engine}" echo " Image Loaders.: ${features_evas_loader}" diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000000..af37acdb5c --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,133 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = static_cast(c); + + auto d = a; +]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11 -std=c++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) diff --git a/pc/.gitignore b/pc/.gitignore index b6178fb51b..1daef65f9c 100644 --- a/pc/.gitignore +++ b/pc/.gitignore @@ -24,6 +24,7 @@ /efreet-trash.pc /efreet.pc /eina.pc +/eina-cxx.pc /eio.pc /eldbus.pc /embryo.pc diff --git a/pc/eina-cxx.pc.in b/pc/eina-cxx.pc.in new file mode 100644 index 0000000000..c6571fa4ae --- /dev/null +++ b/pc/eina-cxx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Eina C++ +Description: A C++ binding for the Eina library +Requires.private: @requirements_pc_eina@ +Version: @VERSION@ +Libs: -L${libdir} -leina @requirements_public_libs_eina@ +Libs.private: @requirements_libs_eina@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eina-@VMAJ@ -I${includedir}/eina-@VMAJ@/eina -I${includedir}/eina_cxx-@VMAJ@ -I${includedir}/eina_cxx-@VMAJ@/eina_cxx diff --git a/src/Makefile.am b/src/Makefile.am index e797d57820..9abc8a919d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,6 +56,8 @@ include Makefile_Emotion.am include Makefile_Ethumb.am include Makefile_Ethumb_Client.am +include Makefile_Eina_Cxx.am + .PHONY: benchmark examples BENCHMARK_SUBDIRS = \ @@ -71,6 +73,7 @@ benchmark: all-am EXAMPLES_SUBDIRS = \ examples/eina \ +examples/eina_cxx \ examples/eo \ examples/eet \ examples/evas \ diff --git a/src/Makefile_Eina_Cxx.am b/src/Makefile_Eina_Cxx.am new file mode 100644 index 0000000000..fa4888da41 --- /dev/null +++ b/src/Makefile_Eina_Cxx.am @@ -0,0 +1,61 @@ + +### Library + +#lib_LTLIBRARIES += lib/eina/libeina.la + +installed_einacxxmainheadersdir = $(includedir)/eina_cxx-@VMAJ@ +dist_installed_einacxxmainheaders_DATA = \ +lib/eina_cxx/Eina.hh + +installed_einacxxheadersdir = $(includedir)/eina_cxx-@VMAJ@/eina_cxx +dist_installed_einacxxheaders_DATA = \ +lib/eina_cxx/eina_accessor.hh \ +lib/eina_cxx/eina_clone_allocators.hh \ +lib/eina_cxx/eina_error.hh \ +lib/eina_cxx/eina_inarray.hh \ +lib/eina_cxx/eina_inlist.hh \ +lib/eina_cxx/eina_iterator.hh \ +lib/eina_cxx/eina_lists_auxiliary.hh \ +lib/eina_cxx/eina_ptrarray.hh \ +lib/eina_cxx/eina_ptrlist.hh \ +lib/eina_cxx/eina_ref.hh \ +lib/eina_cxx/eina_stringshare.hh \ +lib/eina_cxx/eina_thread.hh \ +lib/eina_cxx/eina_type_traits.hh \ +lib/eina_cxx/eina_value.hh + +### Unit tests + +if EFL_ENABLE_TESTS +if HAVE_CXX11 + +check_PROGRAMS += tests/eina_cxx/eina_cxx_suite +TESTS += tests/eina_cxx/eina_cxx_suite + +tests_eina_cxx_eina_cxx_suite_SOURCES = \ +tests/eina_cxx/eina_cxx_suite.cc \ +tests/eina_cxx/eina_cxx_test_inlist.cc \ +tests/eina_cxx/eina_cxx_test_inarray.cc \ +tests/eina_cxx/eina_cxx_test_iterator.cc \ +tests/eina_cxx/eina_cxx_test_ptrarray.cc \ +tests/eina_cxx/eina_cxx_test_ptrlist.cc \ +tests/eina_cxx/eina_cxx_test_stringshare.cc \ +tests/eina_cxx/eina_cxx_test_error.cc \ +tests/eina_cxx/eina_cxx_test_accessor.cc \ +tests/eina_cxx/eina_cxx_test_thread.cc \ +tests/eina_cxx/eina_cxx_test_eina_value.cc + +tests_eina_cxx_eina_cxx_suite_CXXFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_builddir)/src/lib/eina_cxx \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eina_cxx\" \ +-DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)/src/tests/eina_cxx\" \ +-DTESTS_BUILD_DIR=PACKAGE_BUILD_DIR \ +@CHECK_CFLAGS@ \ +@EINA_CFLAGS@ +tests_eina_cxx_eina_cxx_suite_LDADD = @CHECK_LIBS@ @USE_EINA_LIBS@ +tests_eina_cxx_eina_cxx_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ + +endif +endif + diff --git a/src/examples/eina_cxx/Makefile.am b/src/examples/eina_cxx/Makefile.am new file mode 100644 index 0000000000..6f784b08a1 --- /dev/null +++ b/src/examples/eina_cxx/Makefile.am @@ -0,0 +1,45 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +-I. \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +-I$(top_srcdir)/src/lib/eina_cxx \ +-I$(top_builddir)/src/lib/eina_cxx + +LDADD = $(top_builddir)/src/lib/eina/libeina.la @EINA_LDFLAGS@ @USE_BOOST_SYSTEM_LIBS@ @USE_BOOST_SYSTEM_LDFLAGS@ +AM_CXXFLAGS = @USE_BOOST_CPPFLAGS@ + +SRCS = \ +eina_cxx_list_01.cc + +EXTRA_PROGRAMS = \ +eina_cxx_list_01 \ +eina_cxx_thread_01 + +eina_cxx_list_01_SOURCES = \ +eina_cxx_list_01.cc + +eina_cxx_thread_01_SOURCES = \ +eina_cxx_thread_01.cc + +EXTRA_DIST = $(DATA_FILES) + +examples: $(EXTRA_PROGRAMS) + +clean-local: + rm -f $(EXTRA_PROGRAMS) + +install-examples: + mkdir -p $(datadir)/eina/examples + $(install_sh_DATA) -c $(SRCS) $(DATA_FILES) $(datadir)/eina/examples + +uninstall-local: + for f in $(SRCS) $(DATA_FILES); do \ + rm -f $(datadir)/eina/examples/$$f ; \ + done + +if ALWAYS_BUILD_EXAMPLES +noinst_PROGRAMS = $(EXTRA_PROGRAMS) +endif diff --git a/src/examples/eina_cxx/eina_cxx_list_01.cc b/src/examples/eina_cxx/eina_cxx_list_01.cc new file mode 100644 index 0000000000..b451ef1553 --- /dev/null +++ b/src/examples/eina_cxx/eina_cxx_list_01.cc @@ -0,0 +1,55 @@ +//Compile with: +//gcc -g eina_list_01.c -o eina_list_01 `pkg-config --cflags --libs eina` + +#include +#include + +#include +#include + +#include + +template +I next(I i, std::size_t n = 1u) +{ + for(;n;--n) + ++i; +} + +int main(int argc, char **argv) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + + list.push_back("tigh"); + list.push_back("adar"); + list.push_back("baltar"); + list.push_back("roslin"); + + for(efl::eina::ptr_list::const_iterator + first = list.begin(), last = list.end() + ;first != last; ++first) + std::cout << *first << std::endl; + + efl::eina::ptr_list::iterator + iterator = ::next(list.begin(), 2u); + list.insert(iterator, "cain"); + + iterator = std::find(list.begin(), list.end(), "cain"); + assert(iterator != list.end() && ::next(iterator) != list.end()); + list.insert(::next(iterator), "zarek"); + + list.insert(list.begin(), "adama"); + + iterator = std::find(list.begin(), list.end(), "cain"); + assert(iterator != list.end()); + list.insert(iterator, "gaeta"); + + list.insert(::next(list.begin()), "lampkin"); + + for(efl::eina::ptr_list::const_iterator + first = list.begin(), last = list.end() + ;first != last; ++first) + std::cout << *first << std::endl; +} diff --git a/src/examples/eina_cxx/eina_cxx_thread_01.cc b/src/examples/eina_cxx/eina_cxx_thread_01.cc new file mode 100644 index 0000000000..6ce329f3e5 --- /dev/null +++ b/src/examples/eina_cxx/eina_cxx_thread_01.cc @@ -0,0 +1,32 @@ +//Compile with: +//gcc -g eina_list_01.c -o eina_list_01 `pkg-config --cflags --libs eina` + +#include +#include + +#include +#include + +#include + +namespace eina = efl::eina; + +void thread1(eina::mutex& m) +{ + +} + +int main(int argc, char **argv) +{ + eina::eina_init eina_init; + eina::eina_threads_init threads_init; + + eina::mutex m; + eina::condition_variable c; + + eina::unique_lock l(m); + + eina::thread thread1(&::thread1, eina::ref(m)); + + thread1.join(); +} diff --git a/src/lib/eina_cxx/Eina.hh b/src/lib/eina_cxx/Eina.hh new file mode 100644 index 0000000000..7e7e985c16 --- /dev/null +++ b/src/lib/eina_cxx/Eina.hh @@ -0,0 +1,44 @@ +#ifndef EINA_HH_ +#define EINA_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace efl { namespace eina { + +struct eina_init +{ + eina_init() + { + ::eina_init(); + } + ~eina_init() + { + ::eina_shutdown(); + } +}; + +struct eina_threads_init +{ + eina_threads_init() + { + ::eina_threads_init(); + } + ~eina_threads_init() + { + ::eina_threads_shutdown(); + } +}; + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_accessor.hh b/src/lib/eina_cxx/eina_accessor.hh new file mode 100644 index 0000000000..b389b31bf7 --- /dev/null +++ b/src/lib/eina_cxx/eina_accessor.hh @@ -0,0 +1,214 @@ +#ifndef EINA_ACCESSOR_HH_ +#define EINA_ACCESSOR_HH_ + +#include +#include + +#include +#include +#include +#include + +namespace efl { namespace eina { + +template +struct accessor +{ + typedef unsigned int key_type; + typedef T mapped_type; + typedef T value_type; + typedef std::size_t size_type; + + accessor() : _impl(0) {} + explicit accessor(Eina_Accessor* impl) + : _impl(impl) + { + assert(_impl != 0); + } + accessor(accessor const& other) + : _impl(eina_accessor_clone(other._impl)) + {} + accessor& operator=(accessor const& other) + { + eina_accessor_free(_impl); + _impl = eina_accessor_clone(other._impl); + if(!_impl) + throw eina::system_error(efl::eina::get_error_code(), "Error cloning accessor"); + return *this; + } + ~accessor() + { + eina_accessor_free(_impl); + } + + mapped_type& operator[](size_type i) const + { + assert(_impl != 0); + void* p; + if(!eina_accessor_data_get(_impl, i, &p)) + { + eina::error_code ec = efl::eina::get_error_code(); + throw eina::system_error(ec, "EFL Eina Error"); + } + return *static_cast(p); + } + + Eina_Accessor* native_handle() const; + + void swap(accessor& other) + { + std::swap(_impl, other._impl); + } +private: + typedef Eina_Accessor*(accessor::*unspecified_bool_type)() const; +public: + operator unspecified_bool_type() const + { + return native_handle() ? &accessor::native_handle : 0 ; + } +private: + Eina_Accessor* _impl; +}; + +template +void swap(accessor& lhs, accessor& rhs) +{ + lhs.swap(rhs); +} + +template +struct accessor_iterator +{ + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + + accessor_iterator(accessor const& a, unsigned int pos = 0u) + : _accessor(a), _index(pos) + {} + + accessor_iterator& operator+=(difference_type i) + { + _index += i; + return *this; + } + accessor_iterator& operator-=(difference_type i) + { + _index -= i; + return *this; + } + value_type& operator[](difference_type i) + { + return _accessor[_index + i]; + } + accessor_iterator& operator++() + { + ++_index; + return *this; + } + accessor_iterator& operator--() + { + --_index; + return *this; + } + accessor_iterator& operator++(int) + { + accessor_iterator tmp(*this); + ++*this; + return tmp; + } + accessor_iterator& operator--(int) + { + accessor_iterator tmp(*this); + --*this; + return tmp; + } + value_type& operator*() const + { + return _accessor[_index]; + } + pointer operator->() const + { + return &**this; + } + void swap(accessor_iterator& other) + { + std::swap(_index, other._index); + std::swap(_accessor, other._accessor); + } +private: + accessor _accessor; + unsigned int _index; + + template + friend bool operator==(accessor_iterator const& lhs, accessor_iterator const& rhs) + { + return lhs._index == rhs._index; + } + + template + friend typename accessor_iterator::difference_type + operator-(accessor_iterator const& lhs, accessor_iterator const& rhs) + { + return lhs._index - rhs._index; + } + + template + friend + accessor_iterator operator+(accessor_iterator lhs + , typename accessor_iterator::difference_type rhs) + { + lhs._index += rhs; + return lhs; + } + + template + friend + accessor_iterator operator+(typename accessor_iterator::difference_type lhs + , accessor_iterator rhs) + { + return rhs + lhs; + } + + template + friend bool operator<(accessor_iterator const& lhs, accessor_iterator const& rhs) + { + return lhs._index < rhs._index; + } + + template + friend bool operator<=(accessor_iterator const& lhs, accessor_iterator const& rhs) + { + return lhs._index <= rhs._index; + } +}; + +template +bool operator>=(accessor_iterator const& lhs, accessor_iterator const& rhs) +{ + return !(lhs < rhs); +} + +template +bool operator>(accessor_iterator const& lhs, accessor_iterator const& rhs) +{ + return !(lhs <= rhs); +} + +template +bool operator!=(accessor_iterator const& lhs, accessor_iterator const& rhs) +{ + return !(lhs == rhs); +} + +template +void swap(accessor_iterator& lhs, accessor_iterator& rhs) +{ + lhs.swap(rhs); +} + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_clone_allocators.hh b/src/lib/eina_cxx/eina_clone_allocators.hh new file mode 100644 index 0000000000..6f7aba49eb --- /dev/null +++ b/src/lib/eina_cxx/eina_clone_allocators.hh @@ -0,0 +1,69 @@ +#ifndef EINA_CLONE_ALLOCATORS_HH_ +#define EINA_CLONE_ALLOCATORS_HH_ + +#include + +namespace efl { namespace eina { + +struct heap_copy_allocator +{ + template + static T* allocate_clone(T const& v) + { + return new T(v); + } + + template + static void deallocate_clone(T* p) + { +#ifdef EFL_EINA_CXX11 + std::default_delete()(p); +#else + delete p; +#endif + } +}; + +struct heap_clone_allocator +{ + template + static T* allocate_clone(T const& v) + { + return new_clone(v); + } + template + static void deallocate_clone(T* p) + { + delete_clone(p); + } +}; + +struct view_clone_allocator +{ + template + static T* allocate_clone(T const& v) + { + return const_cast(&v); + } + template + static void deallocate_clone(T* p) + { + } +}; + +struct heap_no_copy_allocator +{ + template + static void deallocate_clone(T* p) + { +#ifdef EFL_EINA_CXX11 + std::default_delete()(p); +#else + delete p; +#endif + } +}; + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_error.hh b/src/lib/eina_cxx/eina_error.hh new file mode 100644 index 0000000000..1199e694b9 --- /dev/null +++ b/src/lib/eina_cxx/eina_error.hh @@ -0,0 +1,105 @@ +#ifndef _EINA_ERROR_HH +#define _EINA_ERROR_HH + +#include + +#include + +namespace efl { namespace eina { + +using std::errc; +using std::system_error; +using std::error_code; +using std::error_condition; +typedef std::error_category system_error_category; + +inline system_error_category const& get_generic_category() +{ + return ::std::generic_category(); +} +inline system_error_category const& get_system_category() +{ + return ::std::system_category(); +} + +enum error_type {}; + +struct error_category : system_error_category +{ + const char* name() const throw() + { + return "eina"; + } + + bool equivalent(int code, eina::error_condition const& condition) const throw() + { + return code == condition.value(); + } + + bool equivalent(eina::error_code const& code, int condition) const throw() + { + return code.value() == condition; + } + + std::string message(int condition) const + { + const char* e = ::eina_error_msg_get(condition); + return e? e : "::eina_error_msg_get returned NULL. No error message available"; + } +}; + +inline eina::system_error_category& eina_error_category() +{ + static error_category _error_category; + return _error_category; +} + +inline eina::error_code get_error_code() +{ + Eina_Error error = eina_error_get(); + if(error) + { + eina_error_set(0); + return eina::error_code(error, eina_error_category()); + } + else + return eina::error_code(); +} + +inline eina::error_condition get_error_condition() +{ + Eina_Error error = eina_error_get(); + if(error) + { + eina_error_set(0); + return eina::error_condition(error, eina_error_category()); + } + else + return eina::error_condition(); +} + +inline error_type get_error_code_enum() +{ + return static_cast( ::eina_error_get() ); +} + + +inline void throw_on_error() +{ + eina::error_code ec = get_error_code(); + if(ec) + { + throw eina::system_error(ec, "EFL Eina Error"); + } +} + +} } + +namespace std { + +template <> struct is_error_condition_enum< ::efl::eina::error_type> : true_type {}; +template <> struct is_error_code_enum< ::efl::eina::error_type> : true_type {}; + +} + +#endif diff --git a/src/lib/eina_cxx/eina_inarray.hh b/src/lib/eina_cxx/eina_inarray.hh new file mode 100644 index 0000000000..3619358bad --- /dev/null +++ b/src/lib/eina_cxx/eina_inarray.hh @@ -0,0 +1,544 @@ +#ifndef EINA_INARRAY_HH_ +#define EINA_INARRAY_HH_ + +#include +#include + +#include +#include +#include + +namespace efl { namespace eina { + +struct _inarray_common_base +{ + typedef std::size_t size_type; + + explicit _inarray_common_base(size_type member_size) + : _array( ::eina_inarray_new(member_size, 0) ) + { + } + ~_inarray_common_base() + { + ::eina_inarray_free(_array); + } + + size_type size() const + { + return ::eina_inarray_count(_array); + } + bool empty() const + { + return size() == 0u; + } + + Eina_Inarray* _array; +private: + _inarray_common_base(_inarray_common_base const& other); + _inarray_common_base& operator=(_inarray_common_base const& other); +}; + +template +class _pod_inarray : _inarray_common_base +{ + typedef _inarray_common_base _base_type; +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef T* pointer; + typedef T const* const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + using _base_type::size; + using _base_type::empty; + + _pod_inarray() : _base_type(sizeof(T)) + { + } + _pod_inarray(size_type n, value_type const& t) : _base_type(sizeof(T)) + { + while(n--) + push_back(t); + } + template + _pod_inarray(InputIterator i, InputIterator const& j + , typename eina::enable_if::value>::type* = 0) + : _base_type(sizeof(T)) + { + while(i != j) + { + push_back(*i); + ++i; + } + } + _pod_inarray(_pod_inarrayconst& other) + : _base_type(sizeof(T)) + { + insert(end(), other.begin(), other.end()); + } + ~_pod_inarray() + { + } + _pod_inarray& operator=(_pod_inarrayconst& other) + { + clear(); + insert(end(), other.begin(), other.end()); + return *this; + } + void clear() + { + ::eina_inarray_flush(_array); + } + void push_back(T const& value) + { + eina_inarray_push(_array, &value); + } + void pop_back() + { + eina_inarray_pop(_array); + } + iterator insert(iterator i, value_type const& t) + { + if(i != end()) + { + T* q = static_cast + ( ::eina_inarray_alloc_at(_array, i - begin(), 1u)); + std::memcpy(q, &t, sizeof(t)); + return q; + } + else + { + push_back(t); + return end()-1; + } + } + iterator insert(iterator i, size_t n, value_type const& t) + { + T* q; + if(i != end()) + { + q = static_cast + ( ::eina_inarray_alloc_at(_array, i - &_array->members, n)); + } + else + { + q = eina_inarray_grow(_array, n); + } + for(T* p = q; n; --n, ++p) + std::memcpy(p, &t, sizeof(t)); + return q; + } + template + iterator insert(iterator p, InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + size_type n = 0; + while(i != j) + { + p = insert(p, *i); + ++p; + ++i; + ++n; + } + return p - n; + } + iterator erase(iterator q) + { + ::eina_inarray_remove_at(_array, q - begin()); + return q; + } + iterator erase(iterator i, iterator j) + { + while(i != j) + { + erase(--j); + } + return i; + } + template + void assign(InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0); + void assign(size_type n, value_type const& t); + value_type& back() + { + assert(!empty()); + return *static_cast(eina_inarray_nth(_array, size()-1u)); + } + value_type const& back() const + { + return const_cast<_pod_inarray&>(*this).back(); + } + value_type& front() + { + assert(!empty()); + return *static_cast(eina_inarray_nth(_array, 0u)); + } + value_type const& front() const + { + return const_cast<_pod_inarray&>(*this).front(); + } + iterator begin() + { + return !_array->members ? 0 : static_cast(::eina_inarray_nth(_array, 0u)); + } + iterator end() + { + return !_array->members ? 0 : static_cast(::eina_inarray_nth(_array, size()-1)) + 1; + } + const_iterator begin() const + { + return const_cast< _pod_inarray&>(*this).begin(); + } + const_iterator end() const + { + return const_cast< _pod_inarray&>(*this).end(); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } + reverse_iterator rbegin() + { + return reverse_iterator(begin()); + } + reverse_iterator rend() + { + return reverse_iterator(end()); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + void swap(_pod_inarray& other) + { + std::swap(_array, other._array); + } + size_type max_size() const { return -1; } + + Eina_Inarray* native_handle() + { + return this->_array; + } + Eina_Inarray const* native_handle() const + { + return this->_array; + } +}; + +template +class _nonpod_inarray : _inarray_common_base +{ + typedef _inarray_common_base _base_type; +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef T* pointer; + typedef T const* const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + using _base_type::size; + using _base_type::empty; + + _nonpod_inarray() : _base_type(sizeof(T)) + { + } + _nonpod_inarray(size_type n, value_type const& t) : _base_type(sizeof(T)) + { + while(n--) + push_back(t); + } + template + _nonpod_inarray(InputIterator i, InputIterator const& j + , typename eina::enable_if::value>::type* = 0) + : _base_type(sizeof(T)) + { + while(i != j) + { + push_back(*i); + ++i; + } + } + _nonpod_inarray(_nonpod_inarrayconst& other) + : _base_type(sizeof(T)) + { + insert(end(), other.begin(), other.end()); + } + ~_nonpod_inarray() + { + for(T* first = static_cast(_array->members) + , *last = first + _array->len; first != last; ++first) + first->~T(); + } + _nonpod_inarray& operator=(_nonpod_inarrayconst& other) + { + clear(); + insert(end(), other.begin(), other.end()); + return *this; + } + void clear() + { + for(T* first = static_cast(_array->members) + , *last = first + _array->len; first != last; ++first) + first->~T(); + ::eina_inarray_flush(_array); + } + void push_back(T const& value) + { + insert(end(), 1u, value); + } + void pop_back() + { + T* elem = static_cast(_array->members) + _array->len - 1; + elem->~T(); + eina_inarray_pop(_array); + } + iterator insert(iterator i, value_type const& t) + { + return insert(i, 1u, t); + } + iterator insert(iterator i, size_t n, value_type const& t) + { + if(_array->max - _array->len >= n) + { + iterator end = static_cast(_array->members) + + _array->len + , last = end + n; + _array->len += n; + std::reverse_iterator + dest(last), src(end), src_end(i); + for(;src != src_end; ++src) + { + if(dest.base() <= end) + *dest++ = *src; + else + new (&*dest++) T(*src); + } + iterator j = i; + for(size_type i = 0;i != n;++i) + { + if(j < end) + *j = t; + else + new (&*j++) T(t); + } + } + else + { + size_type index = i - static_cast(_array->members); + + Eina_Inarray* old_array = eina_inarray_new(_array->member_size, 0); + *old_array = *_array; + _array->len = _array->max = 0; + _array->members = 0; + eina_inarray_resize(_array, old_array->len+n); + _array->len = old_array->len+n; + + iterator old_first = static_cast(old_array->members) + , first = begin() + , last = first + _array->len; + i = index + begin(); + + while(first != i) + { + new (&*first++) T(*old_first); + old_first++->~T(); + } + for(size_type i = 0;i != n;++i) + new (&*first++) T(t); + assert(last - first == _array->len - index - n); + while(first != last) + { + new (&*first++) T(*old_first); + old_first++->~T(); + } + } + return i; + } + template + iterator insert(iterator p, InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + size_type n = 0; + while(i != j) + { + p = insert(p, *i); + ++p; + ++i; + ++n; + } + return p - n; + } + iterator erase(iterator q) + { + return erase(q, q+1); + } + iterator erase(iterator i, iterator j) + { + iterator last = end(); + iterator k = i, l = j; + while(l != last) + *k++ = *l++; + while(k != last) + k++->~T(); + _array->len -= j - i; + + return i; + } + template + void assign(InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0); + void assign(size_type n, value_type const& t); + value_type& back() + { + assert(!empty()); + return *static_cast(eina_inarray_nth(_array, size()-1u)); + } + value_type const& back() const + { + return const_cast<_nonpod_inarray&>(*this).back(); + } + value_type& front() + { + assert(!empty()); + return *static_cast(eina_inarray_nth(_array, 0u)); + } + value_type const& front() const + { + return const_cast<_nonpod_inarray&>(*this).front(); + } + iterator begin() + { + return static_cast(_array->members); + } + iterator end() + { + return static_cast(_array->members) + _array->len; + } + const_iterator begin() const + { + return const_cast< _nonpod_inarray&>(*this).begin(); + } + const_iterator end() const + { + return const_cast< _nonpod_inarray&>(*this).end(); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } + reverse_iterator rbegin() + { + return reverse_iterator(begin()); + } + reverse_iterator rend() + { + return reverse_iterator(end()); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + void swap(_nonpod_inarray& other) + { + std::swap(_array, other._array); + } + size_type max_size() const { return -1; } + + Eina_Inarray* native_handle() + { + return this->_array; + } + Eina_Inarray const* native_handle() const + { + return this->_array; + } +}; + +template +class inarray : public eina::if_, _pod_inarray + , _nonpod_inarray >::type +{ + typedef typename eina::if_, _pod_inarray + , _nonpod_inarray >::type _base_type; +public: + inarray() : _base_type() {} + inarray(typename _base_type::size_type n, typename _base_type::value_type const& t) + : _base_type(n, t) {} + template + inarray(InputIterator i, InputIterator const& j + , typename eina::enable_if::value>::type* = 0) + : _base_type(i, j) + {} + +}; + +template +bool operator==(inarray const& lhs, inarray const& rhs) +{ + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator!=(inarray const& lhs, inarray const& rhs) +{ + return !(lhs == rhs); +} + +template +void swap(inarray& lhs, inarray& rhs) +{ + lhs.swap(rhs); +} + + + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_inlist.hh b/src/lib/eina_cxx/eina_inlist.hh new file mode 100644 index 0000000000..168b262c53 --- /dev/null +++ b/src/lib/eina_cxx/eina_inlist.hh @@ -0,0 +1,464 @@ +#ifndef EINA_INLIST_HH_ +#define EINA_INLIST_HH_ + +#include +#include +#include +#include + +#include + +namespace efl { namespace eina { + +template +struct _inlist_node +{ + EINA_INLIST; + T object; +}; + +template +_inlist_node* _get_node(Eina_Inlist* l) +{ + return static_cast<_inlist_node*>(static_cast(l)); +} + +template +_inlist_node const* _get_node(Eina_Inlist const* l) +{ + return const_cast(l); +} + +template +Eina_Inlist* _get_list(_inlist_node* n) +{ + if(n) + return EINA_INLIST_GET(n); + else + return 0; +} + +template +Eina_Inlist const* _get_list(_inlist_node const* n) +{ + return _get_list(const_cast<_inlist_node*>(n)); +} + +template +struct _inlist_iterator +{ + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + _inlist_iterator() {} + explicit _inlist_iterator(_inlist_node* list, _inlist_node* node) + : _list(list), _node(node) {} + + _inlist_iterator& operator++() + { + _node = _get_node(_node->__in_list.next); + return *this; + } + _inlist_iterator operator++(int) + { + _inlist_iterator tmp(*this); + ++*this; + return tmp; + } + _inlist_iterator& operator--() + { + if(_node) + _node = _get_node(_node->__in_list.prev); + else + _node = _get_node(_list->__in_list.last); + return *this; + } + _inlist_iterator operator--(int) + { + _inlist_iterator tmp(*this); + --*this; + return tmp; + } + T const& operator*() const + { + return _node->object; + } + T const* operator->() const + { + return &_node->object; + } + _inlist_node* native_handle() + { + return _node; + } + _inlist_node const* native_handle() const + { + return _node; + } +private: + _inlist_node* _list; + _inlist_node* _node; + + friend bool operator==(_inlist_iterator lhs, _inlist_iterator rhs) + { + return lhs._node == rhs._node; + } +}; + +template +bool operator!=(_inlist_iterator lhs, _inlist_iterator rhs) +{ + return !(lhs == rhs); +} + +template +struct _inlist_common_base +{ + typedef typename Allocator::template rebind<_inlist_node >::other node_allocator_type; + typedef Allocator allocator_type; + typedef _inlist_node node_type; + + _inlist_common_base(Allocator allocator) + : _impl(allocator) {} + _inlist_common_base() + {} + ~_inlist_common_base() + { + clear(); + } + + void clear() + { + Eina_Inlist* p = _impl._list; + Eina_Inlist* q; + while(p) + { + q = p->next; + + _inlist_node* node = _get_node(p); + node->~_inlist_node(); + get_node_allocator().deallocate(node, 1); + + p = q; + } + _impl._list = 0; + } + node_allocator_type& get_node_allocator() + { + return _impl; + } + + // For EBO + struct _inlist_impl : node_allocator_type + { + _inlist_impl(Allocator allocator) + : node_allocator_type(allocator), _list(0) + {} + _inlist_impl() : _list(0) {} + + Eina_Inlist* _list; + }; + + _inlist_impl _impl; +private: + _inlist_common_base(_inlist_common_base const& other); + _inlist_common_base& operator=(_inlist_common_base const& other); +}; + +template > +class inlist : protected _inlist_common_base +{ + typedef _inlist_common_base _base_type; + typedef typename _base_type::node_type _node_type; +public: + typedef typename _base_type::allocator_type allocator_type; + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef _inlist_iterator const_iterator; + typedef _inlist_iterator iterator; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + using _base_type::clear; + + inlist() {} + inlist(size_type n, value_type const& t) + { + while(n--) + push_back(t); + } + template + inlist(InputIterator i, InputIterator const& j + , allocator_type const& alloc = allocator_type() + , typename eina::enable_if::value>::type* = 0) + : _base_type(alloc) + { + while(i != j) + { + push_back(*i); + ++i; + } + } + inlist(inlistconst& other) + : _base_type() + { + insert(end(), other.begin(), other.end()); + } + inlist& operator=(inlistconst& other) + { + clear(); + insert(end(), other.begin(), other.end()); + return *this; + } + size_type size() const + { + return ::eina_inlist_count(this->_impl._list); + } + bool empty() const + { + return this->_impl._list == 0; + } + allocator_type get_allocator() const + { + return allocator_type(this->get_node_allocator()); + } + void push_back(T const& value) + { + _node_type* node ( this->get_node_allocator().allocate(1) ); + try + { + new (&node->object) T(value); + // eina_inlist_append can't fail + this->_impl._list = eina_inlist_append(this->_impl._list, _get_list(node)); + } + catch(...) + { + this->get_node_allocator().deallocate(node, 1); + throw; + } + } + void push_front(T const& value) + { + _node_type* node ( this->get_node_allocator().allocate(1) ); + try + { + new (&node->object) T(value); + // eina_inlist_prepend can't fail + this->_impl._list = eina_inlist_prepend(this->_impl._list, _get_list(node)); + } + catch(...) + { + this->get_node_allocator().deallocate(node, 1); + throw; + } + } + void pop_back() + { + this->_impl._list = eina_inlist_remove(this->_impl._list, this->_impl._list->last); + } + void pop_front() + { + this->_impl._list = eina_inlist_remove(this->_impl._list, this->_impl._list); + } + iterator insert(iterator i, value_type const& t) + { + _node_type* node ( this->get_node_allocator().allocate(1) ); + try + { + new (&node->object) T(t); + // eina_inlist_prepend_relative can't fail + this->_impl._list = _eina_inlist_prepend_relative + (this->_impl._list, _get_list(node) + , _get_list(i.native_handle())); + return iterator(_get_node(this->_impl._list), node); + } + catch(...) + { + this->get_node_allocator().deallocate(node, 1); + throw; + } + } + iterator insert(iterator i, size_t n, value_type const& t) + { + iterator r = i; + if(n--) + r = insert(i, t); + while(n--) + insert(i, t); + return r; + } + + template + iterator insert(iterator p, InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + iterator r = p; + if(i != j) + { + value_type v = *i; + r = insert(p, v); + ++i; + } + while(i != j) + { + insert(p, *i); + ++i; + } + return r; + } + + iterator erase(iterator q) + { + if(q.native_handle()) + { + iterator r(_get_node(this->_impl._list), _get_node(_get_list(q.native_handle())->next)); + this->_impl._list = eina_inlist_remove(this->_impl._list, _get_list(q.native_handle())); + return r; + } + else + return q; + } + + iterator erase(iterator i, iterator j) + { + while(i != j) + i = erase(i); + if(j.native_handle()) + return j; + else + return end(); + } + + template + void assign(InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + clear(); + insert(end(), i, j); + } + + void assign(size_type n, value_type const& t) + { + clear(); + insert(end(), n, t); + } + + value_type& back() + { + return _get_node(this->_impl._list->last)->object; + } + value_type const& back() const + { + return const_cast&>(*this).back(); + } + value_type& front() + { + return _get_node(this->_impl._list)->object; + } + value_type const& front() const + { + return const_cast&>(*this).front(); + } + const_iterator begin() const + { + return const_iterator(_get_node(this->_impl._list), _get_node(this->_impl._list)); + } + const_iterator end() const + { + return const_iterator(_get_node(this->_impl._list), 0); + } + iterator begin() + { + return iterator(_get_node(this->_impl._list), _get_node(this->_impl._list)); + } + iterator end() + { + return iterator(_get_node(this->_impl._list), 0); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } + reverse_iterator rbegin() + { + return reverse_iterator(begin()); + } + reverse_iterator rend() + { + return reverse_iterator(end()); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + void swap(inlist& other) + { + std::swap(this->_impl._list, other._impl._list); + } + size_type max_size() const { return -1; } + + Eina_Inlist* native_handle() + { + return this->_impl._list; + } + Eina_Inlist const* native_handle() const + { + return this->_impl._list; + } + eina::accessor accessor() const + { + return eina::accessor(eina_inlist_accessor_new(this->_impl._list)); + } + eina::accessor accessor() + { + return eina::accessor(eina_inlist_accessor_new(this->_impl._list)); + } +}; + +template +bool operator==(inlist const& lhs, inlist const& rhs) +{ + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator!=(inlist const& lhs, inlist const& rhs) +{ + return !(lhs == rhs); +} + +template +void swap(inlist& lhs, inlist& rhs) +{ + lhs.swap(rhs); +} + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_iterator.hh b/src/lib/eina_cxx/eina_iterator.hh new file mode 100644 index 0000000000..d10401c0c0 --- /dev/null +++ b/src/lib/eina_cxx/eina_iterator.hh @@ -0,0 +1,101 @@ +#ifndef EINA_ITERATOR_HH_ +#define EINA_ITERATOR_HH_ + +#include + +#include +#include + +namespace efl { namespace eina { + +template +struct _common_iterator_base +{ +private: + typedef _common_iterator_base self_type; +public: + typedef T const value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::ptrdiff_t difference_type; + typedef std::input_iterator_tag iterator_category; + + _common_iterator_base() {} + explicit _common_iterator_base(Eina_Iterator* iterator) + : _iterator(iterator) {} + ~_common_iterator_base() + { + if(_iterator) + eina_iterator_free(_iterator); + } + _common_iterator_base(self_type const& other) + : _iterator(other._iterator) + { + other._iterator = 0; + } + _common_iterator_base& operator=(self_type const& other) + { + _iterator = other._iterator; + other._iterator = 0; + return *this; + } + +protected: + mutable Eina_Iterator* _iterator; + + friend inline bool operator==(_common_iterator_base const& lhs, _common_iterator_base const& rhs) + { + return lhs._iterator == rhs._iterator; + } + friend inline bool operator!=(_common_iterator_base const& lhs, _common_iterator_base const& rhs) + { + return !(lhs == rhs); + } +}; + +template +struct iterator : _common_iterator_base +{ +private: + typedef _common_iterator_base base_type; + typename base_type::pointer _value; + typedef iterator self_type; +public: + typedef typename base_type::value_type value_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::reference reference; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::iterator_category iterator_category; + + explicit iterator(Eina_Iterator* iterator = 0) + : base_type(iterator) + { + if(this->_iterator) + ++*this; + } + self_type& operator++() + { + void* data; + Eina_Bool r = ::eina_iterator_next(this->_iterator, &data); + if(!r) + this->_iterator = 0; + _value = static_cast(data); + return *this; + } + self_type& operator++(int) + { + return ++**this; + } + value_type& operator*() const + { + return *_value; + } + pointer operator->() const + { + return _value; + } +}; + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_lists_auxiliary.hh b/src/lib/eina_cxx/eina_lists_auxiliary.hh new file mode 100644 index 0000000000..ebcbfd6016 --- /dev/null +++ b/src/lib/eina_cxx/eina_lists_auxiliary.hh @@ -0,0 +1,28 @@ +#ifndef _EINA_LISTS_AUXILIARY_HH +#define _EINA_LISTS_AUXILIARY_HH + +#include + +namespace efl { namespace eina { + +inline Eina_List* _eina_list_prepend_relative_list(Eina_List* list, const void* data, Eina_List* relative) EINA_ARG_NONNULL(2) +{ + if(relative) + return ::eina_list_prepend_relative_list(list, data, relative); + else + return ::eina_list_append(list, data); +} + +inline Eina_Inlist *_eina_inlist_prepend_relative(Eina_Inlist *in_list, + Eina_Inlist *in_item, + Eina_Inlist *in_relative) EINA_ARG_NONNULL(2) +{ + if(in_relative) + return ::eina_inlist_prepend_relative(in_list, in_item, in_relative); + else + return ::eina_inlist_append(in_list, in_item); +} + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_ptrarray.hh b/src/lib/eina_cxx/eina_ptrarray.hh new file mode 100644 index 0000000000..7b0e88b6ed --- /dev/null +++ b/src/lib/eina_cxx/eina_ptrarray.hh @@ -0,0 +1,486 @@ +#ifndef EINA_PTRARRAY_HH_ +#define EINA_PTRARRAY_HH_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace efl { namespace eina { + +struct _ptr_array_iterator_base +{ + _ptr_array_iterator_base() : _ptr(0) {} + _ptr_array_iterator_base(void** ptr) + : _ptr(ptr) + {} + + void** _ptr; +}; + +template +struct _ptr_array_iterator : protected _ptr_array_iterator_base +{ + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + _ptr_array_iterator() {} + explicit _ptr_array_iterator(void** ptr) + : _ptr_array_iterator_base(ptr) + + { + } + _ptr_array_iterator(_ptr_array_iterator::type> const& other) + : _ptr_array_iterator_base(static_cast<_ptr_array_iterator_base const&>(other)) + { + } + + _ptr_array_iterator& operator++() + { + ++_ptr; + return *this; + } + _ptr_array_iterator operator++(int) + { + _ptr_array_iterator tmp(*this); + ++*this; + return tmp; + } + _ptr_array_iterator& operator--() + { + --_ptr; + return *this; + } + _ptr_array_iterator operator--(int) + { + _ptr_array_iterator tmp(*this); + --*this; + return tmp; + } + reference operator*() const + { + return *static_cast(*_ptr); + } + pointer operator->() const + { + return &**this; + } + void** native_handle() const + { + return _ptr; + } + friend inline bool operator==(_ptr_array_iterator lhs, _ptr_array_iterator rhs) + { + return lhs._ptr == rhs._ptr; + } + friend inline bool operator!=(_ptr_array_iterator lhs, _ptr_array_iterator rhs) + { + return !(lhs == rhs); + } + friend inline _ptr_array_iterator operator+(_ptr_array_iterator lhs + , difference_type size) + { + lhs._ptr += size; + return lhs; + } + friend inline _ptr_array_iterator operator-(_ptr_array_iterator lhs + , difference_type size) + { + lhs._ptr -= size; + return lhs; + } + friend inline difference_type operator-(_ptr_array_iterator lhs + , _ptr_array_iterator rhs) + { + return lhs._ptr - rhs._ptr; + } +}; + +template +struct _ptr_array_common_base +{ + typedef CloneAllocator clone_allocator_type; + + _ptr_array_common_base(CloneAllocator clone_allocator) + : _impl(clone_allocator) + {} + _ptr_array_common_base(Eina_Array* _array) + : _impl(_array) + {} + _ptr_array_common_base() {} + + CloneAllocator& _get_clone_allocator() + { + return _impl; + } + CloneAllocator const& _get_clone_allocator() const + { + return _impl; + } + void _delete_clone(T const* p) + { + _get_clone_allocator().deallocate_clone(p); + } + T* _new_clone(T const& a) + { + return _get_clone_allocator().allocate_clone(a); + } + + struct _ptr_array_impl : CloneAllocator + { + _ptr_array_impl() : _array( ::eina_array_new(32u) ) {} + _ptr_array_impl(CloneAllocator allocator) + : clone_allocator_type(allocator), _array( ::eina_array_new(32u)) {} + + Eina_Array* _array; + }; + + _ptr_array_impl _impl; + +private: + _ptr_array_common_base(_ptr_array_common_base const& other); + _ptr_array_common_base& operator=(_ptr_array_common_base const& other); +}; + +template +class ptr_array : protected _ptr_array_common_base +{ + typedef _ptr_array_common_base _base_type; +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef _ptr_array_iterator const_iterator; + typedef _ptr_array_iterator iterator; + typedef T* pointer; + typedef T const* const_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef CloneAllocator clone_allocator_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + ptr_array() {} + ptr_array(size_type n, const_reference t) + { + while(n--) + push_back(t); + } + template + ptr_array(InputIterator i, InputIterator const& j + , clone_allocator_type const& alloc = clone_allocator_type() + , typename eina::enable_if::value>::type* = 0) + : _base_type(alloc) + { + while(i != j) + { + push_back(*i); + ++i; + } + } + ptr_array(ptr_array const& other) + : _base_type() + { + insert(end(), other.begin(), other.end()); + } + template + ptr_array(ptr_arrayconst& other) + : _base_type() + { + insert(end(), other.begin(), other.end()); + } + ~ptr_array() + { + clear(); + } + ptr_array& operator=(ptr_arrayconst& other) + { + clear(); + insert(end(), other.begin(), other.end()); + return *this; + } + + void clear() + { + for(iterator first = begin(), last = end(); first != last; ++first) + this->_delete_clone(&*first); + eina_array_flush(this->_impl._array); + } + std::size_t size() const + { + return eina_array_count(this->_impl._array); + } + bool empty() const + { + return size() == 0u; + } + clone_allocator_type get_clone_allocator() const + { + return clone_allocator_type(this->_get_clone_allocator()); + } + void push_back(const_reference a) + { + push_back(this->_new_clone(a)); + } + void push_back(pointer p) + { + std::auto_ptr p1(p); + push_back(p1); + } + void push_back(std::auto_ptr& p) + { + if(eina_array_push(this->_impl._array, p.get())) + p.release(); + else + throw std::bad_alloc(); + } + void pop_back() + { + eina_array_pop(this->_impl._array); + } + iterator insert(iterator i, value_type const& t) + { + return insert(i, this->_new_clone(t)); + } + iterator insert(iterator i, pointer pv) + { + std::auto_ptr p(pv); + return insert(i, p); + } + iterator insert(iterator i, std::auto_ptr& p) + { + std::size_t j + = i.native_handle() - this->_impl._array->data + , size = this->size(); + if(eina_array_push(this->_impl._array, p.get())) + { + if(size - j) + { + memmove( + this->_impl._array->data + j + 1 + , this->_impl._array->data + j + , (size - j)*sizeof(void*)); + // PRE: Q:[j, size) = [j+1, size+1) + pointer* data = static_cast + (static_cast(this->_impl._array->data)); + data[j] = p.get(); + } + p.release(); + return iterator(this->_impl._array->data + j); + } + else + throw std::bad_alloc(); + } + iterator insert(iterator i, size_t n, value_type const& t) + { + iterator r = i; + if(n--) + r = insert(i, t); + while(n--) + insert(i, t); + return r; + } + iterator insert(iterator i, size_t n, pointer p) + { + iterator r = i; + if(n--) + r = insert(i, p); + while(n--) + insert(i, this->_new_clone(p)); + return r; + } + template + iterator insert(iterator p, InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + size_type index = p.native_handle() - this->_impl._array->data; + while(i != j) + { + p = insert(p, this->_new_clone(*i)); + ++p; + ++i; + } + return iterator(this->_impl._array->data + index); + } + iterator erase(iterator q) + { + size_type size = this->size() + , i = q.native_handle() - this->_impl._array->data; + memmove(q.native_handle() + , q.native_handle() + 1 + , (size - i - 1)*sizeof(void*)); + eina_array_pop(this->_impl._array); + return q; + } + iterator erase(iterator i, iterator j) + { + size_type size = this->size() + , distance = std::distance(i, j); + memmove(i.native_handle() + , j.native_handle() + , (size - distance)*sizeof(void*)); + while(distance--) + eina_array_pop(this->_impl._array); + return i; + } + template + void assign(InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + clear(); + insert(end(), i, j); + } + void assign(size_type n, value_type const& t) + { + clear(); + insert(end(), n, t); + } + + value_type& back() + { + return *static_cast(this->_impl._array->data[size()-1]); + } + value_type const& back() const + { + return const_cast&>(*this).back(); + } + value_type& front() + { + return *static_cast(this->_impl._array->data[0]); + } + value_type const& front() const + { + return const_cast&>(*this).front(); + } + + const_reference operator[](size_type index) const + { + pointer data = static_cast + (this->_impl._array->data[index]); + return *data; + } + reference operator[](size_type index) + { + return const_cast + (const_castconst&>(*this)[index]); + } + + const_iterator begin() const + { + return const_iterator(this->_impl._array->data); + } + const_iterator end() const + { + return const_iterator(this->_impl._array->data + size()); + } + iterator begin() + { + return iterator(this->_impl._array->data); + } + iterator end() + { + return iterator(this->_impl._array->data + size()); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } + reverse_iterator rbegin() + { + return reverse_iterator(begin()); + } + reverse_iterator rend() + { + return reverse_iterator(end()); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + eina::iterator ibegin() + { + return eina::iterator( ::eina_array_iterator_new(this->_impl._array) ); + } + eina::iterator iend() + { + return eina::iterator(); + } + eina::iterator ibegin() const + { + return eina::iterator( ::eina_array_iterator_new(this->_impl._array) ); + } + eina::iterator iend() const + { + return eina::iterator(); + } + eina::iterator cibegin() const + { + return ibegin(); + } + eina::iterator ciend() const + { + return iend(); + } + void swap(ptr_array& other) + { + std::swap(this->_impl._array, other._impl._array); + } + size_type max_size() const { return -1; } + + Eina_Array* native_handle() + { + return this->_impl._array; + } + Eina_Array const* native_handle() const + { + return this->_impl._array; + } +}; + +template +bool operator==(ptr_array const& lhs, ptr_array const& rhs) +{ + return lhs.size() == rhs.size() + && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator!=(ptr_array const& lhs, ptr_array const& rhs) +{ + return !(lhs == rhs); +} + +template +void swap(ptr_array& lhs, ptr_array& rhs) +{ + lhs.swap(rhs); +} + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_ptrlist.hh b/src/lib/eina_cxx/eina_ptrlist.hh new file mode 100644 index 0000000000..b9132872b7 --- /dev/null +++ b/src/lib/eina_cxx/eina_ptrlist.hh @@ -0,0 +1,495 @@ +#ifndef EINA_LIST_HH_ +#define EINA_LIST_HH_ + +#include +#include +#include +#include +#include + +#include +#include + +namespace efl { namespace eina { + +struct _ptr_list_iterator_base +{ + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + _ptr_list_iterator_base() : _list(0) {} + _ptr_list_iterator_base(Eina_List* list, Eina_List* node) + : _list(list), _node(node) + {} + +protected: + Eina_List *_list, *_node; +}; + +template +struct _ptr_list_iterator : _ptr_list_iterator_base +{ + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + + _ptr_list_iterator() {} + explicit _ptr_list_iterator(Eina_List* list, Eina_List* node) + : _ptr_list_iterator_base(list, node) + { + } + _ptr_list_iterator(_ptr_list_iterator::type> const& other) + : _ptr_list_iterator_base(static_cast<_ptr_list_iterator_base const&>(other)) + { + } + + _ptr_list_iterator& operator++() + { + _node = eina_list_next(_node); + return *this; + } + _ptr_list_iterator operator++(int) + { + _ptr_list_iterator tmp(*this); + ++*this; + return tmp; + } + _ptr_list_iterator& operator--() + { + if(_node) + _node = eina_list_prev(_node); + else + _node = eina_list_last(_list); + return *this; + } + _ptr_list_iterator operator--(int) + { + _ptr_list_iterator tmp(*this); + --*this; + return tmp; + } + reference operator*() const + { + void* data = eina_list_data_get(_node); + return *static_cast(data); + } + pointer operator->() const + { + return &**this; + } + Eina_List* native_handle() + { + return _node; + } + Eina_List const* native_handle() const + { + return _node; + } + friend inline bool operator==(_ptr_list_iterator lhs, _ptr_list_iterator rhs) + { + return lhs._node == rhs._node; + } + friend inline bool operator!=(_ptr_list_iterator lhs, _ptr_list_iterator rhs) + { + return !(lhs == rhs); + } +}; + +template +struct _ptr_list_common_base +{ + typedef CloneAllocator clone_allocator_type; + + _ptr_list_common_base(CloneAllocator clone_allocator) + : _impl(clone_allocator) + {} + _ptr_list_common_base(Eina_List* _list) + : _impl(_list) + {} + _ptr_list_common_base() {} + + CloneAllocator& _get_clone_allocator() + { + return _impl; + } + CloneAllocator const& _get_clone_allocator() const + { + return _impl; + } + void _delete_clone(T const* p) + { + _get_clone_allocator().deallocate_clone(p); + } + T* _new_clone(T const& a) + { + return _get_clone_allocator().allocate_clone(a); + } + + struct _ptr_list_impl : CloneAllocator + { + _ptr_list_impl() : _list(0) {} + _ptr_list_impl(CloneAllocator allocator) + : clone_allocator_type(allocator), _list(0) {} + + Eina_List* _list; + }; + + _ptr_list_impl _impl; + +private: + _ptr_list_common_base(_ptr_list_common_base const& other); + _ptr_list_common_base& operator=(_ptr_list_common_base const& other); +}; + +template +class ptr_list : protected _ptr_list_common_base +{ + typedef _ptr_list_common_base _base_type; +public: + typedef T value_type; + typedef T& reference; + typedef T const& const_reference; + typedef _ptr_list_iterator const_iterator; + typedef _ptr_list_iterator iterator; + typedef T* pointer; + typedef T const* const_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef CloneAllocator clone_allocator_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + ptr_list() {} + ptr_list(size_type n, const_reference t) + { + while(n--) + push_back(t); + } + template + ptr_list(InputIterator i, InputIterator const& j + , clone_allocator_type const& alloc = clone_allocator_type() + , typename eina::enable_if::value>::type* = 0) + : _base_type(alloc) + { + while(i != j) + { + push_back(*i); + ++i; + } + } + ptr_list(ptr_list const& other) + : _base_type() + { + insert(end(), other.begin(), other.end()); + } + template + ptr_list(ptr_listconst& other) + : _base_type() + { + insert(end(), other.begin(), other.end()); + } + ~ptr_list() + { + clear(); + } + ptr_list& operator=(ptr_listconst& other) + { + clear(); + insert(end(), other.begin(), other.end()); + return *this; + } + + void clear() + { + for(iterator first = begin(), last = end(); first != last; ++first) + this->_delete_clone(&*first); + eina_list_free(this->_impl._list); + this->_impl._list = 0; + } + std::size_t size() const + { + return eina_list_count(this->_impl._list); + } + bool empty() const + { + return size() == 0u; + } + clone_allocator_type get_clone_allocator() const + { + return clone_allocator_type(this->_get_clone_allocator()); + } + void push_back(const_reference a) + { + push_back(this->_new_clone(a)); + } + void push_back(pointer p) + { + std::auto_ptr p1(p); + push_back(p1); + } + void push_back(std::auto_ptr& p) + { + Eina_List* new_list = eina_list_append(this->_impl._list, p.get()); + if(new_list) + { + this->_impl._list = new_list; + p.release(); + } + else + throw std::bad_alloc(); + } + void push_front(const_reference a) + { + push_front(this->new_clone(a)); + } + void push_front(pointer p) + { + std::auto_ptr p1(p); + push_front(p1); + } + void push_front(std::auto_ptr& p) + { + Eina_List* new_list = eina_list_prepend(this->_impl._list, p.get()); + if(new_list) + { + this->_impl._list = new_list; + p.release(); + } + else + throw std::bad_alloc(); + } + void pop_back() + { + this->_impl._list = eina_list_remove_list(this->_impl._list, eina_list_last(this->_impl._list)); + } + void pop_front() + { + this->_impl._list = eina_list_remove_list(this->_impl._list, this->_impl._list); + } + iterator insert(iterator i, value_type const& t) + { + return insert(i, this->_new_clone(t)); + } + iterator insert(iterator i, pointer pv) + { + std::auto_ptr p(pv); + return insert(i, p); + } + iterator insert(iterator i, std::auto_ptr& p) + { + this->_impl._list = _eina_list_prepend_relative_list + (this->_impl._list, p.get(), i.native_handle()); + if(this->_impl._list) + p.release(); + else + throw std::bad_alloc(); + return iterator(this->_impl._list + , i.native_handle() + ? ::eina_list_prev(i.native_handle()) + : ::eina_list_last(this->_impl._list) + ); + } + iterator insert(iterator i, size_t n, value_type const& t) + { + iterator r = i; + if(n--) + r = insert(i, t); + while(n--) + insert(i, t); + return r; + } + iterator insert(iterator i, size_t n, pointer p) + { + iterator r = i; + if(n--) + r = insert(i, p); + while(n--) + insert(i, this->_new_clone(p)); + return r; + } + template + iterator insert(iterator p, InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + iterator r = p; + if(i != j) + { + r = insert(p, *i); + ++i; + } + while(i != j) + { + insert(p, this->_new_clone(*i)); + ++i; + } + return r; + } + iterator erase(iterator q) + { + if(q.native_handle()) + { + iterator r(this->_impl._list, eina_list_next(q.native_handle())); + this->_impl._list = eina_list_remove_list(this->_impl._list, q.native_handle()); + return r; + } + else + return q; + } + iterator erase(iterator i, iterator j) + { + while(i != j) + i = erase(i); + if(j.native_handle()) + return j; + else + return end(); + } + template + void assign(InputIterator i, InputIterator j + , typename eina::enable_if::value>::type* = 0) + { + clear(); + insert(end(), i, j); + } + void assign(size_type n, value_type const& t) + { + clear(); + insert(end(), n, t); + } + + value_type& back() + { + return *static_cast(eina_list_data_get(eina_list_last(this->_impl._list))); + } + value_type const& back() const + { + return const_cast&>(*this).back(); + } + value_type& front() + { + return *static_cast(eina_list_data_get(this->_impl._list)); + } + value_type const& front() const + { + return const_cast&>(*this).front(); + } + + const_iterator begin() const + { + return const_iterator(this->_impl._list, this->_impl._list); + } + const_iterator end() const + { + return const_iterator(this->_impl._list, 0); + } + iterator begin() + { + return iterator(this->_impl._list, this->_impl._list); + } + iterator end() + { + return iterator(this->_impl._list, 0); + } + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } + reverse_iterator rbegin() + { + return reverse_iterator(begin()); + } + reverse_iterator rend() + { + return reverse_iterator(end()); + } + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + eina::iterator ibegin() + { + return eina::iterator( ::eina_list_iterator_new(this->_impl._list) ); + } + eina::iterator iend() + { + return eina::iterator(); + } + eina::iterator ibegin() const + { + return eina::iterator( ::eina_list_iterator_new(this->_impl._list) ); + } + eina::iterator iend() const + { + return eina::iterator(); + } + eina::iterator cibegin() const + { + return ibegin(); + } + eina::iterator ciend() const + { + return iend(); + } + void swap(ptr_list& other) + { + std::swap(this->_impl._list, other._impl._list); + } + size_type max_size() const { return -1; } + + Eina_List* native_handle() + { + return this->_impl._list; + } + Eina_List const* native_handle() const + { + return this->_impl._list; + } + eina::accessor accessor() const + { + return eina::accessor(eina_list_accessor_new(this->_impl._list)); + } + eina::accessor accessor() + { + return eina::accessor(eina_list_accessor_new(this->_impl._list)); + } +}; + +template +bool operator==(ptr_list const& lhs, ptr_list const& rhs) +{ + return lhs.size() == rhs.size() + && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator!=(ptr_list const& lhs, ptr_list const& rhs) +{ + return !(lhs == rhs); +} + +template +void swap(ptr_list& lhs, ptr_list& rhs) +{ + lhs.swap(rhs); +} + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_ref.hh b/src/lib/eina_cxx/eina_ref.hh new file mode 100644 index 0000000000..887a21f769 --- /dev/null +++ b/src/lib/eina_cxx/eina_ref.hh @@ -0,0 +1,26 @@ +#ifndef EINA_REF_HH +#define EINA_REF_HH + +#include + +namespace efl { namespace eina { + +using std::ref; +using std::cref; +using std::reference_wrapper; + +template +T& unref(T& t) +{ + return t; +} + +template +T& unref(reference_wrapper t) +{ + return t.get(); +} + +}} + +#endif diff --git a/src/lib/eina_cxx/eina_stringshare.hh b/src/lib/eina_cxx/eina_stringshare.hh new file mode 100644 index 0000000000..9638547c90 --- /dev/null +++ b/src/lib/eina_cxx/eina_stringshare.hh @@ -0,0 +1,205 @@ +#ifndef _EINA_STRINGSHARE_HH +#define _EINA_STRINGSHARE_HH + +#include +#include + +#include +#include + +namespace efl { namespace eina { + +struct steal_stringshare_ref_t {}; +steal_stringshare_ref_t const steal_stringshare_ref = {}; + +struct stringshare +{ + typedef char value_type; + typedef value_type& reference; + typedef value_type const& const_reference; + typedef value_type* pointer; + typedef value_type const* const_pointer; + typedef const_pointer const_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + + stringshare() + : _string( ::eina_stringshare_add("") ) + {} + stringshare(const char* str) + : _string( ::eina_stringshare_add(str) ) + { + } + stringshare(char* str, steal_stringshare_ref_t) + : _string( str ) + { + } + template + stringshare(InputIterator i, InputIterator j + , typename eina::enable_if + ::value + && !eina::is_contiguous_iterator::value + >::type* = 0) + { + std::string tmp; + while(i != j) + { + tmp.push_back(*i); + ++i; + } + _string = ::eina_stringshare_add(tmp.c_str()); + } + template + stringshare(ContiguousMemoryIterator i, ContiguousMemoryIterator j + , typename eina::enable_if + ::value>::type* = 0) + : _string( ::eina_stringshare_add_length(&*i, j - i) ) + { + } + + ~stringshare() + { + ::eina_stringshare_del(_string); + } + + stringshare(stringshare const& other) + : _string( eina_stringshare_ref(other._string) ) + {} + stringshare& operator=(stringshare const& other) + { + ::eina_stringshare_refplace(&_string, other._string); + return *this; + } + stringshare& operator=(const char* c_string) + { + ::eina_stringshare_replace(&_string, c_string); + return *this; + } + + const_iterator begin() const + { + return _string; + } + const_iterator end() const + { + return _string + size(); + } + + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } + + const_iterator cbegin() const + { + return begin(); + } + const_iterator cend() const + { + return end(); + } + const_reverse_iterator crbegin() const + { + return rbegin(); + } + const_reverse_iterator crend() const + { + return rend(); + } + + size_type size() const + { + return eina_stringshare_strlen(_string); + } + + size_type length() const + { + return size(); + } + size_type max_size() const + { + return -1; + } + bool empty() const + { + return _string[0] == 0; + } + const_reference operator[](size_type i) const + { + return _string[i]; + } + const_reference at(size_type i) const + { + if(i < size()) + return (*this)[i]; + else + throw std::out_of_range(""); + } + const_reference back() const + { + return _string[size()-1]; + } + const_reference front() const + { + return _string[0]; + } + + void swap(stringshare& other) + { + std::swap(_string, other._string); + } + + const char* c_str() const + { + return _string; + } + const char* data() const + { + return _string; + } + +private: + Eina_Stringshare* _string; +}; + +template <> +struct is_contiguous_iterator : true_type {}; + +inline bool operator==(stringshare const& lhs, stringshare const& rhs) +{ + return lhs.c_str() == rhs.c_str(); +} + +inline bool operator!=(stringshare const& lhs, stringshare const& rhs) +{ + return !(lhs == rhs); +} + +inline bool operator==(stringshare const& lhs, const char* rhs) +{ + return lhs.c_str() == rhs || std::strcmp(lhs.c_str(), rhs) == 0; +} + +inline bool operator!=(stringshare const& lhs, const char* rhs) +{ + return !(lhs == rhs); +} + +inline bool operator==(const char* lhs, stringshare const& rhs) +{ + return rhs == lhs; +} + +inline bool operator!=(const char* lhs, stringshare const& rhs) +{ + return !(lhs == rhs); +} + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_thread.hh b/src/lib/eina_cxx/eina_thread.hh new file mode 100644 index 0000000000..bb630a5d27 --- /dev/null +++ b/src/lib/eina_cxx/eina_thread.hh @@ -0,0 +1,356 @@ +#ifndef EINA_THREAD_HH_ +#define EINA_THREAD_HH_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFL_EINA_BOOST_MOVABLE_BUT_NOT_COPYABLE(x) +#define EFL_EINA_BOOST_RV_REF(x) x const& + +namespace efl { namespace eina { + +struct mutex +{ + typedef Eina_Lock* native_handle_type; + + mutex() + { + ::eina_lock_new(&_mutex); + } + ~mutex() + { + ::eina_lock_free(&_mutex); + } + void lock() + { + ::Eina_Lock_Result r = ::eina_lock_take(&_mutex); + switch(r) + { + case EINA_LOCK_SUCCEED: + return; + case EINA_LOCK_DEADLOCK: + throw system_error(error_code(int(eina::errc::resource_deadlock_would_occur) + , get_generic_category())); + default: + throw system_error(get_error_code()); + } + } + bool try_lock() + { + ::Eina_Lock_Result r = ::eina_lock_take_try(&_mutex); + switch(r) + { + case EINA_LOCK_SUCCEED: + return true; + case EINA_LOCK_FAIL: + return false; + case EINA_LOCK_DEADLOCK: + throw system_error(error_code(int(eina::errc::resource_deadlock_would_occur) + , get_generic_category())); + default: + throw system_error(get_error_code()); + } + } + void unlock() + { + ::Eina_Lock_Result r = ::eina_lock_release(&_mutex); + switch(r) + { + case EINA_LOCK_SUCCEED: + return; + case EINA_LOCK_DEADLOCK: + throw system_error(error_code(int(eina::errc::resource_deadlock_would_occur) + , get_generic_category())); + default: + throw system_error(get_error_code()); + } + } + void debug() + { + ::eina_lock_debug(&_mutex); + } + native_handle_type native_handle() + { + return &_mutex; + } +private: + mutex(mutex const&) = delete; + mutex& operator=(mutex const&) = delete; + + Eina_Lock _mutex; +}; + +using std::lock_guard; +using std::unique_lock; + +struct condition_variable +{ + typedef Eina_Condition* native_handle_type; + + condition_variable() + { + ::eina_condition_new(&_cond, _mutex.native_handle()); + } + ~condition_variable() + { + ::eina_condition_free(&_cond); + } + + void notify_one() + { + eina::unique_lock l(_mutex); + Eina_Bool r = eina_condition_signal(&_cond); + if(!r) + throw eina::system_error(eina::get_error_code()); + } + void notify_all() + { + eina::unique_lock l(_mutex); + Eina_Bool r = eina_condition_broadcast(&_cond); + if(!r) + throw eina::system_error(eina::get_error_code()); + } + template + void wait(Lock& lock) + { + eina::unique_lock l(_mutex); + lock.unlock(); + ::eina_condition_wait(&_cond); + lock.lock(); + } + template + void wait(Lock& lock, Predicate p) + { + while(!p()) + wait(lock); + } + native_handle_type native_handle() + { + return &_cond; + } +private: + condition_variable(condition_variable const&); + condition_variable& operator=(condition_variable const&); + + mutex _mutex; + Eina_Condition _cond; +}; + +struct thread_id +{ + thread_id() noexcept + : _raw(0u) + { + } + thread_id(Eina_Thread raw) + : _raw(raw) {} + friend inline bool operator==(thread_id lhs, thread_id rhs) + { + return lhs._raw == rhs._raw; + } + friend inline bool operator!=(thread_id lhs, thread_id rhs) + { + return lhs._raw != rhs._raw; + } + friend inline bool operator<(thread_id lhs, thread_id rhs) + { + return std::less()(lhs._raw, rhs._raw); + } +private: + Eina_Thread _raw; +}; + +inline bool operator<=(thread_id lhs, thread_id rhs) +{ + return (lhs == rhs) || lhs < rhs; +} +inline bool operator>(thread_id lhs, thread_id rhs) +{ + return !(lhs <= rhs); +} +inline bool operator>=(thread_id lhs, thread_id rhs) +{ + return !(lhs < rhs); +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& out, thread_id id) +{ + return out << id._raw; +} + +namespace _detail { + +struct arguments +{ + Eina_Lock mutex; + Eina_Condition condition; + bool started; + std::function function; +}; + +inline void* create_thread(void* data, Eina_Thread) +{ + arguments* args = static_cast(data); + + eina_lock_take(&args->mutex); + + std::function f = std::move(args->function); + + args->started = true; + eina_condition_signal(&args->condition); + eina_lock_release(&args->mutex); + + f(); + return 0; +} + +} + +struct thread +{ + typedef thread_id id; + typedef Eina_Thread native_handle_type; + + thread() noexcept + : _joinable(false), _raw(0u) + { + } + + template + explicit thread(F&& f, Args&&... args) + { + _detail::arguments arguments; + arguments.started = false; + arguments.function = std::bind(f, args...); + + _joinable = true; + Eina_Bool r = ::eina_lock_new(&arguments.mutex); + if(!r) throw eina::system_error(eina::get_error_code()); + r = ::eina_condition_new(&arguments.condition, &arguments.mutex); + if(!r) throw eina::system_error(eina::get_error_code()); + + if(!eina_thread_create + (&_raw, ::EINA_THREAD_NORMAL + , -1, &eina::_detail::create_thread, &arguments)) + { + eina_condition_free(&arguments.condition); + eina_lock_free(&arguments.mutex); + throw eina::system_error(eina::get_error_code()); + } + Eina_Lock_Result lr = ::eina_lock_take(&arguments.mutex); + if(lr != EINA_LOCK_SUCCEED) + throw eina::system_error(eina::get_error_code()); + while(!arguments.started) + { + r = eina_condition_wait(&arguments.condition); + if(!r) throw eina::system_error(eina::get_error_code()); + } + lr = eina_lock_release(&arguments.mutex); + if(lr != EINA_LOCK_SUCCEED) + throw eina::system_error(eina::get_error_code()); + + eina_condition_free(&arguments.condition); + eina_lock_free(&arguments.mutex); + } + + thread(thread&& other) + : _joinable(other._joinable), _raw(other._raw) + { + } + + thread& operator=(thread&& other) + { + _raw = other._raw; + _joinable = other._joinable; + return *this; + } + + ~thread() + { + assert(!joinable()); + } + + void swap(thread& other) noexcept + { + std::swap(_raw, other._raw); + } + bool joinable() const noexcept + { + return _joinable; + } + + void join() + { + assert(joinable()); + ::eina_thread_join(_raw); + _joinable = false; + } + + void detach() + { + assert(joinable()); + _joinable = false; + } + + id get_id() const noexcept + { + return id(_raw); + } + native_handle_type native_handle() const + { + return _raw; + } + + static unsigned hardware_concurrency() noexcept + { + return ::eina_cpu_count(); + } +private: + bool _joinable; + Eina_Thread _raw; +}; + +inline void swap(thread& lhs, thread& rhs) +{ + lhs.swap(rhs); +} + +namespace this_thread { + +inline thread::id get_id() +{ + return thread::id(eina_thread_self()); +} + +inline void yield() {} + +template +void sleep_until(std::chrono::time_pointconst& abs_time); + +template +void sleep_for(std::chrono::durationconst& rel_time); +} + +} } + +namespace std { + +template struct hash; +template <> +struct hash< ::efl::eina::thread_id> : hash +{}; + +} + +#endif diff --git a/src/lib/eina_cxx/eina_type_traits.hh b/src/lib/eina_cxx/eina_type_traits.hh new file mode 100644 index 0000000000..bd22457de3 --- /dev/null +++ b/src/lib/eina_cxx/eina_type_traits.hh @@ -0,0 +1,51 @@ +#ifndef _EINA_TYPE_TRAITS_HH +#define _EINA_TYPE_TRAITS_HH + +#include + +#include +#include + +namespace efl { namespace eina { + +using std::enable_if; +using std::is_integral; +using std::is_pod; +using std::is_const; +using std::remove_cv; +using std::true_type; +using std::false_type; +using std::remove_pointer; +using std::remove_reference; + +template +struct is_contiguous_iterator : false_type {}; +template <> +struct is_contiguous_iterator : true_type {}; +template <> +struct is_contiguous_iterator : true_type {}; +template <> +struct is_contiguous_iterator::const_iterator> : true_type {}; +template <> +struct is_contiguous_iterator::iterator> : true_type {}; + +template +struct if_c +{ + typedef T type; +}; + +template +struct if_c +{ + typedef F type; +}; + +template +struct if_ : if_c +{ +}; + +} } + +#endif diff --git a/src/lib/eina_cxx/eina_value.hh b/src/lib/eina_cxx/eina_value.hh new file mode 100644 index 0000000000..aee5b853c2 --- /dev/null +++ b/src/lib/eina_cxx/eina_value.hh @@ -0,0 +1,371 @@ +#ifndef _EFL_EINA_EINA_VALUE_HH +#define _EFL_EINA_EINA_VALUE_HH + +#include + +#include +#include + +namespace efl { namespace eina { + +template +struct _eina_value_traits_base; + +template +struct _eina_value_traits_aux; + +// Indirection for uint64_t. uint64_t can be a typedef for unsigned +// long, so we can't specialize on the same template +template <> +struct _eina_value_traits_aux +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_UINT64; + } +}; + +template +struct _eina_value_traits : _eina_value_traits_aux +{ +}; + +template +struct _eina_value_traits_base +{ + typedef T type; + + static ::Eina_Value* create() + { + return eina_value_new(_eina_value_traits::value_type()); + } + static void set_type( ::Eina_Value* v) + { + eina_value_setup(v, _eina_value_traits::value_type()); + } + static void set( ::Eina_Value* v, type c) + { + ::eina_value_set(v, c); + } + static type get( ::Eina_Value* v) + { + if(_eina_value_traits::value_type() == eina_value_type_get(v)) + { + type vv; + if(::eina_value_get(v, &vv)) + return vv; + else + throw eina::system_error(eina::get_error_code()); + } + else + throw eina::system_error(EINA_ERROR_VALUE_FAILED, eina::eina_error_category()); + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_UCHAR; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_USHORT; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_UINT; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_ULONG; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_CHAR; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_SHORT; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_INT; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_LONG; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_FLOAT; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_DOUBLE; + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_STRINGSHARE; + } + static void set( ::Eina_Value* v, type c) + { + ::eina_value_set(v, c.data()); + } + static type get( ::Eina_Value* v) + { + char* c_str; + ::eina_value_get(v, &c_str); + return stringshare(c_str, steal_stringshare_ref); + } +}; + +template <> +struct _eina_value_traits + : _eina_value_traits_base +{ + typedef typename _eina_value_traits_base::type type; + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_STRING; + } + static void set( ::Eina_Value* v, type c) + { + ::eina_value_set(v, c.c_str()); + } + static type get( ::Eina_Value* v) + { + char* c_str; + ::eina_value_get(v, &c_str); + std::string r(c_str); + ::free(c_str); + return r; + } +}; + +template +struct _eina_value_traits::value>::type> + : _eina_value_traits_base +{ + typedef typename _eina_value_traits_base::type type; + static ::Eina_Value_Type const* value_type() + { + return EINA_VALUE_TYPE_ARRAY; + } + static void set( ::Eina_Value* v, type c) + { + ::eina_value_set(v, c.c_str()); + } + static type get( ::Eina_Value* v) + { + char* c_str; + ::eina_value_get(v, &c_str); + std::string r(c_str); + ::free(c_str); + return r; + } +}; + +class eina_value +{ + template + void primitive_init(T v) + { + _raw = _eina_value_traits::create(); + _eina_value_traits::set(_raw, v); + } +public: + eina_value() + : _raw(_eina_value_traits::create()) + { + } + eina_value(char v) + { + primitive_init(v); + } + eina_value(short v) + { + primitive_init(v); + } + eina_value(int v) + { + primitive_init(v); + } + eina_value(long v) + { + primitive_init(v); + } + eina_value(unsigned char v) + { + primitive_init(v); + } + eina_value(unsigned short v) + { + primitive_init(v); + } + eina_value(unsigned int v) + { + primitive_init(v); + } + eina_value(unsigned long v) + { + primitive_init(v); + } + eina_value(float v) + { + primitive_init(v); + } + eina_value(double v) + { + primitive_init(v); + } + + ~eina_value() + { + eina_value_free(_raw); + } + + eina_value(eina_value const& other) + : _raw(_eina_value_traits::create()) + { + if(!eina_value_copy(const_cast(other._raw), _raw)) + throw eina::system_error(eina::get_error_code()); + } + eina_value& operator=(eina_value const& other) + { + eina_value_flush(_raw); + if(!eina_value_copy(const_cast(other._raw), _raw)) + throw eina::system_error(eina::get_error_code()); + return *this; + } + + void swap(eina_value& other) + { + std::swap(_raw, other._raw); + } + + typedef Eina_Value* native_handle_type; + native_handle_type native_handle() const + { + return _raw; + } + typedef Eina_Value_Type const* type_info_t; + type_info_t type_info() const + { + return ::eina_value_type_get(_raw); + } +private: + ::Eina_Value* _raw; + + template + friend T get(eina_value const& v) + { + return _eina_value_traits::get(v._raw); + } +}; + +inline void swap(eina_value& lhs, eina_value& rhs) +{ + lhs.swap(rhs); +} + +inline bool operator==(eina_value const& lhs, eina_value const& rhs) +{ + return lhs.type_info() == rhs.type_info() + && eina_value_compare(lhs.native_handle(), rhs.native_handle()) == 0; +} + +inline bool operator<(eina_value const& lhs, eina_value const& rhs) +{ + return std::less()(lhs.type_info(), rhs.type_info()) + || (lhs.type_info() == rhs.type_info() + && eina_value_compare(lhs.native_handle(), rhs.native_handle()) < 0); +} + +inline bool operator>(eina_value const& lhs, eina_value const& rhs) +{ + return std::less()(rhs.type_info(), lhs.type_info()) + || (rhs.type_info() == lhs.type_info() + && eina_value_compare(lhs.native_handle(), rhs.native_handle()) > 0); +} + +inline bool operator<=(eina_value const& lhs, eina_value const& rhs) +{ + return !(lhs > rhs); +} + +inline bool operator>=(eina_value const& lhs, eina_value const& rhs) +{ + return !(lhs < rhs); +} + +inline bool operator!=(eina_value const& lhs, eina_value const& rhs) +{ + return !(lhs == rhs); +} + +} } + +#endif diff --git a/src/tests/eina_cxx/eina_cxx_suite.cc b/src/tests/eina_cxx/eina_cxx_suite.cc new file mode 100644 index 0000000000..a9c20dc61a --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_suite.cc @@ -0,0 +1,125 @@ + +#include "Eina.hh" + +#include +#include + +#include + +void eina_test_inlist(TCase* tc); +void eina_test_inarray(TCase* tc); +void eina_test_ptrlist(TCase* tc); +void eina_test_ptrarray(TCase* tc); +void eina_test_iterator(TCase* tc); +void eina_test_stringshare(TCase* tc); +void eina_test_error(TCase* tc); +void eina_test_accessor(TCase* tc); +void eina_test_thread(TCase* tc); +void eina_test_eina_value(TCase* tc); + +typedef struct _Eina_Test_Case Eina_Test_Case; +struct _Eina_Test_Case +{ + const char *test_case; + void (*build)(TCase *tc); +}; + +static const Eina_Test_Case etc[] = { + { "Ptr_List", eina_test_ptrlist }, + { "Ptr_Array", eina_test_ptrarray }, + { "Inlist", eina_test_inlist }, + { "Inarray", eina_test_inarray }, + { "Iterator", eina_test_iterator }, + { "Stringshare", eina_test_stringshare }, + { "Error", eina_test_error }, + { "Accessor", eina_test_accessor }, + { "Thread", eina_test_thread }, + { "EinaValue", eina_test_eina_value }, + { NULL, NULL } +}; + +static void +_list_tests(void) +{ + const Eina_Test_Case *itr = etc; + fputs("Available Test Cases:\n", stderr); + for (; itr->test_case; itr++) + fprintf(stderr, "\t%s\n", itr->test_case); +} + +static Eina_Bool +_use_test(int argc, const char **argv, const char *test_case) +{ + if (argc < 1) + return 1; + + for (; argc > 0; argc--, argv++) + if (strcmp(test_case, *argv) == 0) + return 1; + + return 0; +} + +Suite * +eina_build_suite(int argc, const char **argv) +{ + TCase *tc; + Suite *s; + int i; + + s = suite_create("Eina"); + + for (i = 0; etc[i].test_case; ++i) + { + if (!_use_test(argc, argv, etc[i].test_case)) + continue; + + tc = tcase_create(etc[i].test_case); + tcase_set_timeout(tc, 0); + + etc[i].build(tc); + suite_add_tcase(s, tc); + } + + return s; +} + +int main(int argc, char* argv[]) +{ + Suite *s; + SRunner *sr; + int i, failed_count; + + for (i = 1; i < argc; i++) + if ((strcmp(argv[i], "-h") == 0) || + (strcmp(argv[i], "--help") == 0)) + { + fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", + argv[0]); + _list_tests(); + return 0; + } + else if ((strcmp(argv[i], "-l") == 0) || + (strcmp(argv[i], "--list") == 0)) + { + _list_tests(); + return 0; + } + + putenv(const_cast("EFL_RUN_IN_TREE=1")); + + s = eina_build_suite(argc - 1, (const char **)argv + 1); + sr = srunner_create(s); + + srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml"); + + eina_init(); + + srunner_run_all(sr, CK_ENV); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + eina_shutdown(); + + return (failed_count == 0) ? 0 : 255; +} diff --git a/src/tests/eina_cxx/eina_cxx_test_accessor.cc b/src/tests/eina_cxx/eina_cxx_test_accessor.cc new file mode 100644 index 0000000000..21ad5e09da --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_accessor.cc @@ -0,0 +1,102 @@ + +#include "Eina.hh" + +#include + +#include + +START_TEST(eina_cxx_accessor_indexing) +{ + efl::eina::ptr_list list; + list.push_back(new int(5)); + list.push_back(new int(10)); + list.push_back(new int(15)); + list.push_back(new int(20)); + + efl::eina::accessor accessor(list.accessor()); + + ck_assert(accessor[0] == 5); + ck_assert(accessor[1] == 10); + ck_assert(accessor[2] == 15); + ck_assert(accessor[3] == 20); +} +END_TEST + +START_TEST(eina_cxx_accessor_iterator) +{ + efl::eina::ptr_list list; + list.push_back(new int(5)); + list.push_back(new int(10)); + list.push_back(new int(15)); + list.push_back(new int(20)); + + std::size_t pos = 0u; + for(efl::eina::accessor_iterator first (list.accessor()) + , last (list.accessor(), list.size()); first != last; ++first, ++pos) + { + ck_assert(pos != 0u || *first == 5); + ck_assert(pos != 1u || *first == 10); + ck_assert(pos != 2u || *first == 15); + ck_assert(pos != 3u || *first == 20); + } +} +END_TEST + +START_TEST(eina_cxx_accessor_relops) +{ + efl::eina::ptr_list list; + list.push_back(new int(5)); + list.push_back(new int(10)); + list.push_back(new int(15)); + list.push_back(new int(20)); + + efl::eina::accessor_iterator first (list.accessor()) + , second(list.accessor(), 1u) + , third(list.accessor(), 2u) + , fourth(list.accessor(), 3u) + ; + ck_assert(!(first < first)); ck_assert(first < second); + ck_assert(first < third); ck_assert(first < fourth); + ck_assert(!(second < first)); ck_assert(!(second < second)); + ck_assert(second < third); ck_assert(second < fourth); + ck_assert(!(third < first)); ck_assert(!(third < second)); + ck_assert(!(third < third)); ck_assert(third < fourth); + ck_assert(!(fourth < first)); ck_assert(!(fourth < second)); + ck_assert(!(fourth < third)); ck_assert(!(fourth < fourth)); + + ck_assert(first <= first); ck_assert(first <= second); + ck_assert(first <= third); ck_assert(first <= fourth); + ck_assert(!(second <= first)); ck_assert(second <= second); + ck_assert(second <= third); ck_assert(second <= fourth); + ck_assert(!(third <= first)); ck_assert(!(third <= second)); + ck_assert(third <= third); ck_assert(third <= fourth); + ck_assert(!(fourth <= first)); ck_assert(!(fourth <= second)); + ck_assert(!(fourth <= third)); ck_assert(fourth <= fourth); + + ck_assert(!(first > first)); ck_assert(!(first > second)); + ck_assert(!(first > third)); ck_assert(!(first > fourth)); + ck_assert(second > first); ck_assert(!(second > second)); + ck_assert(!(second > third)); ck_assert(!(second > fourth)); + ck_assert(third > first); ck_assert(third > second); + ck_assert(!(third > third)); ck_assert(!(third > fourth)); + ck_assert(fourth > first); ck_assert(fourth > second); + ck_assert(fourth > third); ck_assert(!(fourth > fourth)); + + ck_assert(first >= first); ck_assert(!(first >= second)); + ck_assert(!(first >= third)); ck_assert(!(first >= fourth)); + ck_assert(second >= first); ck_assert(second >= second); + ck_assert(!(second >= third)); ck_assert(!(second >= fourth)); + ck_assert(third >= first); ck_assert(third >= second); + ck_assert(third >= third); ck_assert(!(third >= fourth)); + ck_assert(fourth >= first); ck_assert(fourth >= second); + ck_assert(fourth >= third); ck_assert(fourth >= fourth); +} +END_TEST + +void +eina_test_accessor(TCase* tc) +{ + tcase_add_test(tc, eina_cxx_accessor_indexing); + tcase_add_test(tc, eina_cxx_accessor_iterator); + tcase_add_test(tc, eina_cxx_accessor_relops); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_eina_value.cc b/src/tests/eina_cxx/eina_cxx_test_eina_value.cc new file mode 100644 index 0000000000..f9ddd2e6d4 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_eina_value.cc @@ -0,0 +1,191 @@ + +#include "Eina.hh" + +#include + +START_TEST(eina_cxx_eina_value_constructors) +{ + efl::eina::eina_init init; + + efl::eina::eina_value v; + + char c = 'c'; + efl::eina::eina_value vchar(c); + + short s = 5; + efl::eina::eina_value vshort(s); + + efl::eina::eina_value vint(5); + + efl::eina::eina_value vlong(5l); + + unsigned char uc = 'b'; + efl::eina::eina_value vuchar(uc); + + unsigned short us = 5; + efl::eina::eina_value vushort(us); + + efl::eina::eina_value vuint(5u); + + efl::eina::eina_value vulong(5ul); + + efl::eina::eina_value vu64(uint64_t(5ul)); + + efl::eina::eina_value vfloat(5.0f); + + efl::eina::eina_value vdouble(5.0); +} +END_TEST + +START_TEST(eina_cxx_eina_value_get) +{ + efl::eina::eina_init init; + + char c = 'c'; + efl::eina::eina_value vchar(c); + ck_assert(efl::eina::get(vchar) == 'c'); + + short s = 5; + efl::eina::eina_value vshort(s); + ck_assert(efl::eina::get(vshort) == 5); + + efl::eina::eina_value vint(6); + ck_assert(efl::eina::get(vint) == 6); + + efl::eina::eina_value vlong(7l); + ck_assert(efl::eina::get(vlong) == 7l); + + unsigned char uc = 'b'; + efl::eina::eina_value vuchar(uc); + ck_assert(efl::eina::get(vuchar) == 'b'); + + unsigned short us = 8; + efl::eina::eina_value vushort(us); + ck_assert(efl::eina::get(vushort) == 8); + + efl::eina::eina_value vuint(9u); + ck_assert(efl::eina::get(vuint) == 9u); + + efl::eina::eina_value vulong(10ul); + ck_assert(efl::eina::get(vulong) == 10ul); + + efl::eina::eina_value vu64((uint64_t)10ul); + ck_assert(efl::eina::get(vu64) == 10ul); + + efl::eina::eina_value vfloat(11.0f); + ck_assert(efl::eina::get(vfloat) == 11.0f); + + efl::eina::eina_value vdouble(12.0); + ck_assert(efl::eina::get(vdouble) == 12.0f); +} +END_TEST + +START_TEST(eina_cxx_eina_value_wrong_get) +{ + efl::eina::eina_init init; + + char c = 'c'; + efl::eina::eina_value vchar(c); + try + { + efl::eina::get(vchar); + std::abort(); + } + catch(efl::eina::system_error const&) + { + } +} +END_TEST + +START_TEST(eina_cxx_eina_value_comparison_operators) +{ + efl::eina::eina_init init; + + efl::eina::eina_value v; + + char c = 5; + efl::eina::eina_value vchar(c); + + short s = 5; + efl::eina::eina_value vshort(s); + + efl::eina::eina_value vint(5); + + efl::eina::eina_value vlong(5l); + + unsigned char uc = 5; + efl::eina::eina_value vuchar(uc); + + unsigned short us = 5; + efl::eina::eina_value vushort(us); + + efl::eina::eina_value vuint(5u); + + efl::eina::eina_value vulong(5ul); + + efl::eina::eina_value vu64((uint64_t)5ul); + + efl::eina::eina_value vfloat(5.0f); + + efl::eina::eina_value vdouble(5.0); + + ck_assert(vchar == vchar); + ck_assert(vshort == vshort); + ck_assert(vint == vint); + ck_assert(vlong == vlong); + ck_assert(vuchar == vuchar); + ck_assert(vushort == vushort); + ck_assert(vuint == vuint); + ck_assert(vulong == vulong); + ck_assert(vu64 == vu64); + ck_assert(vfloat == vfloat); + ck_assert(vdouble == vdouble); + + ck_assert(vchar != vshort); + ck_assert(vshort != vint); + ck_assert(vint != vlong); + ck_assert(vlong != vuchar); + ck_assert(vuchar != vushort); + ck_assert(vushort != vuint); + ck_assert(vuint != vulong); + ck_assert(vulong != vfloat); + ck_assert(vfloat != vdouble); + ck_assert(vdouble != vchar); + + ck_assert(vchar != vuchar); + ck_assert(vshort != vushort); + ck_assert(vint != vuint); + ck_assert(vlong != vulong); + ck_assert(vfloat != vdouble); + ck_assert(vdouble != vfloat); +} +END_TEST + +START_TEST(eina_cxx_eina_value_copying) +{ + char c = 5; + + efl::eina::eina_value vchar(c); + efl::eina::eina_value vchar2(vchar); + ck_assert(vchar == vchar2); + ck_assert(efl::eina::get(vchar) == 5); + ck_assert(efl::eina::get(vchar2) == 5); + + efl::eina::eina_value vint(10); + vchar = vint; + ck_assert(vchar != vchar2); + ck_assert(vint == vchar); + ck_assert(efl::eina::get(vchar) == 10); + ck_assert(efl::eina::get(vint) == 10); +} +END_TEST + +void +eina_test_eina_value(TCase* tc) +{ + tcase_add_test(tc, eina_cxx_eina_value_constructors); + tcase_add_test(tc, eina_cxx_eina_value_get); + tcase_add_test(tc, eina_cxx_eina_value_wrong_get); + tcase_add_test(tc, eina_cxx_eina_value_comparison_operators); + tcase_add_test(tc, eina_cxx_eina_value_copying); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_error.cc b/src/tests/eina_cxx/eina_cxx_test_error.cc new file mode 100644 index 0000000000..fb3a6aa7ae --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_error.cc @@ -0,0 +1,72 @@ + +#include "Eina.hh" + +#include + +Eina_Error my_error, my_error_2; + +START_TEST(eina_cxx_get_error) +{ + efl::eina::eina_init eina_init; + + my_error = ::eina_error_msg_static_register("Message 1"); + + ::eina_error_set(0); + + efl::eina::error_code ec1 = efl::eina::get_error_code(); + ck_assert(!ec1); + + ::eina_error_set(my_error); + + efl::eina::error_code ec2 = efl::eina::get_error_code(); + ck_assert(!!ec2); + + ck_assert(ec2.message() == "Message 1"); + + ::eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + + efl::eina::error_code ec3 = efl::eina::get_error_code(); + ck_assert(!!ec3); + + ck_assert(ec3.message() == "Out of memory"); +} +END_TEST + +START_TEST(eina_cxx_throw_on_error) +{ + efl::eina::eina_init eina_init; + + ::eina_error_set(my_error_2); + my_error_2 = ::eina_error_msg_static_register("Message 2"); + + ::eina_error_set(0); + try + { + efl::eina::throw_on_error(); + } + catch(std::exception const&) + { + std::abort(); + } + + ::eina_error_set(my_error_2); + try + { + efl::eina::throw_on_error(); + std::abort(); + } + catch(efl::eina::system_error const& e) + { + ck_assert(e.code().value() == my_error_2); + ck_assert(e.code().message() == "Message 2"); + ck_assert(!efl::eina::get_error_code()); + } +} +END_TEST + +void +eina_test_error(TCase *tc) +{ + tcase_add_test(tc, eina_cxx_get_error); + tcase_add_test(tc, eina_cxx_throw_on_error); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_inarray.cc b/src/tests/eina_cxx/eina_cxx_test_inarray.cc new file mode 100644 index 0000000000..d2e526c45b --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_inarray.cc @@ -0,0 +1,388 @@ + +#include "Eina.hh" + +#include +#include + +#include + +#include + +START_TEST(eina_cxx_inarray_pod_push_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::inarray array; + + array.push_back(5); + array.push_back(10); + array.push_back(15); + + int result[] = {5, 10, 15}; + + ck_assert(array.size() == 3); + ck_assert(std::equal(array.begin(), array.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_inarray_pod_pop_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::inarray array; + + array.push_back(5); + array.push_back(10); + array.push_back(15); + array.pop_back(); + + int result[] = {5, 10}; + + ck_assert(array.size() == 2); + ck_assert(std::equal(array.begin(), array.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_inarray_pod_insert) +{ + efl::eina::eina_init eina_init; + + efl::eina::inarray array; + + efl::eina::inarray::iterator it; + + it = array.insert(array.end(), 5); // first element + ck_assert(it != array.end()); + ++it; + ck_assert(it == array.end()); + + it = array.insert(array.end(), 10); // equivalent to push_back + ck_assert(it != array.end()); + ++it; + ck_assert(it == array.end()); + + it = array.insert(array.begin(), 15); // equivalent to push_front + ck_assert(it == array.begin()); + + it = array.end(); + --it; + array.insert(it, 20); // insert before the last element + + int result[] = {15, 5, 20, 10}; + + ck_assert(array.size() == 4); + ck_assert(std::equal(array.begin(), array.end(), result)); + + efl::eina::inarray array2; + it = array2.insert(array2.end(), array.begin(), array.end()); + ck_assert(it == array2.begin()); + ck_assert(array == array2); + + efl::eina::inarray array3; + array3.push_back(1); + it = array3.insert(array3.end(), array.begin(), array.end()); + ck_assert(array3.size() == 5); + ck_assert(array3.front() == 1); + it = array3.begin(); + ++it; + ck_assert(std::equal(it, array3.end(), array.begin())); + + efl::eina::inarray array4; + array4.push_back(1); + it = array4.insert(array4.begin(), array.begin(), array.end()); + ck_assert(array4.size() == 5); + ck_assert(array4.back() == 1); + ck_assert(std::equal(array.begin(), array.end(), array4.begin())); +} +END_TEST + +START_TEST(eina_cxx_inarray_pod_constructors) +{ + efl::eina::eina_init eina_init; + + efl::eina::inarray array1; + ck_assert(array1.empty()); + + efl::eina::inarray array2(10, 5); + ck_assert(array2.size() == 10); + ck_assert(std::find_if(array2.begin(), array2.end() + , std::not1(std::bind1st(std::equal_to(), 5))) == array2.end()); + + efl::eina::inarray array3(array2); + ck_assert(array2 == array3); + + efl::eina::inarray array4(array2.begin(), array2.end()); + ck_assert(array2 == array4); +} +END_TEST + +START_TEST(eina_cxx_inarray_pod_erase) +{ + efl::eina::eina_init eina_init; + + efl::eina::inarray array1; + array1.push_back(5); + array1.push_back(10); + array1.push_back(15); + array1.push_back(20); + array1.push_back(25); + array1.push_back(30); + + efl::eina::inarray::iterator it = array1.begin(), it2; + + it = array1.erase(it); + ck_assert(it == array1.begin()); + ck_assert(array1.size() == 5); + ck_assert(array1.front() == 10); + + it = array1.begin() + 1; + ck_assert(*it == 15); + it = array1.erase(it); + ck_assert(*it == 20); + ck_assert(array1.size() == 4); + + it = array1.end() - 1; + it = array1.erase(it); + ck_assert(it == array1.end()); + ck_assert(array1.size() == 3); + ck_assert(array1.back() == 25); + + it = array1.begin() + 1; + it2 = array1.end() - 1; + it = array1.erase(it, it2); + it2 = array1.end() -1; + ck_assert(it == it2); + ck_assert(array1.size() == 2); + ck_assert(array1.front() == 10); + ck_assert(array1.back() == 25); +} +END_TEST + +unsigned int constructors_called = 0u; +unsigned int destructors_called = 0u; + +struct non_pod +{ + non_pod(int x) + : x(new int(x)) + { + ++::constructors_called; + } + ~non_pod() + { + ++::destructors_called; + delete x; + } + non_pod(non_pod const& other) + { + ++::constructors_called; + x = new int(*other.x); + } + non_pod& operator=(non_pod const& other) + { + delete x; + x = new int(*other.x); + return *this; + } + + int* x; +}; + +bool operator==(non_pod lhs, non_pod rhs) +{ + return *lhs.x == *rhs.x; +} + +START_TEST(eina_cxx_inarray_nonpod_push_back) +{ + efl::eina::eina_init eina_init; + { + efl::eina::inarray array; + + array.push_back(5); + array.push_back(10); + array.push_back(15); + + int result[] = {5, 10, 15}; + + ck_assert(array.size() == 3); + ck_assert(std::equal(array.begin(), array.end(), result)); + } + std::cout << "constructors called " << ::constructors_called + << "\ndestructors called " << ::destructors_called << std::endl; + ck_assert(::constructors_called == ::destructors_called); + ::constructors_called = ::destructors_called = 0; +} +END_TEST + +START_TEST(eina_cxx_inarray_nonpod_pop_back) +{ + { + efl::eina::eina_init eina_init; + + efl::eina::inarray array; + + array.push_back(5); + array.push_back(10); + array.push_back(15); + array.pop_back(); + + int result[] = {5, 10}; + + ck_assert(array.size() == 2); + ck_assert(std::equal(array.begin(), array.end(), result)); + } + std::cout << "constructors called " << ::constructors_called + << "\ndestructors called " << ::destructors_called << std::endl; + ck_assert(::constructors_called == ::destructors_called); + ::constructors_called = ::destructors_called = 0; +} +END_TEST + +START_TEST(eina_cxx_inarray_nonpod_insert) +{ + { + efl::eina::eina_init eina_init; + + efl::eina::inarray array; + + efl::eina::inarray::iterator it; + + it = array.insert(array.end(), 5); // first element + ck_assert(it != array.end()); + ++it; + ck_assert(it == array.end()); + + it = array.insert(array.end(), 10); // equivalent to push_back + ck_assert(it != array.end()); + ++it; + ck_assert(it == array.end()); + + it = array.insert(array.begin(), 15); // equivalent to push_front + ck_assert(it == array.begin()); + + it = array.end(); + --it; + array.insert(it, 20); // insert before the last element + + int result[] = {15, 5, 20, 10}; + + ck_assert(array.size() == 4); + ck_assert(std::equal(array.begin(), array.end(), result)); + + efl::eina::inarray array2; + it = array2.insert(array2.end(), array.begin(), array.end()); + ck_assert(it == array2.begin()); + ck_assert(array == array2); + + efl::eina::inarray array3; + array3.push_back(1); + it = array3.insert(array3.end(), array.begin(), array.end()); + ck_assert(array3.size() == 5); + ck_assert(array3.front() == 1); + it = array3.begin(); + ++it; + ck_assert(std::equal(it, array3.end(), array.begin())); + + efl::eina::inarray array4; + array4.push_back(1); + it = array4.insert(array4.begin(), array.begin(), array.end()); + ck_assert(array4.size() == 5); + ck_assert(array4.back() == 1); + ck_assert(std::equal(array.begin(), array.end(), array4.begin())); + } + std::cout << "constructors called " << ::constructors_called + << "\ndestructors called " << ::destructors_called << std::endl; + ck_assert(::constructors_called == ::destructors_called); + ::constructors_called = ::destructors_called = 0; +} +END_TEST + +START_TEST(eina_cxx_inarray_nonpod_constructors) +{ + { + efl::eina::eina_init eina_init; + + efl::eina::inarray array1; + ck_assert(array1.empty()); + + efl::eina::inarray array2(10, 5); + ck_assert(array2.size() == 10); + ck_assert(std::find_if(array2.begin(), array2.end() + , std::not1(std::bind1st(std::equal_to(), 5))) == array2.end()); + + efl::eina::inarray array3(array2); + ck_assert(array2 == array3); + + efl::eina::inarray array4(array2.begin(), array2.end()); + ck_assert(array2 == array4); + } + std::cout << "constructors called " << ::constructors_called + << "\ndestructors called " << ::destructors_called << std::endl; + ck_assert(::constructors_called == ::destructors_called); + ::constructors_called = ::destructors_called = 0; +} +END_TEST + +START_TEST(eina_cxx_inarray_nonpod_erase) +{ + { + efl::eina::eina_init eina_init; + + efl::eina::inarray array1; + array1.push_back(5); + array1.push_back(10); + array1.push_back(15); + array1.push_back(20); + array1.push_back(25); + array1.push_back(30); + + efl::eina::inarray::iterator it = array1.begin(), it2; + + it = array1.erase(it); + ck_assert(it == array1.begin()); + ck_assert(array1.size() == 5); + ck_assert(array1.front() == 10); + + it = array1.begin() + 1; + ck_assert(*it == 15); + it = array1.erase(it); + ck_assert(*it == 20); + ck_assert(array1.size() == 4); + + it = array1.end() - 1; + it = array1.erase(it); + ck_assert(it == array1.end()); + ck_assert(array1.size() == 3); + ck_assert(array1.back() == 25); + + it = array1.begin() + 1; + it2 = array1.end() - 1; + it = array1.erase(it, it2); + it2 = array1.end() -1; + ck_assert(it == it2); + ck_assert(array1.size() == 2); + ck_assert(array1.front() == 10); + ck_assert(array1.back() == 25); + } + std::cout << "constructors called " << ::constructors_called + << "\ndestructors called " << ::destructors_called << std::endl; + ck_assert(::constructors_called == ::destructors_called); + ::constructors_called = ::destructors_called = 0; +} +END_TEST + +void +eina_test_inarray(TCase *tc) +{ + tcase_add_test(tc, eina_cxx_inarray_pod_push_back); + tcase_add_test(tc, eina_cxx_inarray_pod_pop_back); + tcase_add_test(tc, eina_cxx_inarray_pod_insert); + tcase_add_test(tc, eina_cxx_inarray_pod_erase); + tcase_add_test(tc, eina_cxx_inarray_pod_constructors); + tcase_add_test(tc, eina_cxx_inarray_nonpod_push_back); + tcase_add_test(tc, eina_cxx_inarray_nonpod_pop_back); + tcase_add_test(tc, eina_cxx_inarray_nonpod_insert); + tcase_add_test(tc, eina_cxx_inarray_nonpod_erase); + tcase_add_test(tc, eina_cxx_inarray_nonpod_constructors); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_inlist.cc b/src/tests/eina_cxx/eina_cxx_test_inlist.cc new file mode 100644 index 0000000000..09934f3f04 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_inlist.cc @@ -0,0 +1,212 @@ + +#include "Eina.hh" + +#include +#include + +#include + +START_TEST(eina_cxx_inlist_push_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list; + + list.push_back(5); + list.push_back(10); + list.push_back(15); + + int result[] = {5, 10, 15}; + + ck_assert(list.size() == 3); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_inlist_pop_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list; + + list.push_back(5); + list.push_back(10); + list.push_back(15); + list.pop_back(); + + int result[] = {5, 10}; + + ck_assert(list.size() == 2); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_inlist_push_front) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list; + + list.push_front(5); + list.push_front(10); + list.push_front(15); + + int result[] = {15, 10, 5}; + + ck_assert(list.size() == 3); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_inlist_pop_front) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list; + + list.push_front(5); + list.push_front(10); + list.push_front(15); + list.pop_front(); + + int result[] = {10, 5}; + + ck_assert(list.size() == 2); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_inlist_insert) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list; + + efl::eina::inlist::iterator it; + + it = list.insert(list.end(), 5); // first element + ck_assert(it != list.end()); + ++it; + ck_assert(it == list.end()); + + it = list.insert(list.end(), 10); // equivalent to push_back + ck_assert(it != list.end()); + ++it; + ck_assert(it == list.end()); + + it = list.insert(list.begin(), 15); // equivalent to push_front + ck_assert(it == list.begin()); + + it = list.end(); + --it; + list.insert(it, 20); // insert before the last element + + int result[] = {15, 5, 20, 10}; + + ck_assert(list.size() == 4); + ck_assert(std::equal(list.begin(), list.end(), result)); + + efl::eina::inlist list2; + it = list2.insert(list2.end(), list.begin(), list.end()); + ck_assert(it == list2.begin()); + ck_assert(list == list2); + + efl::eina::inlist list3; + list3.push_back(1); + it = list3.insert(list3.end(), list.begin(), list.end()); + ck_assert(list3.size() == 5); + ck_assert(list3.front() == 1); + it = list3.begin(); + ++it; + ck_assert(std::equal(it, list3.end(), list.begin())); + + efl::eina::inlist list4; + list4.push_back(1); + it = list4.insert(list4.begin(), list.begin(), list.end()); + ck_assert(list4.size() == 5); + ck_assert(list4.back() == 1); + ck_assert(std::equal(list.begin(), list.end(), list4.begin())); +} +END_TEST + +START_TEST(eina_cxx_inlist_constructors) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list1; + ck_assert(list1.empty()); + + efl::eina::inlist list2(10, 5); + ck_assert(list2.size() == 10); + ck_assert(std::find_if(list2.begin(), list2.end() + , std::not1(std::bind1st(std::equal_to(), 5))) == list2.end()); + + efl::eina::inlist list3(list2); + ck_assert(list2 == list3); + + efl::eina::inlist list4(list2.begin(), list2.end()); + ck_assert(list2 == list4); +} +END_TEST + +START_TEST(eina_cxx_inlist_erase) +{ + efl::eina::eina_init eina_init; + + efl::eina::inlist list1; + list1.push_back(5); + list1.push_back(10); + list1.push_back(15); + list1.push_back(20); + list1.push_back(25); + list1.push_back(30); + + efl::eina::inlist::iterator it = list1.begin(), it2; + + it = list1.erase(it); + ck_assert(it == list1.begin()); + ck_assert(list1.size() == 5); + ck_assert(list1.front() == 10); + + it = list1.begin(); + it2 = list1.begin(); + ++it; + ++it2; ++it2; + ck_assert(*it2 == 20); + it = list1.erase(it); + ck_assert(it == it2); + ck_assert(list1.size() == 4); + ck_assert(*it2 == 20); + + it = list1.end(); + --it; + it = list1.erase(it); + ck_assert(it == list1.end()); + ck_assert(list1.size() == 3); + ck_assert(list1.back() == 25); + + it = list1.begin(); + ++it; + it2 = list1.end(); + --it2; + it = list1.erase(it, it2); + it2 = list1.end(); + --it2; + ck_assert(it == it2); + ck_assert(list1.size() == 2); + ck_assert(list1.front() == 10); + ck_assert(list1.back() == 25); +} +END_TEST + +void +eina_test_inlist(TCase *tc) +{ + tcase_add_test(tc, eina_cxx_inlist_push_back); + tcase_add_test(tc, eina_cxx_inlist_push_front); + tcase_add_test(tc, eina_cxx_inlist_pop_back); + tcase_add_test(tc, eina_cxx_inlist_pop_front); + tcase_add_test(tc, eina_cxx_inlist_insert); + tcase_add_test(tc, eina_cxx_inlist_erase); + tcase_add_test(tc, eina_cxx_inlist_constructors); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_iterator.cc b/src/tests/eina_cxx/eina_cxx_test_iterator.cc new file mode 100644 index 0000000000..ee4b356a7b --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_iterator.cc @@ -0,0 +1,34 @@ + +#include "Eina.hh" + +#include + +#include + +START_TEST(eina_cxx_iterator_equal) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + ck_assert(list.size() == 0); + ck_assert(list.empty()); + + list.push_back(new int(5)); + list.push_back(new int(10)); + list.push_back(new int(15)); + list.push_back(new int(20)); + + efl::eina::iterator iterator = list.ibegin() + , last_iterator = list.iend(); + + int result[] = {5, 10, 15, 20}; + + ck_assert(std::equal(iterator, last_iterator, result)); +} +END_TEST + +void +eina_test_iterator(TCase *tc) +{ + tcase_add_test(tc, eina_cxx_iterator_equal); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_ptrarray.cc b/src/tests/eina_cxx/eina_cxx_test_ptrarray.cc new file mode 100644 index 0000000000..4e9a13b933 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_ptrarray.cc @@ -0,0 +1,180 @@ + +#include "Eina.hh" + +#include + +#include + +START_TEST(eina_cxx_ptrarray_push_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_array array; + + array.push_back(new int(5)); + array.push_back(new int(10)); + array.push_back(new int(15)); + + int result[] = {5, 10, 15}; + + ck_assert(array.size() == 3); + ck_assert(std::equal(array.begin(), array.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_ptrarray_pop_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_array array; + + array.push_back(new int(5)); + array.push_back(new int(10)); + array.push_back(new int(15)); + array.pop_back(); + + int result[] = {5, 10}; + + ck_assert(array.size() == 2); + ck_assert(std::equal(array.begin(), array.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_ptrarray_insert) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_array array; + ck_assert(std::distance(array.begin(), array.end()) == 0u); + + efl::eina::ptr_array::iterator it; + + it = array.insert(array.end(), new int(5)); // first element + ck_assert(it != array.end()); + ++it; + ck_assert(it == array.end()); + ck_assert(array[0] == 5); + ck_assert(std::distance(array.begin(), array.end()) == 1u); + + it = array.insert(array.end(), new int(10)); // equivalent to push_back + ck_assert(it != array.end()); + ++it; + ck_assert(it == array.end()); + ck_assert(array[0] == 5); + ck_assert(array[1] == 10); + ck_assert(std::distance(array.begin(), array.end()) == 2u); + + it = array.insert(array.begin(), new int(15)); // equivalent to push_front + ck_assert(it == array.begin()); + + ck_assert(array[1] == 5); + ck_assert(array[2] == 10); + ck_assert(array[0] == 15); + ck_assert(std::distance(array.begin(), array.end()) == 3u); + + array.insert(array.end() - 1, new int(20)); // insert before the last element + ck_assert(array[0] == 15); + ck_assert(array[1] == 5); + ck_assert(array[2] == 20); + ck_assert(array[3] == 10); + ck_assert(std::distance(array.begin(), array.end()) == 4u); + + int result[] = {15, 5, 20, 10}; + + ck_assert(array.size() == 4); + ck_assert(std::distance(array.begin(), array.end()) == 4u); + ck_assert(std::equal(array.begin(), array.end(), result)); + + efl::eina::ptr_array array2; + it = array2.insert(array2.end(), array.begin(), array.end()); + ck_assert(it == array2.begin()); + ck_assert(array == array2); + + + efl::eina::ptr_array array3; + array3.push_back(1); + it = array3.insert(array3.end(), array.begin(), array.end()); + ck_assert(array3.size() == 5); + ck_assert(array3.front() == 1); + it = array3.begin(); + ++it; + ck_assert(std::equal(it, array3.end(), array.begin())); + + efl::eina::ptr_array array4; + array4.push_back(1); + it = array4.insert(array4.begin(), array.begin(), array.end()); + ck_assert(array4.size() == 5); + ck_assert(array4.back() == 1); + ck_assert(std::equal(array.begin(), array.end(), array4.begin())); +} +END_TEST + +START_TEST(eina_cxx_ptrarray_constructors) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_array array1; + ck_assert(array1.empty()); + + efl::eina::ptr_array array2(10, 5); + ck_assert(array2.size() == 10); + ck_assert(std::find_if(array2.begin(), array2.end() + , std::not1(std::bind1st(std::equal_to(), 5))) == array2.end()); + + efl::eina::ptr_array array3(array2); + ck_assert(array2 == array3); + + efl::eina::ptr_array array4 + (array2.begin(), array2.end()); + ck_assert(array2 == array4); +} +END_TEST + +START_TEST(eina_cxx_ptrarray_erase) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_array array1; + array1.push_back(new int(5)); + array1.push_back(new int(10)); + array1.push_back(new int(15)); + array1.push_back(new int(20)); + array1.push_back(new int(25)); + array1.push_back(new int(30)); + + int result[] = {5, 10, 15, 20, 25, 30}; + ck_assert(std::equal(array1.begin(), array1.end(), result)); + + efl::eina::ptr_array::iterator it = array1.erase(array1.begin()); + ck_assert(it == array1.begin()); + ck_assert(array1.size() == 5); + ck_assert(array1.front() == 10); + + ck_assert(std::equal(array1.begin(), array1.end(), &result[1])); + + it = array1.erase(array1.begin() + 1); + ck_assert(*it == 20); + ck_assert(array1.size() == 4); + + it = array1.erase(array1.end() - 1); + ck_assert(it == array1.end()); + ck_assert(array1.size() == 3); + ck_assert(array1.back() == 25); + + it = array1.erase(array1.begin() + 1, array1.end() - 1); + ck_assert(it == array1.end() - 1); + ck_assert(array1.size() == 2); + ck_assert(array1.front() == 10); + ck_assert(array1.back() == 25); +} +END_TEST + +void +eina_test_ptrarray(TCase* tc) +{ + tcase_add_test(tc, eina_cxx_ptrarray_push_back); + tcase_add_test(tc, eina_cxx_ptrarray_pop_back); + tcase_add_test(tc, eina_cxx_ptrarray_insert); + tcase_add_test(tc, eina_cxx_ptrarray_constructors); + tcase_add_test(tc, eina_cxx_ptrarray_erase); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_ptrlist.cc b/src/tests/eina_cxx/eina_cxx_test_ptrlist.cc new file mode 100644 index 0000000000..c95adc3b21 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_ptrlist.cc @@ -0,0 +1,212 @@ + +#include "Eina.hh" + +#include + +#include + +START_TEST(eina_cxx_ptrlist_push_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + + list.push_back(new int(5)); + list.push_back(new int(10)); + list.push_back(new int(15)); + + int result[] = {5, 10, 15}; + + ck_assert(list.size() == 3); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_ptrlist_pop_back) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + + list.push_back(new int(5)); + list.push_back(new int(10)); + list.push_back(new int(15)); + list.pop_back(); + + int result[] = {5, 10}; + + ck_assert(list.size() == 2); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_ptrlist_push_front) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + + list.push_front(new int(5)); + list.push_front(new int(10)); + list.push_front(new int(15)); + + int result[] = {15, 10, 5}; + + ck_assert(list.size() == 3); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_ptrlist_pop_front) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + + list.push_front(new int(5)); + list.push_front(new int(10)); + list.push_front(new int(15)); + list.pop_front(); + + int result[] = {10, 5}; + + ck_assert(list.size() == 2); + ck_assert(std::equal(list.begin(), list.end(), result)); +} +END_TEST + +START_TEST(eina_cxx_ptrlist_insert) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list; + + efl::eina::ptr_list::iterator it; + + it = list.insert(list.end(), new int(5)); // first element + ck_assert(it != list.end()); + ++it; + ck_assert(it == list.end()); + + it = list.insert(list.end(), new int(10)); // equivalent to push_back + ck_assert(it != list.end()); + ++it; + ck_assert(it == list.end()); + + it = list.insert(list.begin(), new int(15)); // equivalent to push_front + ck_assert(it == list.begin()); + + it = list.end(); + --it; + list.insert(it, new int(20)); // insert before the last element + + int result[] = {15, 5, 20, 10}; + + ck_assert(list.size() == 4); + ck_assert(std::equal(list.begin(), list.end(), result)); + + efl::eina::ptr_list list2; + it = list2.insert(list2.end(), list.begin(), list.end()); + ck_assert(it == list2.begin()); + ck_assert(list == list2); + + efl::eina::ptr_list list3; + list3.push_back(1); + it = list3.insert(list3.end(), list.begin(), list.end()); + ck_assert(list3.size() == 5); + ck_assert(list3.front() == 1); + it = list3.begin(); + ++it; + ck_assert(std::equal(it, list3.end(), list.begin())); + + efl::eina::ptr_list list4; + list4.push_back(1); + it = list4.insert(list4.begin(), list.begin(), list.end()); + ck_assert(list4.size() == 5); + ck_assert(list4.back() == 1); + ck_assert(std::equal(list.begin(), list.end(), list4.begin())); +} +END_TEST + +START_TEST(eina_cxx_ptrlist_constructors) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list1; + ck_assert(list1.empty()); + + efl::eina::ptr_list list2(10, 5); + ck_assert(list2.size() == 10); + ck_assert(std::find_if(list2.begin(), list2.end() + , std::not1(std::bind1st(std::equal_to(), 5))) == list2.end()); + + efl::eina::ptr_list list3(list2); + ck_assert(list2 == list3); + + efl::eina::ptr_list list4 + (list2.begin(), list2.end()); + ck_assert(list2 == list4); +} +END_TEST + +START_TEST(eina_cxx_ptrlist_erase) +{ + efl::eina::eina_init eina_init; + + efl::eina::ptr_list list1; + list1.push_back(new int(5)); + list1.push_back(new int(10)); + list1.push_back(new int(15)); + list1.push_back(new int(20)); + list1.push_back(new int(25)); + list1.push_back(new int(30)); + + efl::eina::ptr_list::iterator it = list1.begin(), it2; + + it = list1.erase(it); + ck_assert(it == list1.begin()); + ck_assert(list1.size() == 5); + ck_assert(list1.front() == 10); + + it = list1.begin(); + it2 = list1.begin(); + ++it; + ++it2; ++it2; + ck_assert(*it2 == 20); + it = list1.erase(it); + ck_assert(it == it2); + ck_assert(list1.size() == 4); + ck_assert(*it2 == 20); + + it = list1.end(); + --it; + it = list1.erase(it); + ck_assert(it == list1.end()); + ck_assert(list1.size() == 3); + ck_assert(list1.back() == 25); + + it = list1.begin(); + ++it; + it2 = list1.end(); + --it2; + it = list1.erase(it, it2); + it2 = list1.end(); + --it2; + ck_assert(it == it2); + ck_assert(list1.size() == 2); + ck_assert(list1.front() == 10); + ck_assert(list1.back() == 25); +} +END_TEST + +void +eina_test_ptrlist(TCase* tc) +{ + tcase_add_test(tc, eina_cxx_ptrlist_push_back); + tcase_add_test(tc, eina_cxx_ptrlist_pop_back); + tcase_add_test(tc, eina_cxx_ptrlist_push_front); + tcase_add_test(tc, eina_cxx_ptrlist_pop_front); + tcase_add_test(tc, eina_cxx_ptrlist_insert); + tcase_add_test(tc, eina_cxx_ptrlist_constructors); + tcase_add_test(tc, eina_cxx_ptrlist_erase); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_stringshare.cc b/src/tests/eina_cxx/eina_cxx_test_stringshare.cc new file mode 100644 index 0000000000..1215431712 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_stringshare.cc @@ -0,0 +1,32 @@ + +#include "Eina.hh" + +#include +#include + +#include + +START_TEST(eina_cxx_stringshare_constructors) +{ + efl::eina::eina_init eina_init; + + efl::eina::stringshare string1; + ck_assert(string1.empty()); + + efl::eina::stringshare string2("string"); + ck_assert(string2.size() == 6); + ck_assert(string2 == "string"); + + efl::eina::stringshare string3(string2); + ck_assert(string2 == string3); + + efl::eina::stringshare string4(string3.begin(), string3.end()); + ck_assert(string2 == string3); +} +END_TEST + +void +eina_test_stringshare(TCase *tc) +{ + tcase_add_test(tc, eina_cxx_stringshare_constructors); +} diff --git a/src/tests/eina_cxx/eina_cxx_test_thread.cc b/src/tests/eina_cxx/eina_cxx_test_thread.cc new file mode 100644 index 0000000000..1a749359b2 --- /dev/null +++ b/src/tests/eina_cxx/eina_cxx_test_thread.cc @@ -0,0 +1,127 @@ + +#include "Eina.hh" + +#include + +#include + +bool no_args = false + , args_1 = false + , args_2 = false; + +void thread_no_args() +{ + no_args = true; +} + +struct test +{ + int x; +}; + +void thread_1_arg(int a0) +{ + args_1 = true; + ck_assert(a0 == 5); +} + +void thread_2_arg(int a0, test t) +{ + args_2 = true; + ck_assert(a0 == 5); + ck_assert(t.x == 10); +} + +START_TEST(eina_cxx_thread_constructors) +{ + efl::eina::eina_init init; + efl::eina::eina_threads_init threads_init; + { + efl::eina::thread default_constructed_thread; + ck_assert(default_constructed_thread.get_id() == efl::eina::thread::id()); + } + + { + efl::eina::thread thread_no_args(&::thread_no_args); + thread_no_args.join(); + ck_assert( ::no_args); + } + + { + efl::eina::thread thread_1_arg(&::thread_1_arg, 5); + thread_1_arg.join(); + ck_assert( ::args_1); + } + + { + test t = {10}; + efl::eina::thread thread_2_arg(&::thread_2_arg, 5, t); + thread_2_arg.join(); + ck_assert( ::args_2); + } +} +END_TEST + +START_TEST(eina_cxx_thread_mutexes) +{ + efl::eina::mutex m; + + { + efl::eina::unique_lock lock1(m); + ck_assert(lock1.owns_lock()); + + lock1.unlock(); + ck_assert(!lock1.owns_lock()); + + ck_assert(lock1.try_lock()); + ck_assert(lock1.owns_lock()); + lock1.unlock(); + + lock1.lock(); + ck_assert(lock1.owns_lock()); + } + + { + efl::eina::lock_guard lock1(m); + } +} +END_TEST + +bool b = false; + +void condition_thread(efl::eina::mutex& condition_mutex + , efl::eina::condition_variable& condition_condition) +{ + efl::eina::unique_lock l( condition_mutex); + b = true; + condition_condition.notify_one(); +} + +START_TEST(eina_cxx_thread_conditional) +{ + efl::eina::mutex m; + + efl::eina::mutex condition_mutex; + efl::eina::condition_variable condition_condition; + + efl::eina::unique_lock l( condition_mutex); + efl::eina::thread thread(&condition_thread, std::ref(condition_mutex), std::ref(condition_condition)); + + while(!b) + { + ck_assert(l.owns_lock()); + condition_condition.wait(l); + ck_assert(l.owns_lock()); + } + + thread.join(); +} +END_TEST + +void +eina_test_thread(TCase* tc) +{ + tcase_add_test(tc, eina_cxx_thread_constructors); + tcase_add_test(tc, eina_cxx_thread_mutexes); + tcase_add_test(tc, eina_cxx_thread_conditional); +}