| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // Copyright (c) 2000-2019 Ericsson Telecom AB // |
| // // |
| // All rights reserved. This program and the accompanying materials // |
| // are made available under the terms of the Eclipse Public License v2.0 // |
| // which accompanies this distribution, and is available at // |
| // https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////// |
| // Module: EPTF_CLL_GenericRingBuffer_Functions |
| // |
| // Purpose: |
| // This module provides the interface of generic ring buffer container. |
| // The public functions are defined by macros. |
| // |
| // Module Parameters: |
| // (none) |
| // |
| // Module depends on: |
| // <EPTF_CLL_RingBuffer_Definitions> |
| // <EPTF_CLL_GenericRingBuffer_Definitions> |
| // |
| // Current Owner: |
| // Istvan Falusi (eistfal) |
| // |
| // Last Review Date: |
| // 2007-11-19 |
| // |
| // Detailed Comments: |
| // The Makefile Generator treats this file as TTCN-3 include file. The .ttcnin file will be |
| // added to the Makefile as special TTCN-3 include file which will not be translated by the |
| // compiler, but will be checked for modification when building the test suite. |
| // |
| // Previous definition of <EPTF_BASE_TYPE> macro (type of buffered items) in a .ttcnpp file |
| // is a precondition of using this ring buffer implementation as a TTCN-3 include! |
| // (p.e. |
| // |
| // #define EPTF_BASE_TYPE *UserType* |
| // |
| // ) |
| // This macro sets the <EPTF_BASE_TYPE> as the user type *UserType*. |
| // An appropriate TTCN-3 types module must also be provided (and imported into the .ttncpp module) |
| // by the user with the type definition of *UserType*: |
| // |
| // type record of integer *UserType*; |
| // |
| ////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| #include "EPTF_CLL_GenericRingBuffer_Definitions.ttcnin" |
| |
| #ifndef EPTF_BASE_TYPE |
| #error "undefined EPTF_BASE_TYPE" |
| #endif |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_init |
| // |
| // Purpose: |
| // Function to initialise an empty <EPTF_BASE_TYPE##RingBuffer>. |
| // |
| // Parameters: |
| // pl_buffer - *inout* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer to be initialized |
| // pl_capacity - *in* <integer> - the maximum nuber of elements can be stored in the buffer |
| // |
| // Return Value: |
| // - |
| // |
| // Detailed Comments: |
| // The default value of <pl_capacity> is defined by <c_EPTF_RB_default_capacity> constant. |
| // |
| ///////////////////////////////////////////////////////// |
| #define F_INIT_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_init( \ |
| inout TYPEARG##RingBuffer pl_buffer, \ |
| in integer pl_capacity := c_EPTF_RB_default_capacity \ |
| ) \ |
| { \ |
| pl_buffer.data := {}; \ |
| pl_buffer.status := c_EPTF_emptyRingBufferStatus; \ |
| if (pl_capacity > 0) \ |
| { \ |
| pl_buffer.status.capacity := pl_capacity; \ |
| } \ |
| f_EPTF_##TYPEARG##_RB_clear(pl_buffer) \ |
| } |
| #define F_INIT_RB(TYPEARG) F_INIT_RB_(TYPEARG) |
| F_INIT_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_size |
| // |
| // Purpose: |
| // Function to ask the size of the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // Return Value: |
| // *integer* - the number of stored elements. |
| // |
| ///////////////////////////////////////////////////////// |
| #define F_SIZE_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_size( \ |
| in TYPEARG##RingBuffer pl_buffer \ |
| ) return integer \ |
| { \ |
| return pl_buffer.status.content_size; \ |
| } |
| #define F_SIZE_RB(TYPEARG) F_SIZE_RB_(TYPEARG) |
| F_SIZE_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_capacity |
| // |
| // Purpose: |
| // Function to ask the capacity of the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // Return Value: |
| // *integer* - the possible maximum nuber of elements can be stored in the buffer. |
| // |
| ///////////////////////////////////////////////////////// |
| #define F_CAPACITY_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_capacity( \ |
| in TYPEARG##RingBuffer pl_buffer \ |
| ) return integer \ |
| { \ |
| return pl_buffer.status.capacity; \ |
| } |
| #define F_CAPACITY_RB(TYPEARG) F_CAPACITY_RB_(TYPEARG) |
| F_CAPACITY_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_empty |
| // |
| // Purpose: |
| // Checks whether the buffer is empty. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // Return Value: |
| // *boolean* - true, if the buffer is empty, otherwise false. |
| // |
| ///////////////////////////////////////////////////////// |
| #define F_EMPTY_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_empty( \ |
| in TYPEARG##RingBuffer pl_buffer \ |
| ) return boolean \ |
| { \ |
| return (pl_buffer.status.content_size == 0); \ |
| } |
| #define F_EMPTY_RB(TYPEARG) F_EMPTY_RB_(TYPEARG) |
| F_EMPTY_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_front |
| // |
| // Purpose: |
| // Function to get the first (eldest) element from the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // Return Value: |
| // <EPTF_BASE_TYPE> - the head of the buffer. |
| // |
| // Detailed Comments: |
| // IMPORTANT NOTE: the function does not perform boundary check. |
| // On empty buffer the operstion leads to undefined behaviour. |
| // |
| ///////////////////////////////////////////////////////////// |
| #define F_FRONT_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_front( \ |
| in TYPEARG##RingBuffer pl_buffer \ |
| ) return TYPEARG \ |
| { \ |
| return pl_buffer.data[pl_buffer.status.head]; \ |
| } |
| #define F_FRONT_RB(TYPEARG) F_FRONT_RB_(TYPEARG) |
| F_FRONT_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_back |
| // |
| // Purpose: |
| // Function to get the last (latest) element from the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // Return Value: |
| // <EPTF_BASE_TYPE> - the tail of the buffer. |
| // |
| // Detailed Comments: |
| // IMPORTANT NOTE: the function does not perform boundary check. |
| // On empty buffer the operation leads to undefined behaviour. |
| // |
| ///////////////////////////////////////////////////////////// |
| #define F_BACK_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_back( \ |
| in TYPEARG##RingBuffer pl_buffer \ |
| ) return TYPEARG \ |
| { \ |
| return(pl_buffer.data[pl_buffer.status.tail]); \ |
| } |
| #define F_BACK_RB(TYPEARG) F_BACK_RB_(TYPEARG) |
| F_BACK_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_push_back |
| // |
| // Purpose: |
| // Function to store a new data item at end of buffer. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // pl_dataItem - *in* <EPTF_BASE_TYPE> - the data item to be stored |
| // |
| // Return Value: |
| // - |
| // |
| // Detailed Comments: |
| // The operation is always possible. If buffer is full, |
| // the first data item (item at beginning of buffer) is overwritten. |
| // |
| ////////////////////////////////////////////////////////////////////// |
| #define F_PUSH_BACK_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_push_back( \ |
| inout TYPEARG##RingBuffer pl_buffer, \ |
| in TYPEARG pl_dataItem \ |
| ) \ |
| { \ |
| f_EPTF_RB_increment_tail(pl_buffer.status); \ |
| pl_buffer.data[pl_buffer.status.tail] := pl_dataItem; \ |
| if (pl_buffer.status.content_size > pl_buffer.status.capacity) \ |
| { \ |
| f_EPTF_RB_increment_head(pl_buffer.status); \ |
| } \ |
| } |
| #define F_PUSH_BACK_RB(TYPEARG) F_PUSH_BACK_RB_(TYPEARG) |
| F_PUSH_BACK_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_push_front |
| // |
| // Purpose: |
| // Function to store a new data item at beginning of the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // pl_dataItem - *in* <EPTF_BASE_TYPE> - the data item to be stored |
| // |
| // Return Value: |
| // - |
| // |
| // Detailed Comments: |
| // The operation is always possible. If buffer is full, |
| // the last data item is (item at end of buffer) overwritten. |
| // |
| ////////////////////////////////////////////////////////////////////// |
| #define F_PUSH_FRONT_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_push_front( \ |
| inout TYPEARG##RingBuffer pl_buffer, \ |
| in TYPEARG pl_dataItem \ |
| ) \ |
| { \ |
| f_EPTF_RB_decrement_head(pl_buffer.status); \ |
| pl_buffer.data[pl_buffer.status.head] := pl_dataItem; \ |
| if (pl_buffer.status.content_size > pl_buffer.status.capacity) \ |
| { \ |
| f_EPTF_RB_decrement_tail(pl_buffer.status); \ |
| } \ |
| } |
| #define F_PUSH_FRONT_RB(TYPEARG) F_PUSH_FRONT_RB_(TYPEARG) |
| F_PUSH_FRONT_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_pop_front |
| // |
| // Purpose: |
| // Function to drop the first data item. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // pl_dataItem - *in* <EPTF_BASE_TYPE> - the data item to be stored |
| // |
| // Return Value: |
| // - |
| // |
| ////////////////////////////////////////////////////////////// |
| #define F_POP_FRONT_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_pop_front( \ |
| inout TYPEARG##RingBuffer pl_buffer \ |
| ) \ |
| { \ |
| if (pl_buffer.status.content_size != 0) \ |
| { \ |
| f_EPTF_RB_increment_head(pl_buffer.status); \ |
| } \ |
| } |
| #define F_POP_FRONT_RB(TYPEARG) F_POP_FRONT_RB_(TYPEARG) |
| F_POP_FRONT_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_pop_back |
| // |
| // Purpose: |
| // Function to drop the last data item. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // pl_dataItem - *in* <EPTF_BASE_TYPE> - the data item to be stored |
| // |
| // Return Value: |
| // - |
| // |
| ////////////////////////////////////////////////////////////// |
| #define F_POP_BACK_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_pop_back( \ |
| inout TYPEARG##RingBuffer pl_buffer \ |
| ) \ |
| { \ |
| if (pl_buffer.status.content_size != 0) \ |
| { \ |
| f_EPTF_RB_decrement_tail(pl_buffer.status); \ |
| } \ |
| } |
| #define F_POP_BACK_RB(TYPEARG) F_POP_BACK_RB_(TYPEARG) |
| F_POP_BACK_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_clear |
| // |
| // Purpose: |
| // Function to remove all data from the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *inout* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // Return Value: |
| // - |
| // |
| ////////////////////////////////////////////////////////// |
| #define F_CLEAR_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_clear( \ |
| inout TYPEARG##RingBuffer pl_buffer \ |
| ) \ |
| { \ |
| pl_buffer.status.head := 0; \ |
| pl_buffer.status.tail := pl_buffer.status.capacity - 1; \ |
| pl_buffer.status.content_size := 0; \ |
| } |
| #define F_CLEAR_RB(TYPEARG) F_CLEAR_RB_(TYPEARG) |
| F_CLEAR_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_get |
| // |
| // Purpose: |
| // Function to perform an unchecked random access to the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *inout* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // pl_index - *in* *integer* - the index of desired data item |
| // |
| // Return Value: |
| // <EPTF_BASE_TYPE> - the data item at the given index. |
| // |
| // Detailed Comments: |
| // - IMPORTANT NOTE: the function does not perform boundary check. |
| // If index is invalid the operation leads to undefined behaviour. |
| // - The index of the first (eldest) item is 0. |
| // |
| ////////////////////////////////////////////////////////// |
| #define F_GET_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_get( \ |
| in TYPEARG##RingBuffer pl_buffer, \ |
| in integer pl_index \ |
| ) return TYPEARG \ |
| { \ |
| return( pl_buffer.data[ (pl_buffer.status.head + pl_index) mod pl_buffer.status.capacity ] );\ |
| } |
| #define F_GET_RB(TYPEARG) F_GET_RB_(TYPEARG) |
| F_GET_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_at |
| // |
| // Purpose: |
| // Function to perform a secure access to the buffer. |
| // |
| // Parameters: |
| // pl_buffer - *inout* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer |
| // |
| // pl_index - *in* *integer* - the index of desired data item |
| // |
| // pl_dataItem - *out* <EPTF_BASE_TYPE> - the data item at the given index. |
| // |
| // Return Value: |
| // *boolean* - false, if index is invalid, otherwise true. |
| // |
| // Detailed Comments: |
| // - The function performs boundary check. |
| // - The index of the first (eldest) item is 0. |
| // |
| /////////////////////////////////////////////////////////////////////////// |
| #define F_AT_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_at( \ |
| in TYPEARG##RingBuffer pl_buffer, \ |
| in integer pl_index, \ |
| out TYPEARG pl_dataItem \ |
| ) return boolean \ |
| { \ |
| if (pl_index < 0 or pl_index >= f_EPTF_##TYPEARG##_RB_size(pl_buffer)) \ |
| { \ |
| return false; \ |
| } \ |
| pl_dataItem := f_EPTF_##TYPEARG##_RB_get(pl_buffer, pl_index); \ |
| return true; \ |
| } |
| #define F_AT_RB(TYPEARG) F_AT_RB_(TYPEARG) |
| F_AT_RB(EPTF_BASE_TYPE) |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////////////////////// |
| // Function: f_EPTF_##EPTF_BASE_TYPE##_RB_dump |
| // |
| // Purpose: |
| // Function to dump the content of the buffer into a list. |
| // |
| // Parameters: |
| // pl_buffer - *in* <EPTF_BASE_TYPE##RingBuffer> - the ring buffer to be dumped |
| // |
| // pl_dest - *out* <EPTF_BASE_TYPE##List> - the destination array |
| // |
| // Return Value: |
| // - |
| // |
| ///////////////////////////////////////////////////////////////////////// |
| #define F_DUMP_RB_(TYPEARG) \ |
| public function f_EPTF_##TYPEARG##_RB_dump( \ |
| in TYPEARG##RingBuffer pl_buffer, \ |
| out TYPEARG##List pl_dest \ |
| ) \ |
| { \ |
| pl_dest:= {}; \ |
| for (var integer i:=0; i<pl_buffer.status.content_size; i:= i+1) \ |
| { \ |
| pl_dest[i] := pl_buffer.data[(pl_buffer.status.head + i) mod pl_buffer.status.capacity];\ |
| } \ |
| } |
| #define F_DUMP_RB(TYPEARG) F_DUMP_RB_(TYPEARG) |
| F_DUMP_RB(EPTF_BASE_TYPE) |
| |
| //========================================================================= |
| // Private Functions |
| //========================================================================= |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RB_increment_tail |
| // |
| // Purpose: |
| // Function to increment the tail of a ring buffer. |
| // |
| // Parameters: |
| // pl_status - *inout* <EPTF_RingBufferStatus> - the status structure of ring buffer to be modified |
| // |
| // Return Value: |
| // - |
| // |
| /////////////////////////////////////////////////////////// |
| private function f_EPTF_RB_increment_tail( inout EPTF_RingBufferStatus pl_status ) |
| { |
| pl_status.content_size := pl_status.content_size + 1; |
| pl_status.tail := (pl_status.tail + 1) mod pl_status.capacity; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RB_increment_head |
| // |
| // Purpose: |
| // Function to increment the head of a ring buffer. |
| // |
| // Parameters: |
| // pl_status - *inout* <EPTF_RingBufferStatus> - the status structure of ring buffer to be modified |
| // |
| // Return Value: |
| // - |
| // |
| // Detailed Comments: |
| // Precondition of calling this function: ring buffer is not empty. |
| // |
| /////////////////////////////////////////////////////////// |
| private function f_EPTF_RB_increment_head( inout EPTF_RingBufferStatus pl_status ) |
| { |
| pl_status.head := (pl_status.head + 1) mod pl_status.capacity; |
| pl_status.content_size := pl_status.content_size - 1; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RB_decrement_tail |
| // |
| // Purpose: |
| // Function to decrement the tail of a ring buffer. |
| // |
| // Parameters: |
| // pl_status - *inout* <EPTF_RingBufferStatus> - the status structure of ring buffer to be modified |
| // |
| // Return Value: |
| // - |
| // |
| // Detailed Comments: |
| // Precondition of calling this function: ring buffer is not empty. |
| // |
| /////////////////////////////////////////////////////////// |
| private function f_EPTF_RB_decrement_tail( inout EPTF_RingBufferStatus pl_status ) |
| { |
| pl_status.tail := (pl_status.tail - 1) mod pl_status.capacity; |
| pl_status.content_size := pl_status.content_size - 1; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RB_decrement_head |
| // |
| // Purpose: |
| // Function to decrement the head of a ring buffer. |
| // |
| // Parameters: |
| // pl_status - *inout* <EPTF_RingBufferStatus> - the status structure of ring buffer to be modified |
| // |
| // Return Value: |
| // - |
| // |
| /////////////////////////////////////////////////////////// |
| private function f_EPTF_RB_decrement_head( inout EPTF_RingBufferStatus pl_status ) |
| { |
| pl_status.content_size := pl_status.content_size + 1; |
| pl_status.head := (pl_status.head - 1) mod pl_status.capacity; |
| } |