eina: introduce Eina_Slice and Eina_Rw_Slice.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Fri, 12 Aug 2016 20:08:38 +0000 (17:08 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Mon, 22 Aug 2016 21:25:14 +0000 (18:25 -0300)
A plain simple pointer + length describing a linear memory region.

src/Makefile_Eina.am
src/lib/eina/Eina.h
src/lib/eina/eina_inline_slice.x [new file with mode: 0644]
src/lib/eina/eina_slice.h [new file with mode: 0644]
src/lib/eo/eina_types.eot
src/tests/eina/eina_suite.c
src/tests/eina/eina_suite.h
src/tests/eina/eina_test_slice.c [new file with mode: 0644]

index a116329..f2a5762 100644 (file)
@@ -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`\" \
index e57660e..f57cc62 100644 (file)
@@ -271,6 +271,7 @@ extern "C" {
 #include <eina_promise.h>
 #include <eina_bezier.h>
 #include <eina_safepointer.h>
+#include <eina_slice.h>
 
 #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 (file)
index 0000000..27cca37
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..7d393ec
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _EINA_SLICE_H
+#define _EINA_SLICE_H
+
+#include "eina_types.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/**
+ * @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<void *>((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 */
index 26fb470..c7b9c95 100644 (file)
@@ -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;
+}
index 8417b06..2c35a11 100644 (file)
@@ -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 }
 };
 
index b11c0ad..3ff362e 100644 (file)
@@ -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 (file)
index 0000000..ca73e73
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <Eina.h>
+
+#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);
+}