/* vim: set ft=cpp: -*- C++ -*- */
#ifndef __QUEX_INCLUDE_GUARD__BUFFER__BUFFER
#define __QUEX_INCLUDE_GUARD__BUFFER__BUFFER

#include<quex/code_base/definitions>
#include<quex/code_base/MemoryManager>

QUEX_NAMESPACE_MAIN_OPEN

typedef struct QUEX_SETTING_USER_CLASS_DECLARATION_EPILOG { 
    E_Ownership           ownership;

    /* (*) Buffer Memory Setup:
     *      memory[0]             = lower buffer limit code character
     *      memory[1]             = first char of content
     *      ...
     *      memory[BUFFER_SIZE-2] = last char of content
     *      memory[BUFFER_SIZE-1] = upper buffer limit code character             */
    QUEX_TYPE_CHARACTER*  _front;         /* first character in buffer (BLC)      */
    QUEX_TYPE_CHARACTER*  _back;          /* last character in buffer  (BLC)      */

} QUEX_NAME(BufferMemory);

QUEX_INLINE size_t  QUEX_NAME(BufferMemory_size)(QUEX_NAME(BufferMemory)*);
QUEX_INLINE void    QUEX_NAME(BufferMemory_construct)(QUEX_NAME(BufferMemory)*  me, 
                                                      QUEX_TYPE_CHARACTER*      Memory, 
                                                      const size_t              Size,
                                                      E_Ownership               Ownership);
QUEX_INLINE void    QUEX_NAME(BufferMemory_destruct)(QUEX_NAME(BufferMemory)* me);

typedef struct QUEX_SETTING_USER_CLASS_DECLARATION_EPILOG QUEX_NAME(Buffer_tag) { 
/* Buffer of characters on which the analyzer runs. 
 *
 * Character Stream:
 * (by BufferFiller)     
 *     
 *    character_index_end_of_stream ----------------------.
 *    character_index_begin ---------------.              |
 *                                         |              |
 *    character index:   0  1  2  3  4  6  6  7  8  9  10 11 12 13 14 ...
 *  
 *    stream:           [aa.bb.cc.dd.ee.ff:gg.hh.ii.jj.kk.ll:mm.nn.oo.pp.qq ...
 *                              .---------'                 |
 * Buffer:                      |                 .---------' 
 *                           [00|gg.hh.ii.jj.kk.ll|00.??.??.??.??|00]
 *                            |                    |              |
 *           _front ----------'                    |              |
 *           input.end_p --------------------------'              |
 *           _back -----------------------------------------------'
 * 
 * 'character_index_end_of_stream == -1' => end of stream has not yet been
 * detected.                                                                 */
                                                                             
    QUEX_NAME(BufferMemory)  _memory;                                        
                                                                             
    /* (*) Iterator positions for lexical analysis                           */
    QUEX_TYPE_CHARACTER*     _read_p;                                        
    QUEX_TYPE_CHARACTER*     _lexeme_start_p;                                
                                                                             
    struct {                                                                 
        QUEX_TYPE_CHARACTER*      end_p;                                     
        QUEX_TYPE_STREAM_POSITION character_index_begin;                     
        /* Character index + 1 of the last character in the stream.          */
        QUEX_TYPE_STREAM_POSITION character_index_end_of_stream; 
    } input;

    /* (*) Information about previous content:
     *
     * _character_at_lexeme_start: character that has been covered by a 
     *                             terminating zero. Reset upon restart of 
     *                             analysis.
     * _character_at_lexeme_start: Used to check whether the lexeme's 
     *                             preceeding character was newline. 
     *                             (i.e. for begin-of-line pre-context).     */
    QUEX_TYPE_CHARACTER      _character_at_lexeme_start;      
#   ifdef __QUEX_OPTION_SUPPORT_BEGIN_OF_LINE_PRE_CONDITION
    QUEX_TYPE_CHARACTER      _character_before_lexeme_start;  
#   endif

    struct    QUEX_NAME(BufferFiller_tag)*  filler;

    void*     (*fill)(struct QUEX_NAME(Buffer_tag)*  me, 
                      const void*                    ContentBegin,
                      const void*                    ContentEnd);
    void      (*fill_prepare)(struct QUEX_NAME(Buffer_tag)*  me, 
                              void**                         begin_p, 
                              const void**                   end_p);
    void      (*fill_finish)(struct QUEX_NAME(Buffer_tag)* me,
                             const void*                   FilledEndP);

    /* Event handlers:                                          
     * on_content_change: If the user maintained pointers into the buffer, 
     *                    this callback indicates that everything from 'BeginP'
     *                    to 'EndP' needs to be copied somewhere else.
     * on_overflow: Distance between current '_read_p' and the lexeme start
     *              plus the fallback region are too big for the current 
     *              buffer's size.                                           */
    void      (*on_content_change)(const QUEX_TYPE_CHARACTER*  BeginP,
                                          const QUEX_TYPE_CHARACTER*  EndP);
    void      (*on_overflow)(struct QUEX_NAME(Buffer_tag)*, bool ForwardF);

} QUEX_NAME(Buffer);

QUEX_INLINE void    QUEX_NAME(Buffer_construct)(QUEX_NAME(Buffer)*                   me, 
                                                struct QUEX_NAME(BufferFiller_tag)*  filler,
                                                QUEX_TYPE_CHARACTER*                 memory,
                                                const size_t                         MemorySize,
                                                QUEX_TYPE_CHARACTER*                 EndOfFileP,
                                                E_Ownership                          Ownership);

/* Constructor, destructor, reset. */
QUEX_INLINE void  QUEX_NAME(Buffer_reset)(QUEX_NAME(Buffer)*                  me, 
                                          struct QUEX_NAME(BufferFiller_tag)* filler); 

QUEX_INLINE void  QUEX_NAME(Buffer_destruct)(QUEX_NAME(Buffer)* me);

/* Moving buffer content. */
QUEX_INLINE ptrdiff_t  QUEX_NAME(Buffer_move_away_passed_content)(QUEX_NAME(Buffer)*    me,
                                                                  QUEX_TYPE_CHARACTER** position_register,
                                                                  const size_t          PositionRegisterN);
QUEX_INLINE ptrdiff_t  QUEX_NAME(Buffer_move_away_upfront_content)(QUEX_NAME(Buffer)* me);
                      
/* Automatic loading of buffer content (during analysis). */
QUEX_INLINE bool       QUEX_NAME(Buffer_load_forward)(QUEX_NAME(Buffer)*    me,
                                                      QUEX_TYPE_CHARACTER** position_register,
                                                      const size_t          PositionRegisterN);
QUEX_INLINE bool       QUEX_NAME(Buffer_load_backward)(QUEX_NAME(Buffer)* me);
QUEX_INLINE bool       QUEX_NAME(Buffer_move_and_load_backward)(QUEX_NAME(Buffer)* me, 
                                                                QUEX_TYPE_STREAM_POSITION NewCharacterIndexBegin);
QUEX_INLINE bool       QUEX_NAME(Buffer_move_and_load_forward)(QUEX_NAME(Buffer)* me, 
                                                               QUEX_TYPE_STREAM_POSITION NewCharacterIndexBegin,
                                                               QUEX_TYPE_STREAM_POSITION MinCharacterIndexInBuffer);
/* User's manual buffer filling. */
QUEX_INLINE void*      QUEX_NAME(Buffer_fill)(QUEX_NAME(Buffer)* me, 
                                              const void*        ContentBegin, 
                                              const void*        ContentEnd);
QUEX_INLINE void       QUEX_NAME(Buffer_fill_prepare)(QUEX_NAME(Buffer)*  me, 
                                                      void**              begin_p, 
                                                      const void**        end_p);
QUEX_INLINE void       QUEX_NAME(Buffer_fill_finish)(QUEX_NAME(Buffer)* me,
                                                     const void*        FilledEndP);

                      
QUEX_INLINE void       QUEX_NAME(Buffer_print_this)(QUEX_NAME(Buffer)*);

/* Member attributes. */
QUEX_INLINE bool       QUEX_NAME(Buffer_is_empty)(QUEX_NAME(Buffer)* me);
QUEX_INLINE bool       QUEX_NAME(Buffer_is_end_of_file)(QUEX_NAME(Buffer)*);
QUEX_INLINE bool       QUEX_NAME(Buffer_is_begin_of_file)(QUEX_NAME(Buffer)*);

QUEX_INLINE void       QUEX_NAME(Buffer_register_content)(QUEX_NAME(Buffer)* me,
                                                          QUEX_TYPE_CHARACTER*      EndOfInputP,
                                                          QUEX_TYPE_STREAM_POSITION CharacterIndexBegin);
QUEX_INLINE void       QUEX_NAME(Buffer_register_eos)(QUEX_NAME(Buffer)* me,
                                                      QUEX_TYPE_STREAM_POSITION CharacterIndexEndOfStream);
QUEX_INLINE QUEX_TYPE_STREAM_POSITION  
                       QUEX_NAME(Buffer_input_character_index_end)(QUEX_NAME(Buffer)* me);
QUEX_INLINE QUEX_TYPE_STREAM_POSITION  
                       QUEX_NAME(Buffer_input_character_index_begin)(QUEX_NAME(Buffer)* me);
QUEX_INLINE size_t                QUEX_NAME(Buffer_content_size)(QUEX_NAME(Buffer)*);

/* Tell & seek '_read_p' to/from character index. */
QUEX_INLINE QUEX_TYPE_STREAM_POSITION  
                       QUEX_NAME(Buffer_tell)(QUEX_NAME(Buffer)*);
QUEX_INLINE void       QUEX_NAME(Buffer_seek)(QUEX_NAME(Buffer)*, 
                                              const QUEX_TYPE_STREAM_POSITION CharacterIndex);
QUEX_INLINE bool       QUEX_NAME(Buffer_seek_forward)(QUEX_NAME(Buffer)*, const ptrdiff_t CharacterN);
QUEX_INLINE bool       QUEX_NAME(Buffer_seek_backward)(QUEX_NAME(Buffer)*, const ptrdiff_t CharacterN);

QUEX_NAMESPACE_MAIN_CLOSE
#include <quex/code_base/buffer/filler/BufferFiller>

#endif /* __QUEX_INCLUDE_GUARD__BUFFER__BUFFER */
