From c2aedc117ad9271c0ef4e68bbfd3873d9137ed2d Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Mon, 19 Dec 2016 16:49:29 -0200 Subject: [PATCH] efl_io_buffer: adopt read-only and read-write buffers. todo--, allow buffer backing store to be provided by Eina_Slice (rdonly) or Eina_Rw_Slice (rdwr). --- src/examples/ecore/efl_net_server_example.c | 8 +-- src/lib/efl/interfaces/efl_io_buffer.c | 94 ++++++++++++++++++++++++++++- src/lib/efl/interfaces/efl_io_buffer.eo | 36 +++++++++++ 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/src/examples/ecore/efl_net_server_example.c b/src/examples/ecore/efl_net_server_example.c index 22efdd0..3a9598e 100644 --- a/src/examples/ecore/efl_net_server_example.c +++ b/src/examples/ecore/efl_net_server_example.c @@ -343,7 +343,7 @@ _server_client_add(void *data EINA_UNUSED, const Efl_Event *event) * One can change these to Efl_Io_File or event pipe to something * else like Efl_Io_Stdin, Efl_Io_Stdout and it would just work. */ - Eina_Slice slice; + static const Eina_Slice hello_world_slice = EINA_SLICE_STR_LITERAL("Hello World!"); Send_Recv_Data *d; Eo *send_buffer, *recv_buffer; @@ -354,10 +354,8 @@ _server_client_add(void *data EINA_UNUSED, const Efl_Event *event) return; } - // TODO buffer constructor taking RO string - send_buffer = efl_add(EFL_IO_BUFFER_CLASS, NULL); - slice = (Eina_Slice)EINA_SLICE_STR("Hello World!"); - efl_io_writer_write(send_buffer, &slice, NULL); + send_buffer = efl_add(EFL_IO_BUFFER_CLASS, NULL, + efl_io_buffer_adopt_readonly(efl_added, hello_world_slice)); /* Unlimited buffer to store the received data. */ recv_buffer = efl_add(EFL_IO_BUFFER_CLASS, NULL); diff --git a/src/lib/efl/interfaces/efl_io_buffer.c b/src/lib/efl/interfaces/efl_io_buffer.c index 66b5338..299fb56 100644 --- a/src/lib/efl/interfaces/efl_io_buffer.c +++ b/src/lib/efl/interfaces/efl_io_buffer.c @@ -17,6 +17,7 @@ typedef struct _Efl_Io_Buffer_Data Eina_Bool closed; Eina_Bool can_read; Eina_Bool can_write; + Eina_Bool readonly; } Efl_Io_Buffer_Data; static Eina_Bool @@ -25,6 +26,8 @@ _efl_io_buffer_realloc(Eo *o, Efl_Io_Buffer_Data *pd, size_t size) void *tmp; size_t limit = efl_io_buffer_limit_get(o); + EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, EINA_FALSE); + if ((limit > 0) && (size > limit)) size = limit; @@ -77,6 +80,7 @@ _efl_io_buffer_realloc_rounded(Eo *o, Efl_Io_Buffer_Data *pd, size_t size) EOLIAN static void _efl_io_buffer_preallocate(Eo *o, Efl_Io_Buffer_Data *pd, size_t size) { + EINA_SAFETY_ON_TRUE_RETURN(pd->readonly); EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o)); if (pd->allocated < size) _efl_io_buffer_realloc_rounded(o, pd, size); @@ -85,6 +89,7 @@ _efl_io_buffer_preallocate(Eo *o, Efl_Io_Buffer_Data *pd, size_t size) EOLIAN static void _efl_io_buffer_limit_set(Eo *o, Efl_Io_Buffer_Data *pd, size_t limit) { + EINA_SAFETY_ON_TRUE_RETURN(pd->readonly); EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o)); if (pd->limit == limit) return; @@ -125,6 +130,7 @@ EOLIAN static Eina_Binbuf * _efl_io_buffer_binbuf_steal(Eo *o, Efl_Io_Buffer_Data *pd) { Eina_Binbuf *ret; + EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, NULL); EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), NULL); ret = eina_binbuf_manage_new(pd->bytes, efl_io_sizer_size_get(o), EINA_FALSE); @@ -166,7 +172,7 @@ _efl_io_buffer_efl_object_destructor(Eo *o, Efl_Io_Buffer_Data *pd) if (pd->bytes) { - free(pd->bytes); + if (!pd->readonly) free(pd->bytes); pd->bytes = NULL; pd->allocated = 0; pd->used = 0; @@ -244,6 +250,7 @@ _efl_io_buffer_efl_io_writer_write(Eo *o, Efl_Io_Buffer_Data *pd, Eina_Slice *sl size_t available, todo, write_pos, limit; int err = EINVAL; + EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, EPERM); EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINVAL); EINA_SAFETY_ON_TRUE_GOTO(efl_io_closer_closed_get(o), error); @@ -362,6 +369,13 @@ _efl_io_buffer_efl_io_sizer_resize(Eo *o, Efl_Io_Buffer_Data *pd, uint64_t size) if (efl_io_sizer_size_get(o) == size) return 0; + if (pd->readonly) + { + EINA_SAFETY_ON_TRUE_RETURN_VAL(size > pd->used, EPERM); + pd->used = size; + goto end; + } + old_size = pd->used; pd->used = size; @@ -378,6 +392,7 @@ _efl_io_buffer_efl_io_sizer_resize(Eo *o, Efl_Io_Buffer_Data *pd, uint64_t size) if (old_size < size) memset(pd->bytes + old_size, 0, size - old_size); + end: pos_read = efl_io_buffer_position_read_get(o); if (pos_read > size) efl_io_buffer_position_read_set(o, size); @@ -500,6 +515,8 @@ _efl_io_buffer_position_write_set(Eo *o, Efl_Io_Buffer_Data *pd, uint64_t positi EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EINA_FALSE); size = efl_io_sizer_size_get(o); + if (position < size) + EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->readonly, EINA_FALSE); EINA_SAFETY_ON_TRUE_RETURN_VAL(position > size, EINA_FALSE); if (pd->position_write == position) return EINA_TRUE; @@ -524,4 +541,79 @@ _efl_io_buffer_position_write_get(Eo *o EINA_UNUSED, Efl_Io_Buffer_Data *pd) return pd->position_write; } +EOLIAN static void +_efl_io_buffer_adopt_readonly(Eo *o, Efl_Io_Buffer_Data *pd, const Eina_Slice slice) +{ + Eina_Bool changed_size; + + EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o)); + + if (!pd->readonly) free(pd->bytes); + pd->readonly = EINA_TRUE; + pd->bytes = (uint8_t *)slice.bytes; + pd->allocated = slice.len; + + changed_size = (pd->used != slice.len); + pd->used = slice.len; + efl_io_writer_can_write_set(o, EINA_FALSE); + if (pd->closed) return; + + if (efl_io_buffer_position_read_get(o) > slice.len) + { + efl_io_buffer_position_read_set(o, slice.len); + if (pd->closed) return; + } + + efl_io_buffer_position_write_set(o, slice.len); + if (pd->closed) return; + + if (changed_size) + { + efl_event_callback_call(o, EFL_IO_SIZER_EVENT_SIZE_CHANGED, NULL); + if (pd->closed) return; + } + + efl_event_callback_call(o, EFL_IO_BUFFER_EVENT_REALLOCATED, NULL); +} + +EOLIAN static void +_efl_io_buffer_adopt_readwrite(Eo *o, Efl_Io_Buffer_Data *pd, Eina_Rw_Slice slice) +{ + Eina_Bool changed_size; + + EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o)); + + if (!pd->readonly) free(pd->bytes); + pd->readonly = EINA_FALSE; + pd->bytes = slice.bytes; + pd->allocated = slice.len; + + changed_size = (pd->used != slice.len); + pd->used = slice.len; + + efl_io_writer_can_write_set(o, (pd->limit == 0) || + (efl_io_buffer_position_write_get(o) < pd->limit)); + if (pd->closed) return; + + if (efl_io_buffer_position_read_get(o) > slice.len) + { + efl_io_buffer_position_read_set(o, slice.len); + if (pd->closed) return; + } + + if (efl_io_buffer_position_write_get(o) > slice.len) + { + efl_io_buffer_position_write_set(o, slice.len); + if (pd->closed) return; + } + + if (changed_size) + { + efl_event_callback_call(o, EFL_IO_SIZER_EVENT_SIZE_CHANGED, NULL); + if (pd->closed) return; + } + + efl_event_callback_call(o, EFL_IO_BUFFER_EVENT_REALLOCATED, NULL); +} + #include "interfaces/efl_io_buffer.eo.c" diff --git a/src/lib/efl/interfaces/efl_io_buffer.eo b/src/lib/efl/interfaces/efl_io_buffer.eo index 30b75d2..ee4d52c 100644 --- a/src/lib/efl/interfaces/efl_io_buffer.eo +++ b/src/lib/efl/interfaces/efl_io_buffer.eo @@ -22,6 +22,39 @@ class Efl.Io.Buffer (Efl.Object, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Ef } } + adopt_readonly { + [[Adopt a read-only slice as buffer's backing store. + + The slice memory will not be copied and must remain + alive during buffer's lifetime. Usually this is + guaranteed by some global static-const memory or some + parent object and this buffer being a view of that -- be + aware of parent memory remaining alive, such as + "slice,changed" events. + ]] + params { + @in slice: const(Eina.Slice); [[Slice to adopt as read-only]] + } + } + + adopt_readwrite { + [[Adopt a read-write slice as buffer's backing store. + + The slice memory will not be copied and must remain + alive during buffer's lifetime. Usually this is + guaranteed by some global static memory or some + parent object and this buffer being a view of that -- be + aware of parent memory remaining alive, such as + "slice,changed" events. + + The memory will be disposed using free() and reallocated + using realloc(). + ]] + params { + @in slice: Eina.Rw_Slice; [[Slice to adopt as read-write]] + } + } + @property limit { [[Limit how big the buffer can grow. @@ -95,6 +128,9 @@ class Efl.Io.Buffer (Efl.Object, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Ef [[Steals the internal buffer memory and returns it as a binbuf. The returned memory must be freed with eina_binbuf_free(). + + On failure, for example a read-only backing store was + adopted with @.adopt_readonly, NULL is returned. ]] return: free(own(ptr(Eina.Binbuf)), eina_binbuf_free) @warn_unused; [[Binbuf]] } -- 2.7.4