eina: introduce Eina_Slice and Eina_Rw_Slice.

A plain simple pointer + length describing a linear memory region.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-08-12 17:08:38 -03:00
parent 8906461b48
commit 9062bbd8e0
8 changed files with 1001 additions and 2 deletions

View 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`\" \

View 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

View File

@ -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 */

530
src/lib/eina/eina_slice.h Normal file
View File

@ -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 */

View 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;
}

View 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 }
};

View 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_ */

View File

@ -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);
}