diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index a1163291bb..f2a5762836 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am @@ -99,7 +99,9 @@ lib/eina/eina_inline_vector.x \ lib/eina/eina_promise.h \ lib/eina/eina_bezier.h \ lib/eina/eina_safepointer.h \ -lib/eina/eina_inline_safepointer.x +lib/eina/eina_inline_safepointer.x \ +lib/eina/eina_slice.h \ +lib/eina/eina_inline_slice.x lib_eina_libeina_la_SOURCES = \ lib/eina/eina_abi.c \ @@ -330,7 +332,8 @@ tests/eina/eina_test_quaternion.c \ tests/eina/eina_test_vector.c \ tests/eina/eina_test_promise.c \ tests/eina/eina_test_bezier.c \ -tests/eina/eina_test_safepointer.c +tests/eina/eina_test_safepointer.c \ +tests/eina/eina_test_slice.c tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -DTESTS_WD=\"`pwd`\" \ diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index e57660e233..f57cc624f5 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -271,6 +271,7 @@ extern "C" { #include #include #include +#include #undef EAPI #define EAPI diff --git a/src/lib/eina/eina_inline_slice.x b/src/lib/eina/eina_inline_slice.x new file mode 100644 index 0000000000..27cca3708f --- /dev/null +++ b/src/lib/eina/eina_inline_slice.x @@ -0,0 +1,232 @@ +/* EINA - EFL data type library + * Copyright (C) 2016 ProFUSION embedded systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifndef _EINA_INLINE_SLICE_H +#define _EINA_INLINE_SLICE_H + +static inline Eina_Slice +eina_rw_slice_slice_get(const Eina_Rw_Slice rw_slice) +{ + Eina_Slice ret; + ret.len = rw_slice.len; + ret.mem = rw_slice.mem; + return ret; +} + +static inline Eina_Rw_Slice +eina_slice_dup(const Eina_Slice slice) +{ + Eina_Rw_Slice ret; + + ret.len = slice.len; + ret.mem = NULL; + if (ret.len == 0) return ret; + + ret.mem = malloc(ret.len); + if (!ret.mem) + ret.len = 0; + else + memcpy(ret.mem, slice.mem, ret.len); + + return ret; +} + +static inline Eina_Rw_Slice +eina_rw_slice_dup(const Eina_Rw_Slice rw_slice) +{ + return eina_slice_dup(eina_rw_slice_slice_get(rw_slice)); +} + +static inline int +eina_slice_compare(const Eina_Slice a, const Eina_Slice b) +{ + const size_t len = a.len <= b.len ? a.len : b.len; + if (len > 0) + { + int r = memcmp(a.mem, b.mem, len); + if (r != 0) return r; + } + if (a.len < b.len) return -1; + else if (a.len > b.len) return 1; + else return 0; +} + +static inline int +eina_rw_slice_compare(const Eina_Rw_Slice a, const Eina_Rw_Slice b) +{ + return eina_slice_compare(eina_rw_slice_slice_get(a), + eina_rw_slice_slice_get(b)); +} + +static inline Eina_Rw_Slice +eina_rw_slice_copy(const Eina_Rw_Slice dst, const Eina_Slice src) +{ + const size_t len = src.len <= dst.len ? src.len : dst.len; + Eina_Rw_Slice ret; + + ret.len = len; + ret.mem = dst.mem; + if (len > 0) memcpy(ret.mem, src.mem, len); + return ret; +} + +static inline Eina_Slice +eina_slice_seek(const Eina_Slice slice, ssize_t offset, int whence) +{ + Eina_Slice ret; + + ret.len = 0; + ret.mem = slice.mem; + + if (whence == SEEK_END) + { + whence = SEEK_SET; + offset += slice.len; + } + + if (whence != SEEK_SET) + return ret; + + if (offset < 0) + offset = 0; + else if ((size_t)offset > slice.len) + offset = slice.len; + + ret.len = slice.len - offset; + ret.mem = (const void *)(slice.bytes + offset); + return ret; +} + +static inline Eina_Rw_Slice +eina_rw_slice_seek(const Eina_Rw_Slice rw_slice, ssize_t offset, int whence) +{ + Eina_Rw_Slice ret; + + ret.len = 0; + ret.mem = rw_slice.mem; + + if (whence == SEEK_END) + { + whence = SEEK_SET; + offset += rw_slice.len; + } + + if (whence != SEEK_SET) + return ret; + + if (offset < 0) + offset = 0; + else if ((size_t)offset > rw_slice.len) + offset = rw_slice.len; + + ret.len = rw_slice.len - offset; + ret.mem = (void *)(rw_slice.bytes + offset); + return ret; +} + +static inline const void * +eina_slice_strchr(const Eina_Slice slice, int c) +{ + if (slice.len == 0) return NULL; + return memchr(slice.mem, c, slice.len); +} + +static inline const void * +eina_slice_find(const Eina_Slice slice, const Eina_Slice needle) +{ + Eina_Slice s, n; + uint8_t c; + + if (slice.len == 0) return NULL; + if (needle.len == 0) return NULL; + if (slice.len < needle.len) return NULL; + if (slice.len == 1) return eina_slice_strchr(slice, needle.bytes[0]); + if ((slice.len == needle.len) && + (memcmp(slice.mem, needle.mem, needle.len) == 0)) + return slice.mem; + + s.mem = slice.mem; + s.len = slice.len - needle.len; + + c = needle.bytes[0]; + n.mem = (const void *)(needle.bytes + 1); + n.len = needle.len - 1; + + while (s.len > 0) + { + const uint8_t *p = (const uint8_t *)eina_slice_strchr(s, c); + size_t offset; + + if (!p) return NULL; + + p++; + if (memcmp(p, n.mem, n.len) == 0) + return (const void *)(p - 1); + + offset = p - s.bytes; + s.bytes += offset; + s.len -= offset; + } + + return NULL; +} + +static inline void * +eina_rw_slice_strchr(const Eina_Rw_Slice rw_slice, int c) +{ + if (rw_slice.len == 0) return NULL; + return memchr(rw_slice.mem, c, rw_slice.len); +} + +static inline void * +eina_rw_slice_find(const Eina_Rw_Slice rw_slice, const Eina_Slice needle) +{ + return (void *)eina_slice_find(eina_rw_slice_slice_get(rw_slice), needle); +} + +static inline const void * +eina_slice_end_get(const Eina_Slice slice) +{ + return (const void *)(slice.bytes + slice.len); +} + +static inline void * +eina_rw_slice_end_get(const Eina_Rw_Slice rw_slice) +{ + return (void *)(rw_slice.bytes + rw_slice.len); +} + +static inline char * +eina_slice_strdup(const Eina_Slice slice) +{ + if (slice.len == 0) + return strdup(""); + else + return strndup((const char *)slice.mem, slice.len); +} + +static inline char * +eina_rw_slice_strdup(const Eina_Rw_Slice rw_slice) +{ + if (rw_slice.len == 0) + return strdup(""); + else + return strndup((const char *)rw_slice.mem, rw_slice.len); +} + +#endif /* _EINA_INLINE_SLICE_H */ diff --git a/src/lib/eina/eina_slice.h b/src/lib/eina/eina_slice.h new file mode 100644 index 0000000000..7d393ec912 --- /dev/null +++ b/src/lib/eina/eina_slice.h @@ -0,0 +1,530 @@ +/* EINA - EFL data type library + * Copyright (C) 2016 ProFUSION embedded systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifndef _EINA_SLICE_H +#define _EINA_SLICE_H + +#include "eina_types.h" +#include +#include +#include +#include + +/** + * @addtogroup Eina_Slice_Group Memory Slices + * + * @brief These functions provide memory slices in read-only and + * read-write forms. + * + * Memory slices define a contiguous linear memory starting at a given + * pointer (@c mem) and spanning for a given length (@c len). + * + * They may be read-only (Eina_Slice) or read-write (Eina_Rw_Slice). + * + * @since 1.19 + */ + +/** + * @addtogroup Eina_Data_Types_Group Data Types + * + * @{ + */ + +/** + * @defgroup Eina_Slice_Group Memory Slices + * + * @{ + */ + +/** + * @typedef Eina_Slice + * Defines a read-only memory region. + * + * The slice is a memory starting at @c mem and accessible up to @c + * len bytes. + * + * @see Eina_Rw_Slice for read-write memory regions. + * + * @since 1.19 + */ +typedef struct _Eina_Slice Eina_Slice; + +/** + * @typedef Eina_Rw_Slice + * Defines a read-and-write able memory region. + * + * The slice is a memory starting at @c mem and accessible up to @c + * len bytes. + * + * @see Eina_Slice for read-only memory regions. + * + * @since 1.19 + */ +typedef struct _Eina_Rw_Slice Eina_Rw_Slice; + +/** + * @struct _Eina_Slice + * Defines a read-only memory region. + * + * The slice is a memory starting at @c mem and accessible up to @c + * len bytes. + * + * @see Eina_Rw_Slice for read-write memory regions. + * + * @since 1.19 + */ +struct _Eina_Slice +{ + size_t len; /**< size of memory pointed by @c mem */ + union { + const void *mem; /**< memory pointed by this slice. Just read, never modify it. */ + const uint8_t *bytes; /**< memory as uint8_t pointer */ + }; +}; + +/** + * @struct _Eina_Rw_Slice + * Defines a read-and-write able memory region. + * + * The slice is a memory starting at @c mem and accessible up to @c + * len bytes. + * + * @see Eina_Slice for read-only memory regions. + * + * @since 1.19 + */ +struct _Eina_Rw_Slice +{ + size_t len; /**< size of memory pointed by @c mem */ + union { + void *mem; /**< memory pointed by this slice. It's write able. */ + uint8_t *bytes; /**< memory as uint8_t pointer */ + }; +}; + +/** + * @brief Convert the Read-write slice to read-only. + * + * @param rw_slice the read-write slice to convert. + * @return the red-only slice matching the slice. + */ +static inline Eina_Slice eina_rw_slice_slice_get(const Eina_Rw_Slice rw_slice); + +/** + * @brief Creates a duplicate of slice's memory. + * + * @param slice the input to duplicate + * @return a new read-write slice with new @c mem that matches @a slice + * contents. The new @c mem is allocated with malloc() and must + * be released with free(). + * + * @see eina_rw_slice_copy() + * @see eina_rw_slice_dup() + * + * @since 1.19 + */ +static inline Eina_Rw_Slice eina_slice_dup(const Eina_Slice slice) EINA_WARN_UNUSED_RESULT; + +/** + * @brief Creates a duplicate of slice's memory. + * + * @param rw_slice the input to duplicate + * @return a new read-write slice with new @c mem that matches @a slice + * contents. The new @c mem is allocated with malloc() and must + * be released with free(). + * + * @see eina_rw_slice_copy() + * @see eina_slice_dup() + * + * @since 1.19 + */ +static inline Eina_Rw_Slice eina_rw_slice_dup(const Eina_Rw_Slice rw_slice) EINA_WARN_UNUSED_RESULT; + +/** + * @brief Compare two slices, similar to memcmp() + * + * @param a the first slice to compare. + * @param b the second slice to compare. + * @return 0 if equal, < 0 if a < b, > 0 if a > b + * + * @since 1.19 + */ +static inline int eina_slice_compare(const Eina_Slice a, const Eina_Slice b); + +/** + * @brief Compare two slices, similar to memcmp() + * + * @param a the first slice to compare. + * @param b the second slice to compare. + * @return 0 if equal, < 0 if a < b, > 0 if a > b + * + * @since 1.19 + */ +static inline int eina_rw_slice_compare(const Eina_Rw_Slice a, const Eina_Rw_Slice b); + +/** + * @brief Copy a read-only slice to a read-write one, similar to memcpy(). + * + * @param dest where to write the memory. + * @param src where to load memory. + * + * @return a new slice with the resulting write. Note that the length + * (@c len) will be the smallest of @a dest and @a src. + * + * @see eina_rw_slice_dup() + * @see eina_slice_dup() + * + * @since 1.19 + */ +static inline Eina_Rw_Slice eina_rw_slice_copy(const Eina_Rw_Slice dest, const Eina_Slice src); + +/** + * @brief Seek within a slice, similar to fseek(). + * + * @param slice the containing slice to seek inside. + * @param offset how to get to the new position. + * @param whence SEEK_SET, SEEK_END as fseek(). + * @return a new slice contained inside, it will start at the given + * offset and have a length that goes until the end of the @a + * slice. If an invalid @a whence, a zero-sized slice starting + * at @a slice mem will be returned. The slice is guaranteed + * to be contained within @a slice, even if offset causes it + * to go out of bounds, then it will be clamped to 0 and + * slice.len. + * + * @since 1.19 + */ +static inline Eina_Slice eina_slice_seek(const Eina_Slice slice, ssize_t offset, int whence); + +/** + * @brief Seek within a read-write slice, similar to fseek(). + * + * @param rw_slice the containing slice to seek inside. + * @param offset how to get to the new position. + * @param whence SEEK_SET, SEEK_END as fseek(). + * @return a new slice contained inside, it will start at the given + * offset and have a length that goes until the end of the @a + * rw_slice. If an invalid @a whence, a zero-sized slice + * starting at @a rw_slice mem will be returned. The slice is + * guaranteed to be contained within @a rw_slice, even if + * offset causes it to go out of bounds, then it will be + * clamped to 0 and slice.len. + * + * @since 1.19 + */ +static inline Eina_Rw_Slice eina_rw_slice_seek(const Eina_Rw_Slice rw_slice, ssize_t offset, int whence); + + +/** + * @brief Find a character inside the slice, similar to memchr(). + * + * @param slice the reference memory. + * @param c the byte (character) to find. + * @return the memory within slice or @c NULL if not found. + * + * @since 1.19 + */ +static inline const void *eina_slice_strchr(const Eina_Slice slice, int c); + +/** + * @brief Find a needle inside the slice, similar to memmem(). + * + * @param slice the reference memory. + * @param needle what to find. + * @return the memory within slice or @c NULL if not found. + * + * @since 1.19 + */ +static inline const void *eina_slice_find(const Eina_Slice slice, const Eina_Slice needle); + +/** + * @brief Find a character inside the slice, similar to memchr(). + * + * @param rw_slice the reference memory. + * @param c the byte (character) to find. + * @return the memory within slice or @c NULL if not found. + * + * @since 1.19 + */ +static inline void *eina_rw_slice_strchr(const Eina_Rw_Slice rw_slice, int c); + +/** + * @brief Find a needle inside the slice, similar to memmem(). + * + * @param rw_slice the reference memory. + * @param needle what to find. + * @return the memory within slice or @c NULL if not found. + * + * @since 1.19 + */ +static inline void *eina_rw_slice_find(const Eina_Rw_Slice rw_slice, const Eina_Slice needle); + +/** + * @brief The memory position where the slice ends. + * + * @note this is out-of the slice, the first byte after it ends and + * must not be accessed. + * + * @param slice the reference memory. + * @return the first byte after the slice ends. + * + * @since 1.19 + */ +static inline const void *eina_slice_end_get(const Eina_Slice slice); + +/** + * @brief The memory position where the slice ends. + * + * @note this is out-of the slice, the first byte after it ends and + * must not be accessed. + * + * @param rw_slice the reference memory. + * @return the first byte after the slice ends. + * + * @since 1.19 + */ +static inline void *eina_rw_slice_end_get(const Eina_Rw_Slice rw_slice); + +/** + * @brief A null-terminated string for this slice. + * + * @param slice the reference memory. + * @return newly allocated memory or @c NULL on error + * + * @since 1.19 + */ +static inline char *eina_slice_strdup(const Eina_Slice slice); + +/** + * @brief A null-terminated string for this slice. + * + * @param slice the reference memory. + * @return newly allocated memory or @c NULL on error + * + * @since 1.19 + */ +static inline char *eina_rw_slice_strdup(const Eina_Rw_Slice rw_slice); + +/** + * @def EINA_SLICE_ARRAY(buf) + * + * Initializer for arrays of any kind. + * + * It is often useful for globals. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * static uint8_t buf[1024]; + * static Eina_Slice rw_slice = EINA_SLICE_ARRAY(buf); + * @endcode + * + * @see EINA_SLICE_STR_LITERAL() for specific version that checks for string literals. + * + * @since 1.19 + */ +#ifdef __cplusplus +#define EINA_SLICE_ARRAY(buf) {((sizeof(buf) / sizeof((buf)[0])) * sizeof((buf)[0])), (buf)} +#else +#define EINA_SLICE_ARRAY(buf) {.len = ((sizeof(buf) / sizeof((buf)[0])) * sizeof((buf)[0])), .mem = (buf)} +#endif + + +/** + * @def EINA_RW_SLICE_DECLARE(name, length) + * + * Declare a local (stack) array for storage at given @a length and + * initialize an Eina_Rw_Slice called @a name. + * + * @param name the name of the variable to be the Eina_Rw_Slice + * @param length the size in bytes of the storage. + * + * @since 1.19 + */ +#define EINA_RW_SLICE_DECLARE(name, length) \ + uint8_t _eina_slice_storage_ ## name [(length)] = { 0 }; \ + Eina_Rw_Slice name = EINA_SLICE_ARRAY(_eina_slice_storage_ ## name) + +/** + * @def EINA_SLICE_STR_LITERAL(buf) + * + * Initializer for string literals (those declared as + * double-quoted). The size will @b NOT include the trainling + * null-terminator. + * + * It is often useful for globals. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * static const Eina_Slice ro_slice = EINA_SLICE_STR_LITERAL("hello world"); + * @endcode + * + * @see EINA_SLICE_STR() for more generic version. + * @see EINA_SLICE_ARRAY() for version that uses a general array. + * + * @since 1.19 + */ +#ifdef __cplusplus +#define EINA_SLICE_STR_LITERAL(buf) {(sizeof("" buf) - 1), (buf)} +#else +#define EINA_SLICE_STR_LITERAL(buf) {.len = (sizeof("" buf) - 1), .mem = (buf)} +#endif + +/** + * @def EINA_SLICE_STR(str) + * + * Initializer for strings (uses strlen()). + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice ro_slice = EINA_SLICE_STR("hello world"); + * @endcode + * + * @see EINA_SLICE_STR() for specific version using literals. + * + * @since 1.19 + */ +#ifdef __cplusplus +#define EINA_SLICE_STR(str) {strlen((str)), (str)} +#else +#define EINA_SLICE_STR(str) {.len = strlen((str)), .mem = (str)} +#endif + +/** + * @def EINA_SLICE_STR_FMT + * + * To be used in printf()-like statements, prints the slice as a + * string, its @c len is to be used, then it doesn need the null + * terminator. + * + * Use with EINA_SLICE_STR_PRINT() + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice s = EINA_SLICE_STR_LITERAL("hello"); + * printf("s=" EINA_SLICE_STR_FMT "\n", EINA_SLICE_STR_PRINT(s)); + * @endcode + * + * @since 1.19 + */ +#define EINA_SLICE_STR_FMT "%.*s" + +/** + * @def EINA_SLICE_STR_PRINT(s) + * + * To be used in printf()-like statements when EINA_SLICE_STR_FMT was + * used, it will print the slice as a string up to @c len. + * + * Use with EINA_SLICE_STR_FMT. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice s = EINA_SLICE_STR_LITERAL("hello"); + * printf("s=" EINA_SLICE_STR_FMT "\n", EINA_SLICE_STR_PRINT(s)); + * @endcode + * + * @since 1.19 + */ +#define EINA_SLICE_STR_PRINT(s) (int)(s).len, (const char *)(s).mem + +/** + * @def EINA_SLICE_FMT + * + * To be used in printf()-like statements, prints the slice as + * @c 0x1234+12 (@c mem + @c len). + * + * Use with EINA_SLICE_PRINT() + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice s = EINA_SLICE_STR_LITERAL("hello"); + * printf("s=" EINA_SLICE_FMT "\n", EINA_SLICE_PRINT(s)); + * @endcode + * + * @since 1.19 + */ +#define EINA_SLICE_FMT "%p+%zu" + +/** + * @def EINA_SLICE_PRINT(s) + * + * To be used in printf()-like statements when EINA_SLICE_FMT was + * used, it will print the slice @c mem and @c len. + * + * Use with EINA_SLICE_FMT. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @param s the slice + * + * @code + * Eina_Slice s = EINA_SLICE_STR_LITERAL("hello"); + * printf("s=" EINA_SLICE_FMT "\n", EINA_SLICE_PRINT(s)); + * @endcode + * + * @since 1.19 + */ +#define EINA_SLICE_PRINT(s) (s).mem, (s).len + +/** + * @def EINA_SLICE_FOREACH(s, itr) + * + * Iterate over the slice memory, using @c itr. Each increment will be + * using the size of @c itr pointer (int32_t* will do in increments of + * 4 bytes). + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @note Be aware of memory alignment! Accessing unaligned memory may + * not be supported in some architectures. + * + * @param s the slice + * @param itr the iterator to hold each byte. Use a proper type, not + * "void*" or "const void*" as it doesn't have an intrinsic + * size. + * + * @since 1.19 + */ +#ifdef __cplusplus +#define EINA_SLICE_FOREACH(s, itr) \ + for ((itr) = static_cast<__typeof__(itr)>((s).mem); \ + (itr) < static_cast<__typeof__(itr)>(static_cast((s).bytes + (s).len)); \ + (itr)++) +#else +#define EINA_SLICE_FOREACH(s, itr) \ + for ((itr) = (s).mem; \ + (void *)(itr) < (void *)((s).bytes + (s).len); \ + (itr)++) +#endif + +#include "eina_inline_slice.x" + +/** + * @} + */ + +/** + * @} + */ + +#endif /* _EINA_SLICE_H */ diff --git a/src/lib/eo/eina_types.eot b/src/lib/eo/eina_types.eot index 26fb4709dc..c7b9c958fb 100644 --- a/src/lib/eo/eina_types.eot +++ b/src/lib/eo/eina_types.eot @@ -43,3 +43,15 @@ enum @extern Eina.Xattr.Flags { type @extern Eina.Error: int; struct @extern @free(eina_binbuf_free) Eina.Binbuf; + +struct @extern Eina.Slice { + [[A linear, read-only, memory segment]] + len: size; + mem: const(void_ptr); +} + +struct @extern Eina.Rw_Slice { + [[A linear, read-write, memory segment]] + len: size; + mem: void_ptr; +} diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c index 8417b0652c..2c35a11536 100644 --- a/src/tests/eina/eina_suite.c +++ b/src/tests/eina/eina_suite.c @@ -80,6 +80,7 @@ static const Efl_Test_Case etc[] = { { "Promise", eina_test_promise }, { "Bezier", eina_test_bezier }, { "SafePointer", eina_test_safepointer }, + { "Slice", eina_test_slice }, { NULL, NULL } }; diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h index b11c0ad705..3ff362e7bd 100644 --- a/src/tests/eina/eina_suite.h +++ b/src/tests/eina/eina_suite.h @@ -72,5 +72,6 @@ void eina_test_vector(TCase *tc); void eina_test_promise(TCase *tc); void eina_test_bezier(TCase *tc); void eina_test_safepointer(TCase *tc); +void eina_test_slice(TCase *tc); #endif /* EINA_SUITE_H_ */ diff --git a/src/tests/eina/eina_test_slice.c b/src/tests/eina/eina_test_slice.c new file mode 100644 index 0000000000..ca73e73312 --- /dev/null +++ b/src/tests/eina/eina_test_slice.c @@ -0,0 +1,219 @@ +/* EINA - EFL data type library + * Copyright (C) 2016 ProFUSION embedded systems + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include "eina_suite.h" + +START_TEST(eina_test_slice_init) +{ + Eina_Rw_Slice a = EINA_SLICE_STR_LITERAL("hello world"); + char buf[1024] = ""; + Eina_Rw_Slice b = EINA_SLICE_ARRAY(buf); + Eina_Rw_Slice c = EINA_SLICE_STR("hi there"); + EINA_RW_SLICE_DECLARE(d, 512); + + eina_init(); + + fail_unless(a.len == sizeof("hello world") - 1); + fail_unless(strcmp(a.mem, "hello world") == 0); + + fail_unless(b.len == sizeof(buf)); + + fail_unless(c.len == strlen("hi there")); + fail_unless(strcmp(c.mem, "hi there") == 0); + + fail_unless(d.len == 512); + + eina_shutdown(); +} +END_TEST + +START_TEST(eina_test_slice_ro) +{ + Eina_Slice slice = EINA_SLICE_STR_LITERAL("hi there"); + Eina_Slice a, needle; + Eina_Rw_Slice dup; + const void *p; + char *str; + + dup = eina_slice_dup(slice); + fail_unless(dup.len == slice.len); + fail_unless(dup.mem != slice.mem); + fail_unless(eina_slice_compare(eina_rw_slice_slice_get(dup), slice) == 0); + free(dup.mem); + + str = eina_slice_strdup(slice); + fail_unless(str != NULL); + fail_unless(strcmp(str, "hi there") == 0); + free(str); + + a = eina_slice_seek(slice, strlen("hi "), SEEK_SET); + fail_unless(a.mem == slice.bytes + strlen("hi ")); + fail_unless(a.len == slice.len - strlen("hi ")); + + a = eina_slice_seek(slice, 0, SEEK_SET); + fail_unless(a.mem == slice.bytes + 0); + fail_unless(a.len == slice.len); + + a = eina_slice_seek(slice, -1, SEEK_END); + fail_unless(a.mem == slice.bytes + slice.len - 1); + fail_unless(a.len == 1); + + a = eina_slice_seek(slice, 0, SEEK_END); + fail_unless(a.mem == eina_slice_end_get(slice)); + fail_unless(a.len == 0); + + p = eina_slice_end_get(slice); + fail_unless(p == slice.bytes + slice.len); + + slice = (Eina_Slice)EINA_SLICE_STR_LITERAL("HELLO WORLD"); + slice.len = strlen("hi there"); /* crop... */ + + p = eina_slice_strchr(slice, ' '); + fail_unless(p == slice.bytes + 5); /* 5 = index of ' ' in HELLO WORLD.. */ + + p = eina_slice_strchr(slice, '!'); + fail_unless(p == NULL); + + needle = (Eina_Slice)EINA_SLICE_STR_LITERAL(" W"); + p = eina_slice_find(slice, needle); + fail_unless(p == slice.bytes + 5); /* 5 = index of ' W' in HELLO WORLD..*/ + + needle = (Eina_Slice)EINA_SLICE_STR_LITERAL("LO"); + p = eina_slice_find(slice, needle); + fail_unless(p == slice.bytes + 3); /* 3 = index of 'LO' in HELLO WORLD..*/ + + needle = (Eina_Slice)EINA_SLICE_STR_LITERAL("HELLO"); + p = eina_slice_find(slice, needle); + fail_unless(p == slice.mem); + + needle = (Eina_Slice)EINA_SLICE_STR_LITERAL("WORLD"); /* would go out of boundaries */ + p = eina_slice_find(slice, needle); + fail_unless(p == NULL); +} +END_TEST + +START_TEST(eina_test_slice_rw) +{ + uint8_t buf[] = "hi there"; + Eina_Rw_Slice rw_slice = EINA_SLICE_ARRAY(buf); + Eina_Slice ro_slice; + Eina_Rw_Slice a; + const void *p; + char *str; + + buf[sizeof(buf) - 1] = 0xff; + rw_slice.len--; /* do not account \0 (now 0xff) */ + ro_slice = eina_rw_slice_slice_get(rw_slice); + + fail_unless(rw_slice.len == ro_slice.len); + fail_unless(rw_slice.mem == ro_slice.mem); + + a = eina_slice_dup(ro_slice); + fail_unless(a.len == ro_slice.len); + fail_unless(a.mem != ro_slice.mem); + fail_unless(eina_rw_slice_compare(a, rw_slice) == 0); + free(a.mem); + + str = eina_rw_slice_strdup(rw_slice); + fail_unless(str != NULL); + fail_unless(strcmp(str, "hi there") == 0); + free(str); + + a = eina_rw_slice_seek(rw_slice, strlen("hi "), SEEK_SET); + fail_unless(a.mem == rw_slice.bytes + strlen("hi ")); + fail_unless(a.len == rw_slice.len - strlen("hi ")); + + a = eina_rw_slice_seek(rw_slice, 0, SEEK_SET); + fail_unless(a.mem == rw_slice.bytes + 0); + fail_unless(a.len == rw_slice.len); + + a = eina_rw_slice_seek(rw_slice, -1, SEEK_END); + fail_unless(a.mem == rw_slice.bytes + rw_slice.len - 1); + fail_unless(a.len == 1); + + a = eina_rw_slice_seek(rw_slice, 0, SEEK_END); + fail_unless(a.mem == eina_rw_slice_end_get(rw_slice)); + fail_unless(a.len == 0); + + p = eina_rw_slice_end_get(rw_slice); + fail_unless(p == rw_slice.bytes + rw_slice.len); + + ro_slice = (Eina_Slice)EINA_SLICE_STR_LITERAL("HELLO WORLD, big string to be cropped"); + a = eina_rw_slice_copy(rw_slice, ro_slice); + + fail_unless(a.mem == rw_slice.mem); + fail_unless(a.len == rw_slice.len); + fail_unless(strncmp(a.mem, "HELLO WO", a.len) == 0); + + p = eina_rw_slice_strchr(rw_slice, ' '); + fail_unless(p == rw_slice.bytes + 5); /* 5 = index of ' ' in HELLO WORLD.. */ + + p = eina_rw_slice_strchr(rw_slice, '!'); + fail_unless(p == NULL); + + ro_slice = (Eina_Slice)EINA_SLICE_STR_LITERAL(" W"); + p = eina_rw_slice_find(rw_slice, ro_slice); + fail_unless(p == rw_slice.bytes + 5); /* 5 = index of ' W' in HELLO WORLD..*/ + + ro_slice = (Eina_Slice)EINA_SLICE_STR_LITERAL("LO"); + p = eina_rw_slice_find(rw_slice, ro_slice); + fail_unless(p == rw_slice.bytes + 3); /* 3 = index of 'LO' in HELLO WORLD..*/ + + ro_slice = (Eina_Slice)EINA_SLICE_STR_LITERAL("HELLO"); + p = eina_rw_slice_find(rw_slice, ro_slice); + fail_unless(p == rw_slice.mem); + + ro_slice = (Eina_Slice)EINA_SLICE_STR_LITERAL("WORLD"); /* would go out of boundaries */ + p = eina_rw_slice_find(rw_slice, ro_slice); + fail_unless(p == NULL); + + fail_unless(buf[sizeof(buf) - 1] == 0xff); +} +END_TEST + +START_TEST(eina_test_slice_print) +{ + char buf[] = "Hello World"; + Eina_Slice slice = {.len = strlen("Hello"), .mem = buf}; + char a[128], b[128]; + + snprintf(a, sizeof(a), EINA_SLICE_FMT, EINA_SLICE_PRINT(slice)); + snprintf(b, sizeof(b), "%p+%zu", slice.mem, slice.len); + fail_unless(strcmp(a, b) == 0); + + snprintf(a, sizeof(a), EINA_SLICE_STR_FMT, EINA_SLICE_STR_PRINT(slice)); + fail_unless(strcmp(a, "Hello") == 0); +} +END_TEST + +void +eina_test_slice(TCase *tc) +{ + tcase_add_test(tc, eina_test_slice_init); + tcase_add_test(tc, eina_test_slice_ro); + tcase_add_test(tc, eina_test_slice_rw); + tcase_add_test(tc, eina_test_slice_print); +}